mirror of
https://github.com/KoalaSat/nostros.git
synced 2024-09-29 06:30:47 +00:00
Better login process
This commit is contained in:
parent
7586c32306
commit
5738c2fbcb
@ -126,13 +126,13 @@ export const NoteCard: React.FC<NoteCardProps> = ({
|
||||
}, [database])
|
||||
|
||||
const publishReaction: (positive: boolean) => void = (positive) => {
|
||||
if (note && publicKey) {
|
||||
if (note?.id && publicKey) {
|
||||
const event: Event = {
|
||||
content: positive ? '+' : '-',
|
||||
created_at: getUnixTime(new Date()),
|
||||
kind: Kind.Reaction,
|
||||
pubkey: publicKey,
|
||||
tags: [...(note.tags ?? []), ['e', note.id], ['p', note.pubkey]],
|
||||
tags: [...note.tags, ['e', note.id], ['p', note.pubkey]],
|
||||
}
|
||||
relayPool?.sendEvent(event)
|
||||
}
|
||||
|
296
frontend/Components/ProfileActions/index.tsx
Normal file
296
frontend/Components/ProfileActions/index.tsx
Normal file
@ -0,0 +1,296 @@
|
||||
import { t } from 'i18next'
|
||||
import * as React from 'react'
|
||||
import { StyleSheet, View, ListRenderItem, Switch, FlatList } from 'react-native'
|
||||
import { IconButton, List, Snackbar, Text, useTheme } from 'react-native-paper'
|
||||
import { AppContext } from '../../Contexts/AppContext'
|
||||
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
||||
import { UserContext } from '../../Contexts/UserContext'
|
||||
import {
|
||||
getUser,
|
||||
updateUserBlock,
|
||||
updateUserContact,
|
||||
User,
|
||||
} from '../../Functions/DatabaseFunctions/Users'
|
||||
import { populatePets, username } from '../../Functions/RelayFunctions/Users'
|
||||
import LnPayment from '../LnPayment'
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
|
||||
import { navigate } from '../../lib/Navigation'
|
||||
import RBSheet from 'react-native-raw-bottom-sheet'
|
||||
import { getUserRelays, NoteRelay } from '../../Functions/DatabaseFunctions/NotesRelays'
|
||||
import { relayToColor } from '../../Functions/NativeFunctions'
|
||||
import { Relay } from '../../Functions/DatabaseFunctions/Relays'
|
||||
import ProfileShare from '../ProfileShare'
|
||||
|
||||
interface ProfileActionsProps {
|
||||
user: User
|
||||
setUser: (user: User) => void
|
||||
}
|
||||
|
||||
export const ProfileActions: React.FC<ProfileActionsProps> = ({ user, setUser }) => {
|
||||
const theme = useTheme()
|
||||
const { database } = React.useContext(AppContext)
|
||||
const { publicKey } = React.useContext(UserContext)
|
||||
const { relayPool, updateRelayItem } = React.useContext(RelayPoolContext)
|
||||
const [isContact, setIsContact] = React.useState<boolean>()
|
||||
const [showNotification, setShowNotification] = React.useState<undefined | string>()
|
||||
const [showNotificationRelay, setShowNotificationRelay] = React.useState<undefined | string>()
|
||||
const bottomSheetRelaysRef = React.useRef<RBSheet>(null)
|
||||
const bottomSheetShareRef = React.useRef<RBSheet>(null)
|
||||
const [userRelays, setUserRelays] = React.useState<NoteRelay[]>([])
|
||||
const [openLn, setOpenLn] = React.useState<boolean>(false)
|
||||
|
||||
React.useEffect(() => {
|
||||
loadUser()
|
||||
loadRelays()
|
||||
}, [])
|
||||
|
||||
const loadRelays: () => void = () => {
|
||||
if (database) {
|
||||
getUserRelays(database, user.id).then((results) => {
|
||||
if (results) {
|
||||
setUserRelays(results)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const loadUser: () => void = () => {
|
||||
if (database) {
|
||||
getUser(user.id, database).then((result) => {
|
||||
if (result) {
|
||||
setUser(result)
|
||||
} else if (user.id === publicKey) {
|
||||
setUser({
|
||||
id: publicKey,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const onChangeBlockUser: () => void = () => {
|
||||
if (database && user?.blocked !== undefined) {
|
||||
updateUserBlock(user.id, database, !user?.blocked).then(() => {
|
||||
loadUser()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const removeContact: () => void = () => {
|
||||
if (relayPool && database && publicKey) {
|
||||
updateUserContact(user.id, database, false).then(() => {
|
||||
populatePets(relayPool, database, publicKey)
|
||||
setIsContact(false)
|
||||
setShowNotification('contactRemoved')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const addContact: () => void = () => {
|
||||
if (relayPool && database && publicKey) {
|
||||
updateUserContact(user.id, database, true).then(() => {
|
||||
populatePets(relayPool, database, publicKey)
|
||||
setIsContact(true)
|
||||
setShowNotification('contactAdded')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const activeRelay: (relay: Relay) => void = (relay) => {
|
||||
relay.active = 1
|
||||
updateRelayItem(relay).then(() => {
|
||||
setShowNotificationRelay('active')
|
||||
})
|
||||
}
|
||||
|
||||
const desactiveRelay: (relay: Relay) => void = (relay) => {
|
||||
relay.active = 0
|
||||
relay.global_feed = 0
|
||||
updateRelayItem(relay).then(() => {
|
||||
setShowNotificationRelay('desactive')
|
||||
})
|
||||
}
|
||||
|
||||
const bottomSheetStyles = React.useMemo(() => {
|
||||
return {
|
||||
container: {
|
||||
backgroundColor: theme.colors.background,
|
||||
paddingTop: 16,
|
||||
paddingBottom: 32,
|
||||
paddingLeft: 16,
|
||||
borderTopRightRadius: 28,
|
||||
borderTopLeftRadius: 28,
|
||||
height: 'auto',
|
||||
},
|
||||
}
|
||||
}, [])
|
||||
|
||||
const renderRelayItem: ListRenderItem<NoteRelay> = ({ index, item }) => {
|
||||
return (
|
||||
<List.Item
|
||||
key={index}
|
||||
title={item.url}
|
||||
left={() => (
|
||||
<MaterialCommunityIcons
|
||||
style={styles.relayColor}
|
||||
name='circle'
|
||||
color={relayToColor(item.url)}
|
||||
/>
|
||||
)}
|
||||
right={() => (
|
||||
<Switch
|
||||
style={styles.switch}
|
||||
value={item.active !== undefined && item.active > 0}
|
||||
onValueChange={() => (item.active ? desactiveRelay(item) : activeRelay(item))}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.mainLayout}>
|
||||
<View style={styles.actionButton}>
|
||||
<IconButton
|
||||
icon={isContact ? 'account-multiple-remove-outline' : 'account-multiple-plus-outline'}
|
||||
size={28}
|
||||
onPress={() => {
|
||||
isContact ? removeContact() : addContact()
|
||||
}}
|
||||
disabled={user.id === publicKey}
|
||||
/>
|
||||
<Text>{isContact ? t('profilePage.unfollow') : t('profilePage.follow')}</Text>
|
||||
</View>
|
||||
<View style={styles.actionButton}>
|
||||
<IconButton
|
||||
icon='message-plus-outline'
|
||||
size={28}
|
||||
onPress={() => {
|
||||
navigate('Conversation', {
|
||||
pubKey: user.id,
|
||||
title: username(user),
|
||||
})
|
||||
}}
|
||||
/>
|
||||
<Text>{t('profilePage.message')}</Text>
|
||||
</View>
|
||||
<View style={styles.actionButton}>
|
||||
<IconButton
|
||||
icon='lightning-bolt'
|
||||
size={28}
|
||||
onPress={() => setOpenLn(true)}
|
||||
disabled={!user?.lnurl}
|
||||
iconColor='#F5D112'
|
||||
/>
|
||||
<Text>{t('profilePage.invoice')}</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.mainLayout}>
|
||||
<View style={styles.actionButton}>
|
||||
<IconButton
|
||||
icon={user?.blocked && user?.blocked > 0 ? 'account-cancel' : 'account-cancel-outline'}
|
||||
size={28}
|
||||
onPress={onChangeBlockUser}
|
||||
/>
|
||||
<Text>
|
||||
{t(user?.blocked && user?.blocked > 0 ? 'profileCard.unblock' : 'profileCard.block')}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.actionButton}>
|
||||
<IconButton
|
||||
icon='share-variant-outline'
|
||||
size={28}
|
||||
onPress={() => bottomSheetShareRef.current?.open()}
|
||||
/>
|
||||
<Text>{t('profileCard.share')}</Text>
|
||||
</View>
|
||||
<View style={styles.actionButton}>
|
||||
<IconButton
|
||||
icon='chart-timeline-variant'
|
||||
size={28}
|
||||
onPress={() => bottomSheetRelaysRef.current?.open()}
|
||||
/>
|
||||
<Text>{t('profilePage.relaysTitle')}</Text>
|
||||
</View>
|
||||
</View>
|
||||
<RBSheet ref={bottomSheetRelaysRef} closeOnDragDown={true} customStyles={bottomSheetStyles}>
|
||||
<View>
|
||||
<Text variant='titleLarge'>{t('profilePage.relaysTitle')}</Text>
|
||||
<Text variant='bodyMedium'>
|
||||
{t('profilePage.relaysDescription', { username: username(user) })}
|
||||
</Text>
|
||||
<List.Item
|
||||
title={t('relaysPage.relayName')}
|
||||
right={() => (
|
||||
<>
|
||||
<Text style={styles.listHeader}>{t('relaysPage.active')}</Text>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
<FlatList
|
||||
showsVerticalScrollIndicator={false}
|
||||
data={userRelays}
|
||||
renderItem={renderRelayItem}
|
||||
/>
|
||||
</View>
|
||||
{showNotificationRelay && (
|
||||
<Snackbar
|
||||
style={styles.snackbar}
|
||||
visible={showNotificationRelay !== undefined}
|
||||
duration={Snackbar.DURATION_SHORT}
|
||||
onIconPress={() => setShowNotificationRelay(undefined)}
|
||||
onDismiss={() => setShowNotificationRelay(undefined)}
|
||||
>
|
||||
{t(`profilePage.${showNotificationRelay}`)}
|
||||
</Snackbar>
|
||||
)}
|
||||
</RBSheet>
|
||||
<RBSheet ref={bottomSheetShareRef} closeOnDragDown={true} customStyles={bottomSheetStyles}>
|
||||
<ProfileShare user={user} />
|
||||
</RBSheet>
|
||||
<LnPayment setOpen={setOpenLn} open={openLn} user={user} />
|
||||
{showNotification && (
|
||||
<Snackbar
|
||||
style={styles.snackbar}
|
||||
visible={showNotification !== undefined}
|
||||
duration={Snackbar.DURATION_SHORT}
|
||||
onIconPress={() => setShowNotification(undefined)}
|
||||
onDismiss={() => setShowNotification(undefined)}
|
||||
>
|
||||
{t(`profilePage.${showNotification}`)}
|
||||
</Snackbar>
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
width: '100%',
|
||||
},
|
||||
relayColor: {
|
||||
paddingTop: 9,
|
||||
},
|
||||
mainLayout: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
actionButton: {
|
||||
alignItems: 'center',
|
||||
},
|
||||
snackbar: {
|
||||
marginLeft: 16,
|
||||
bottom: 16,
|
||||
},
|
||||
switch: {
|
||||
marginLeft: 32,
|
||||
},
|
||||
listHeader: {
|
||||
paddingRight: 5,
|
||||
paddingLeft: 16,
|
||||
textAlign: 'center',
|
||||
},
|
||||
})
|
||||
|
||||
export default ProfileActions
|
@ -1,23 +1,17 @@
|
||||
import { t } from 'i18next'
|
||||
import * as React from 'react'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
import { Card, IconButton, Snackbar, Text, useTheme } from 'react-native-paper'
|
||||
import { Divider, Snackbar, TouchableRipple, useTheme } from 'react-native-paper'
|
||||
import { AppContext } from '../../Contexts/AppContext'
|
||||
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
||||
import { UserContext } from '../../Contexts/UserContext'
|
||||
import {
|
||||
getUser,
|
||||
updateUserBlock,
|
||||
updateUserContact,
|
||||
User,
|
||||
} from '../../Functions/DatabaseFunctions/Users'
|
||||
import { populatePets, usernamePubKey } from '../../Functions/RelayFunctions/Users'
|
||||
import { getUser, User } from '../../Functions/DatabaseFunctions/Users'
|
||||
import { usernamePubKey } from '../../Functions/RelayFunctions/Users'
|
||||
import LnPayment from '../LnPayment'
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
|
||||
import { navigate, push } from '../../lib/Navigation'
|
||||
import { push } from '../../lib/Navigation'
|
||||
import RBSheet from 'react-native-raw-bottom-sheet'
|
||||
import { getNpub } from '../../lib/nostr/Nip19'
|
||||
import ProfileData from '../ProfileData'
|
||||
import ProfileActions from '../ProfileActions'
|
||||
|
||||
interface ProfileCardProps {
|
||||
bottomSheetRef: React.RefObject<RBSheet>
|
||||
@ -27,13 +21,9 @@ interface ProfileCardProps {
|
||||
export const ProfileCard: React.FC<ProfileCardProps> = ({ bottomSheetRef, showImages = true }) => {
|
||||
const theme = useTheme()
|
||||
const { displayUserDrawer } = React.useContext(AppContext)
|
||||
const { database, setDisplayUserShareDrawer } = React.useContext(AppContext)
|
||||
const { publicKey } = React.useContext(UserContext)
|
||||
const { relayPool } = React.useContext(RelayPoolContext)
|
||||
const { database } = React.useContext(AppContext)
|
||||
const [user, setUser] = React.useState<User>()
|
||||
const [blocked, setBlocked] = React.useState<number>()
|
||||
const [openLn, setOpenLn] = React.useState<boolean>(false)
|
||||
const [isContact, setIsContact] = React.useState<boolean>()
|
||||
const [showNotification, setShowNotification] = React.useState<undefined | string>()
|
||||
const nPub = React.useMemo(() => getNpub(displayUserDrawer), [displayUserDrawer])
|
||||
const username = React.useMemo(() => usernamePubKey(user?.name ?? '', nPub), [nPub, user])
|
||||
@ -42,45 +32,13 @@ export const ProfileCard: React.FC<ProfileCardProps> = ({ bottomSheetRef, showIm
|
||||
loadUser()
|
||||
}, [])
|
||||
|
||||
const onChangeBlockUser: () => void = () => {
|
||||
if (database && blocked !== undefined && displayUserDrawer) {
|
||||
updateUserBlock(displayUserDrawer, database, !blocked).then(() => {
|
||||
setBlocked(blocked === 0 ? 1 : 0)
|
||||
loadUser()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const removeContact: () => void = () => {
|
||||
if (relayPool && database && publicKey && displayUserDrawer) {
|
||||
updateUserContact(displayUserDrawer, database, false).then(() => {
|
||||
populatePets(relayPool, database, publicKey)
|
||||
setIsContact(false)
|
||||
setShowNotification('contactRemoved')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const addContact: () => void = () => {
|
||||
if (relayPool && database && publicKey && displayUserDrawer) {
|
||||
updateUserContact(displayUserDrawer, database, true).then(() => {
|
||||
populatePets(relayPool, database, publicKey)
|
||||
setIsContact(true)
|
||||
setShowNotification('contactAdded')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const loadUser: () => void = () => {
|
||||
if (database && displayUserDrawer) {
|
||||
getUser(displayUserDrawer, database).then((result) => {
|
||||
if (result) {
|
||||
setUser(result)
|
||||
setBlocked(result.blocked)
|
||||
setIsContact(result?.contact)
|
||||
} else {
|
||||
setUser({ id: displayUserDrawer })
|
||||
setBlocked(0)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -93,9 +51,10 @@ export const ProfileCard: React.FC<ProfileCardProps> = ({ bottomSheetRef, showIm
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Card onPress={goToProfile}>
|
||||
<Card.Content style={styles.card}>
|
||||
<View style={styles.cardUser}>
|
||||
<Divider />
|
||||
<TouchableRipple onPress={goToProfile}>
|
||||
<View style={styles.cardUser}>
|
||||
<View>
|
||||
<View style={styles.cardUserMain}>
|
||||
<ProfileData
|
||||
username={user?.name}
|
||||
@ -107,81 +66,18 @@ export const ProfileCard: React.FC<ProfileCardProps> = ({ bottomSheetRef, showIm
|
||||
avatarSize={54}
|
||||
/>
|
||||
</View>
|
||||
{user?.about && (
|
||||
<View style={styles.about}>
|
||||
<Text>
|
||||
{`${user?.about ? user?.about?.slice(0, 75) : ''}${
|
||||
user?.about && user?.about?.length > 75 ? ' ...' : ''
|
||||
}`}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
<View>
|
||||
<View style={styles.arrow}>
|
||||
<MaterialCommunityIcons
|
||||
name='menu-right'
|
||||
size={25}
|
||||
color={theme.colors.onPrimaryContainer}
|
||||
/>
|
||||
</View>
|
||||
</Card.Content>
|
||||
</Card>
|
||||
<View style={styles.mainLayout}>
|
||||
{displayUserDrawer !== publicKey && (
|
||||
<View style={styles.actionButton}>
|
||||
<IconButton
|
||||
icon={isContact ? 'account-multiple-remove-outline' : 'account-multiple-plus-outline'}
|
||||
size={28}
|
||||
onPress={() => {
|
||||
isContact ? removeContact() : addContact()
|
||||
}}
|
||||
/>
|
||||
<Text>{isContact ? t('profileCard.unfollow') : t('profileCard.follow')}</Text>
|
||||
</View>
|
||||
)}
|
||||
<View style={styles.actionButton}>
|
||||
<IconButton
|
||||
icon='message-plus-outline'
|
||||
size={28}
|
||||
onPress={() => {
|
||||
navigate('Conversation', { pubKey: displayUserDrawer, title: username })
|
||||
bottomSheetRef.current?.close()
|
||||
}}
|
||||
/>
|
||||
<Text>{t('profileCard.message')}</Text>
|
||||
</View>
|
||||
<View style={styles.actionButton}>
|
||||
<IconButton
|
||||
icon='share-variant-outline'
|
||||
size={28}
|
||||
onPress={() => {
|
||||
setDisplayUserShareDrawer(user?.id)
|
||||
}}
|
||||
/>
|
||||
<Text>{t('profileCard.share')}</Text>
|
||||
</View>
|
||||
{user?.lnurl && (
|
||||
<View style={styles.actionButton}>
|
||||
<>
|
||||
<IconButton
|
||||
icon='lightning-bolt'
|
||||
size={28}
|
||||
onPress={() => setOpenLn(true)}
|
||||
iconColor='#F5D112'
|
||||
/>
|
||||
<Text>{t('profileCard.invoice')}</Text>
|
||||
</>
|
||||
</View>
|
||||
)}
|
||||
<View style={styles.actionButton}>
|
||||
<IconButton
|
||||
icon={blocked && blocked > 0 ? 'account-cancel' : 'account-cancel-outline'}
|
||||
size={28}
|
||||
onPress={onChangeBlockUser}
|
||||
/>
|
||||
<Text>{t(blocked && blocked > 0 ? 'profileCard.unblock' : 'profileCard.block')}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableRipple>
|
||||
<Divider />
|
||||
{user && <ProfileActions user={user} setUser={setUser} />}
|
||||
{showNotification && (
|
||||
<Snackbar
|
||||
style={styles.snackbar}
|
||||
@ -229,6 +125,11 @@ const styles = StyleSheet.create({
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
cardUser: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
paddingTop: 16,
|
||||
},
|
||||
card: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
@ -258,13 +159,18 @@ const styles = StyleSheet.create({
|
||||
list: {
|
||||
padding: 16,
|
||||
},
|
||||
cardUser: {
|
||||
flex: 1,
|
||||
},
|
||||
verifyIcon: {
|
||||
paddingTop: 6,
|
||||
paddingLeft: 5,
|
||||
},
|
||||
dividerTop: {
|
||||
marginBottom: 16,
|
||||
},
|
||||
arrow: {
|
||||
alignContent: 'center',
|
||||
justifyContent: 'center',
|
||||
marginTop: -16,
|
||||
},
|
||||
})
|
||||
|
||||
export default ProfileCard
|
||||
|
@ -3,37 +3,21 @@ import * as React from 'react'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
import Clipboard from '@react-native-clipboard/clipboard'
|
||||
import { IconButton, Snackbar, Text, TouchableRipple } from 'react-native-paper'
|
||||
import { AppContext } from '../../Contexts/AppContext'
|
||||
import { getUser, User } from '../../Functions/DatabaseFunctions/Users'
|
||||
import { User } from '../../Functions/DatabaseFunctions/Users'
|
||||
import Share from 'react-native-share'
|
||||
import RBSheet from 'react-native-raw-bottom-sheet'
|
||||
import { getNpub } from '../../lib/nostr/Nip19'
|
||||
import QRCode from 'react-native-qrcode-svg'
|
||||
|
||||
export const ProfileShare: React.FC = () => {
|
||||
const { displayUserShareDrawer } = React.useContext(AppContext)
|
||||
interface ProfileShareProps {
|
||||
user: User
|
||||
}
|
||||
|
||||
export const ProfileShare: React.FC<ProfileShareProps> = ({ user }) => {
|
||||
const bottomSheetShareRef = React.useRef<RBSheet>(null)
|
||||
const { database } = React.useContext(AppContext)
|
||||
const [user, setUser] = React.useState<User>()
|
||||
const [qrCode, setQrCode] = React.useState<any>()
|
||||
const [showNotification, setShowNotification] = React.useState<undefined | string>()
|
||||
const nPub = React.useMemo(() => getNpub(displayUserShareDrawer), [displayUserShareDrawer])
|
||||
|
||||
React.useEffect(() => {
|
||||
loadUser()
|
||||
}, [])
|
||||
|
||||
const loadUser: () => void = () => {
|
||||
if (database && displayUserShareDrawer) {
|
||||
getUser(displayUserShareDrawer, database).then((result) => {
|
||||
if (result) {
|
||||
setUser(result)
|
||||
} else {
|
||||
setUser({ id: displayUserShareDrawer })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
const nPub = React.useMemo(() => getNpub(user.id), [user])
|
||||
|
||||
return (
|
||||
<View style={styles.mainLayout}>
|
||||
@ -73,20 +57,19 @@ export const ProfileShare: React.FC = () => {
|
||||
/>
|
||||
<Text>{t('profileShare.copyNPub')}</Text>
|
||||
</View>
|
||||
{user?.nip05 && (
|
||||
<View style={styles.shareActionButton}>
|
||||
<IconButton
|
||||
icon='check-decagram-outline'
|
||||
size={28}
|
||||
onPress={() => {
|
||||
setShowNotification('copyNip05')
|
||||
Clipboard.setString(user?.nip05 ?? '')
|
||||
bottomSheetShareRef.current?.close()
|
||||
}}
|
||||
/>
|
||||
<Text>{t('profileShare.copyNip05')}</Text>
|
||||
</View>
|
||||
)}
|
||||
<View style={styles.shareActionButton}>
|
||||
<IconButton
|
||||
icon='check-decagram-outline'
|
||||
size={28}
|
||||
onPress={() => {
|
||||
setShowNotification('nip05Copied')
|
||||
Clipboard.setString(user?.nip05 ?? '')
|
||||
bottomSheetShareRef.current?.close()
|
||||
}}
|
||||
disabled={!user.nip05}
|
||||
/>
|
||||
<Text>{t('profileShare.copyNip05')}</Text>
|
||||
</View>
|
||||
{showNotification && (
|
||||
<Snackbar
|
||||
style={styles.snackbar}
|
||||
|
@ -35,8 +35,6 @@ export interface AppContextProps {
|
||||
checkClipboard: () => void
|
||||
displayUserDrawer?: string
|
||||
setDisplayUserDrawer: (displayUserDrawer: string | undefined) => void
|
||||
displayUserShareDrawer?: string
|
||||
setDisplayUserShareDrawer: (displayUserShareDrawer: string | undefined) => void
|
||||
refreshBottomBarAt?: number
|
||||
setRefreshBottomBarAt: (refreshBottomBarAt: number) => void
|
||||
pushedTab?: string
|
||||
@ -78,7 +76,6 @@ export const initialAppContext: AppContextProps = {
|
||||
getSatoshiSymbol: () => <></>,
|
||||
setClipboardNip21: () => {},
|
||||
setDisplayUserDrawer: () => {},
|
||||
setDisplayUserShareDrawer: () => {},
|
||||
}
|
||||
|
||||
export const AppContextProvider = ({ children }: AppContextProviderProps): JSX.Element => {
|
||||
@ -103,7 +100,6 @@ export const AppContextProvider = ({ children }: AppContextProviderProps): JSX.E
|
||||
const [clipboardLoads, setClipboardLoads] = React.useState<string[]>([])
|
||||
const [clipboardNip21, setClipboardNip21] = React.useState<string>()
|
||||
const [displayUserDrawer, setDisplayUserDrawer] = React.useState<string>()
|
||||
const [displayUserShareDrawer, setDisplayUserShareDrawer] = React.useState<string>()
|
||||
const [pushedTab, setPushedTab] = useState<string>()
|
||||
|
||||
useEffect(() => {
|
||||
@ -229,8 +225,6 @@ export const AppContextProvider = ({ children }: AppContextProviderProps): JSX.E
|
||||
satoshi,
|
||||
setSatoshi,
|
||||
getSatoshiSymbol,
|
||||
setDisplayUserShareDrawer,
|
||||
displayUserShareDrawer,
|
||||
refreshBottomBarAt,
|
||||
setRefreshBottomBarAt,
|
||||
pushedTab,
|
||||
|
@ -1,10 +1,11 @@
|
||||
import React, { useContext, useEffect, useMemo, useState } from 'react'
|
||||
import RelayPool from '../lib/nostr/RelayPool/intex'
|
||||
import RelayPool, { fallbackRelays } from '../lib/nostr/RelayPool/intex'
|
||||
import { AppContext } from './AppContext'
|
||||
import { DeviceEventEmitter } from 'react-native'
|
||||
import debounce from 'lodash.debounce'
|
||||
import { getRelays, Relay } from '../Functions/DatabaseFunctions/Relays'
|
||||
import { getActiveRelays, getRelays, Relay } from '../Functions/DatabaseFunctions/Relays'
|
||||
import { UserContext } from './UserContext'
|
||||
import { randomInt } from '../Functions/NativeFunctions'
|
||||
|
||||
export interface RelayPoolContextProps {
|
||||
relayPoolReady: boolean
|
||||
@ -69,15 +70,25 @@ export const RelayPoolContextProvider = ({
|
||||
[setLastConfirmationId],
|
||||
)
|
||||
|
||||
const createRandomRelays: () => Promise<void> = async () => {
|
||||
const randomrelays: string[] = []
|
||||
while (randomrelays.length < 5) {
|
||||
const index = randomInt(0, fallbackRelays.length - 1)
|
||||
const url = fallbackRelays[index]
|
||||
if (!randomrelays.includes(url)) {
|
||||
randomrelays.push(fallbackRelays[index])
|
||||
await addRelayItem({ url })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const loadRelayPool: () => void = async () => {
|
||||
if (database && publicKey) {
|
||||
DeviceEventEmitter.addListener('WebsocketEvent', debouncedEventIdHandler)
|
||||
DeviceEventEmitter.addListener('WebsocketConfirmation', debouncedConfirmationHandler)
|
||||
const initRelayPool = new RelayPool(privateKey)
|
||||
await initRelayPool.resilientMode(database, publicKey)
|
||||
initRelayPool.connect(publicKey, () => setRelayPoolReady(true))
|
||||
setRelayPool(initRelayPool)
|
||||
loadRelays()
|
||||
initRelayPool.connect(publicKey, () => {
|
||||
initRelayPool.resilientMode(database, publicKey)
|
||||
setRelayPool(initRelayPool)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,10 +148,23 @@ export const RelayPoolContextProvider = ({
|
||||
|
||||
useEffect(() => {
|
||||
if (publicKey && publicKey !== '') {
|
||||
DeviceEventEmitter.addListener('WebsocketEvent', debouncedEventIdHandler)
|
||||
DeviceEventEmitter.addListener('WebsocketConfirmation', debouncedConfirmationHandler)
|
||||
loadRelayPool()
|
||||
}
|
||||
}, [publicKey])
|
||||
|
||||
useEffect(() => {
|
||||
if (database && relayPool) {
|
||||
getActiveRelays(database).then((results) => {
|
||||
if (results.length < 1) {
|
||||
createRandomRelays()
|
||||
}
|
||||
loadRelays().then(() => setRelayPoolReady(true))
|
||||
})
|
||||
}
|
||||
}, [relayPool])
|
||||
|
||||
return (
|
||||
<RelayPoolContext.Provider
|
||||
value={{
|
||||
|
@ -53,7 +53,7 @@ export const initialUserContext: UserContextProps = {
|
||||
|
||||
export const UserContextProvider = ({ children }: UserContextProviderProps): JSX.Element => {
|
||||
const { database, loadingDb, init } = useContext(AppContext)
|
||||
const { relayPool } = useContext(RelayPoolContext)
|
||||
const { relayPool, relayPoolReady } = useContext(RelayPoolContext)
|
||||
const [userState, setUserState] = useState<'loading' | 'access' | 'ready'>('loading')
|
||||
const [publicKey, setPublicKey] = useState<string>()
|
||||
const [nPub, setNpub] = useState<string>()
|
||||
@ -123,10 +123,10 @@ export const UserContextProvider = ({ children }: UserContextProviderProps): JSX
|
||||
}, [publicKey])
|
||||
|
||||
useEffect(() => {
|
||||
if (userState === 'ready' && publicKey) {
|
||||
if (userState === 'ready' && publicKey && relayPoolReady) {
|
||||
navigate('Feed')
|
||||
}
|
||||
}, [userState, publicKey])
|
||||
}, [userState, publicKey, relayPoolReady])
|
||||
|
||||
useEffect(() => {
|
||||
if (!loadingDb) {
|
||||
|
@ -1,10 +1,34 @@
|
||||
import { QuickSQLiteConnection } from 'react-native-quick-sqlite'
|
||||
import { getItems } from '..'
|
||||
import { Relay } from '../Relays'
|
||||
|
||||
export interface NoteRelay {
|
||||
export interface NoteRelay extends Relay {
|
||||
relay_url: string
|
||||
pubkey: string
|
||||
note_id: number
|
||||
}
|
||||
const databaseToEntity: (object: object) => NoteRelay = (object) => {
|
||||
return object as NoteRelay
|
||||
}
|
||||
|
||||
export const getUserRelays: (
|
||||
db: QuickSQLiteConnection,
|
||||
pubKey: string,
|
||||
) => Promise<NoteRelay[]> = async (db, pubKey) => {
|
||||
const query = `
|
||||
SELECT * FROM nostros_notes_relays LEFT JOIN
|
||||
nostros_relays ON nostros_relays.url = nostros_notes_relays.relay_url
|
||||
WHERE pubkey = ? GROUP BY relay_url
|
||||
`
|
||||
const resultSet = db.execute(query, [pubKey])
|
||||
if (resultSet.rows && resultSet.rows.length > 0) {
|
||||
const items: object[] = getItems(resultSet)
|
||||
const users: NoteRelay[] = items.map((object) => databaseToEntity(object))
|
||||
return users
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
export const getNoteRelaysUsage: (
|
||||
db: QuickSQLiteConnection,
|
||||
|
@ -33,8 +33,8 @@ export const searchRelays: (
|
||||
const searchQuery = `SELECT * FROM nostros_relays WHERE url = '${relayUrl}';`
|
||||
const results = await db.execute(searchQuery)
|
||||
const items: object[] = getItems(results)
|
||||
const notes: Relay[] = items.map((object) => databaseToEntity(object))
|
||||
return notes
|
||||
const relays: Relay[] = items.map((object) => databaseToEntity(object))
|
||||
return relays
|
||||
}
|
||||
|
||||
export const getRelays: (db: QuickSQLiteConnection) => Promise<Relay[]> = async (db) => {
|
||||
@ -45,6 +45,14 @@ export const getRelays: (db: QuickSQLiteConnection) => Promise<Relay[]> = async
|
||||
return relays
|
||||
}
|
||||
|
||||
export const getActiveRelays: (db: QuickSQLiteConnection) => Promise<Relay[]> = async (db) => {
|
||||
const notesQuery = 'SELECT * FROM nostros_relays WHERE active = 1;'
|
||||
const resultSet = await db.execute(notesQuery)
|
||||
const items: object[] = getItems(resultSet)
|
||||
const relays: Relay[] = items.map((object) => databaseToEntity(object))
|
||||
return relays
|
||||
}
|
||||
|
||||
export const getRelay: (db: QuickSQLiteConnection, url: string) => Promise<Relay> = async (
|
||||
db,
|
||||
url,
|
||||
|
@ -8,7 +8,7 @@ export interface User {
|
||||
picture?: string
|
||||
about?: string
|
||||
contact?: boolean
|
||||
follower?: boolean
|
||||
follower?: number
|
||||
lnurl?: string
|
||||
nip05?: string
|
||||
created_at?: number
|
||||
|
@ -51,7 +51,7 @@ export const pickRandomItems = <T extends unknown>(arr: T[], n: number): T[] =>
|
||||
|
||||
export const validImageUrl: (url: string | undefined) => boolean = (url) => {
|
||||
if (url) {
|
||||
const regexp = /^(https?:\/\/.*\.(?:png|jpg|jpeg|gif|webp))$/
|
||||
const regexp = /^(https?:\/\/.*\.(?:png|jpg|jpeg|gif|webp)(\?.*)?)$/
|
||||
return regexp.test(url)
|
||||
} else {
|
||||
return false
|
||||
|
@ -38,7 +38,13 @@ export const formatPubKey: (pubKey: string | undefined) => string = (pubKey) =>
|
||||
|
||||
const uniqueCode = pubKey.replace('npub1', '')
|
||||
|
||||
return `${uniqueCode.slice(0, 8)}:${uniqueCode.slice(-8)}`
|
||||
return formatId(uniqueCode)
|
||||
}
|
||||
|
||||
export const formatId: (key: string | undefined) => string = (key) => {
|
||||
if (!key) return ''
|
||||
|
||||
return `${key.slice(0, 8)}:${key.slice(-8)}`
|
||||
}
|
||||
|
||||
export const getNip05Domain: (nip05: string | undefined) => string | null = (nip05) => {
|
||||
|
@ -41,7 +41,8 @@
|
||||
"home": "Start",
|
||||
"searchingProfile": "Durchsuche Profil",
|
||||
"foundProfile": "Profil gefunden",
|
||||
"foundContacts": "{{contactsCount}} Kontakte gefunden"
|
||||
"foundContacts": "{{contactsCount}} Kontakte gefunden",
|
||||
"storing": "Storing {{lastEventId}} on database."
|
||||
},
|
||||
"sendPage": {
|
||||
"isContact": "Folge ich",
|
||||
@ -257,13 +258,18 @@
|
||||
"notifications": {
|
||||
"contactAdded": "Kontakt hinzugefügt",
|
||||
"contactRemoved": "Entfernt ",
|
||||
"npubCopied": "Öffentlicher Schlüssel kopiert."
|
||||
"npubCopied": "Öffentlicher Schlüssel kopiert.",
|
||||
"active": "Relay aktiviert.",
|
||||
"desactive": "Relay deaktiviert."
|
||||
},
|
||||
"invoice": "Zap",
|
||||
"message": "Nachricht",
|
||||
"follow": "Folgen",
|
||||
"isFollower": "follows you",
|
||||
"unfollow": "Nicht mehr folgen",
|
||||
"copyNPub": "Schlüssel kopieren"
|
||||
"copyNPub": "Schlüssel kopieren",
|
||||
"relaysTitle": "Relays",
|
||||
"relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected."
|
||||
},
|
||||
"homePage": {
|
||||
"clipboardTitle": "Nostr Schlüssel entdeckt",
|
||||
|
@ -40,8 +40,9 @@
|
||||
"relays": "See relays",
|
||||
"home": "Go Home",
|
||||
"searchingProfile": "Searching for your profile",
|
||||
"foundProfile": "Found profile",
|
||||
"foundContacts": "{{contactsCount}} contacts found"
|
||||
"foundProfile": "Profile found",
|
||||
"foundContacts": "{{contactsCount}} contacts found",
|
||||
"storing": "Storing {{lastEventId}} on database."
|
||||
},
|
||||
"sendPage": {
|
||||
"isContact": "Following",
|
||||
@ -175,9 +176,9 @@
|
||||
},
|
||||
"relaysPage": {
|
||||
"resilienceTitle": "Resilience (experimental)",
|
||||
"resilienceDescription": "The nostr protocol provides a good amount of tools to build a desentralized network, but unlike other desentralized protocols such as Bitcoin, it's not inherent by defaul on his usage.\n\nTo ahcieve such goal, clients and relays should activally colaborate. Nostros resiliense mode tries to, first, expose these concerns to their users, and secondly, start experimening with new pattern and way to help on network' resilency.\n\nFunctional implementation will soon endup appearing on Nostros by default.",
|
||||
"resilienceDescription": "The Nostr protocol provides a good number of tools to build a decentralized network, but unlike other decentralized protocols such as Bitcoin, it is not inherently bound to its use. To achieve the goal of a decentralized network, clients (e.g., Nostros) and relays (content servers) should actively cooperate. The Nostros resilience mode seeks first to raise awareness of this among users, and second to test new patterns and methods to improve the resilience of the network.\nA working implementation for this will soon be applied in Nostros.",
|
||||
"resilienceCategories": "Resilience exposure",
|
||||
"resilienceCategoriesDescription": "A first approach Nostros is testing is randomly calculate (based on received contats' events) what are the most resilient relays. It tries to avoid both relays with too much events (centralization) and relays with almost no events (battery draining).\n\nThe goal is to generate a list of 5 relays and cover all contacts. But if this is not possible, it will search among other relays, warning to the user about it.\n\nKeep into consideration relays flaged as 'Centralized'/'Small' doesn't means they are to the network, but just to your data.",
|
||||
"resilienceCategoriesDescription": "An initial approach that Nostros is testing is to randomly calculate (based on received contact events) which relays are most balanced. This tries to avoid both relays with too many events (centralization) and relays with almost no events (battery discharge).\n\nThe goal is to create a list of 5 relays that cover all contacts. However, if this is not possible, Nostros will search among other relays and warn the user about it.",
|
||||
"centralized": "Centralized",
|
||||
"small": "Small",
|
||||
"contacts": "# Contacts",
|
||||
@ -269,13 +270,18 @@
|
||||
"notifications": {
|
||||
"contactAdded": "Profile followed",
|
||||
"contactRemoved": "Profile unfollowed",
|
||||
"npubCopied": "Public key copied."
|
||||
"npubCopied": "Public key copied.",
|
||||
"active": "Relay activated.",
|
||||
"desactive": "Relay desactivated."
|
||||
},
|
||||
"invoice": "Tip",
|
||||
"message": "Message",
|
||||
"follow": "Follow",
|
||||
"unfollow": "Following",
|
||||
"copyNPub": "Copy key"
|
||||
"copyNPub": "Copy key",
|
||||
"relaysTitle": "Relays",
|
||||
"isFollower": "follows you",
|
||||
"relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected."
|
||||
},
|
||||
"homePage": {
|
||||
"clipboardTitle": "Nostr key detected",
|
||||
|
@ -41,7 +41,8 @@
|
||||
"home": "Acceder",
|
||||
"searchingProfile": "Buscando tu perfil",
|
||||
"foundProfile": "Perfil encontrado",
|
||||
"foundContacts": "{{contactsCount}} contactos encontrados"
|
||||
"foundContacts": "{{contactsCount}} contactos encontrados",
|
||||
"storing": "Guardando {{lastEventId}} en base de datos."
|
||||
},
|
||||
"sendPage": {
|
||||
"isContact": "Siguiendo",
|
||||
@ -251,13 +252,18 @@
|
||||
"notifications": {
|
||||
"contactAdded": "Siguiendo",
|
||||
"contactRemoved": "Dejando de seguir ",
|
||||
"npubCopied": "Clave pública copiada."
|
||||
"npubCopied": "Clave pública copiada.",
|
||||
"active": "Relay activado.",
|
||||
"desactive": "Relay desactivado."
|
||||
},
|
||||
"invoice": "Propina",
|
||||
"message": "Mensaje",
|
||||
"isFollower": "te sigue",
|
||||
"follow": "Seguir",
|
||||
"unfollow": "Siguiendo",
|
||||
"copyNPub": "Copiar clave"
|
||||
"copyNPub": "Copiar clave",
|
||||
"relaysTitle": "Relays",
|
||||
"relaysDescription": "Estos son los relays de {{username}}, activa aquellos a los que quieras estar conectado."
|
||||
},
|
||||
"homePage": {
|
||||
"clipboardTitle": "Se ha detectado una clave Nostr",
|
||||
|
@ -41,7 +41,8 @@
|
||||
"home": "Accès",
|
||||
"searchingProfile": "A la recherche de votre profil",
|
||||
"foundProfile": "Profil trouvé",
|
||||
"foundContacts": "{{contactsCount}} contacts trouvés"
|
||||
"foundContacts": "{{contactsCount}} contacts trouvés",
|
||||
"storing": "Storing {{lastEventId}} on database."
|
||||
},
|
||||
"sendPage": {
|
||||
"isContact": "Abonné",
|
||||
@ -252,13 +253,18 @@
|
||||
"notifications": {
|
||||
"contactAdded": "Abonné",
|
||||
"contactRemoved": "Vous ne suivez plus ce profil",
|
||||
"npubCopied": "Clé publique copiée"
|
||||
"npubCopied": "Clé publique copiée",
|
||||
"active": "Actif",
|
||||
"share": "Partager"
|
||||
},
|
||||
"invoice": "Facture",
|
||||
"message": "Message",
|
||||
"follow": "Suivre",
|
||||
"isFollower": "follows you",
|
||||
"unfollow": "Abonné",
|
||||
"copyNPub": "Copier la clé"
|
||||
"copyNPub": "Copier la clé",
|
||||
"relaysTitle": "Relays",
|
||||
"relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected."
|
||||
},
|
||||
"profileShare": {
|
||||
"notifications": {
|
||||
|
@ -41,7 +41,8 @@
|
||||
"home": "На главную",
|
||||
"searchingProfile": "Ищем Ваш профиль.",
|
||||
"foundProfile": "Профиль найден.",
|
||||
"foundContacts": "{{contactsCount}} контакта(ов) найдено"
|
||||
"foundContacts": "{{contactsCount}} контакта(ов) найдено",
|
||||
"storing": "Storing {{lastEventId}} on database."
|
||||
},
|
||||
"sendPage": {
|
||||
"isContact": "Подписаны",
|
||||
@ -219,7 +220,9 @@
|
||||
"lud06Published": "LUD-06 published.\n\n{{lud06}}",
|
||||
"nip05Published": "NIP-05 published.\n\n{{nip05}}",
|
||||
"picturePublished": "Picture published.",
|
||||
"connectionError": "Ошибка с подключением"
|
||||
"connectionError": "Ошибка с подключением",
|
||||
"active": "Relay actived.",
|
||||
"desactive": "Relay desactivated."
|
||||
},
|
||||
"publishLud06": "Опубликовть",
|
||||
"lud06Label": "LNURL / Lightning Address",
|
||||
@ -257,7 +260,10 @@
|
||||
"message": "Сообщение",
|
||||
"follow": "Follow",
|
||||
"unfollow": "Following",
|
||||
"copyNPub": "Скопировать ключ"
|
||||
"isFollower": "follows you",
|
||||
"copyNPub": "Скопировать ключ",
|
||||
"relaysTitle": "Relays",
|
||||
"relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected."
|
||||
},
|
||||
"homePage": {
|
||||
"clipboardTitle": "Se ha detectado una clave Nostr",
|
||||
|
@ -40,7 +40,8 @@
|
||||
"home": "去首页",
|
||||
"searchingProfile": "搜索用户",
|
||||
"foundProfile": "已找到的用户",
|
||||
"foundContacts": "已找到 {{contactsCount}} 个联系人"
|
||||
"foundContacts": "已找到 {{contactsCount}} 个联系人",
|
||||
"storing": "Storing {{lastEventId}} on database."
|
||||
},
|
||||
"sendPage": {
|
||||
"isContact": "正在关注",
|
||||
@ -232,7 +233,9 @@
|
||||
"lud06Published": "LUD-06 已发布 \n\n{{lud06}}",
|
||||
"nip05Published": "NIP-05 已发布 \n\n{{nip05}}",
|
||||
"picturePublished": "头像已发布",
|
||||
"connectionError": "连接错误"
|
||||
"connectionError": "连接错误",
|
||||
"active": "中继已启用",
|
||||
"desactive": "中继已停用"
|
||||
},
|
||||
"publishLud06": "发布",
|
||||
"lud06Label": "LNURL / Lightning 地址",
|
||||
@ -269,8 +272,11 @@
|
||||
"invoice": "赞赏",
|
||||
"message": "私信",
|
||||
"follow": "关注",
|
||||
"isFollower": "follows you",
|
||||
"unfollow": "关注中",
|
||||
"copyNPub": "复制公钥"
|
||||
"copyNPub": "复制公钥",
|
||||
"relaysTitle": "Relays",
|
||||
"relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected."
|
||||
},
|
||||
"homePage": {
|
||||
"clipboardTitle": "检测到 Nostr 公钥",
|
||||
|
@ -18,7 +18,6 @@ import ConfigPage from '../ConfigPage'
|
||||
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
||||
import { AppContext } from '../../Contexts/AppContext'
|
||||
import RelayCard from '../../Components/RelayCard'
|
||||
import ProfileShare from '../../Components/ProfileShare'
|
||||
import { updateAllRead } from '../../Functions/DatabaseFunctions/DirectMessages'
|
||||
import { getUnixTime } from 'date-fns'
|
||||
|
||||
@ -26,18 +25,11 @@ export const HomeNavigator: React.FC = () => {
|
||||
const theme = useTheme()
|
||||
const { t } = useTranslation('common')
|
||||
const { displayRelayDrawer, setDisplayrelayDrawer } = React.useContext(RelayPoolContext)
|
||||
const {
|
||||
displayUserDrawer,
|
||||
setDisplayUserDrawer,
|
||||
displayUserShareDrawer,
|
||||
setDisplayUserShareDrawer,
|
||||
setRefreshBottomBarAt,
|
||||
database,
|
||||
} = React.useContext(AppContext)
|
||||
const { displayUserDrawer, setDisplayUserDrawer, setRefreshBottomBarAt, database } =
|
||||
React.useContext(AppContext)
|
||||
const bottomSheetRef = React.useRef<RBSheet>(null)
|
||||
const bottomSheetProfileRef = React.useRef<RBSheet>(null)
|
||||
const bottomSheetRelayRef = React.useRef<RBSheet>(null)
|
||||
const bottomSheetShareRef = React.useRef<RBSheet>(null)
|
||||
const Stack = React.useMemo(() => createStackNavigator(), [])
|
||||
const cardStyleInterpolator = React.useMemo(
|
||||
() =>
|
||||
@ -78,10 +70,6 @@ export const HomeNavigator: React.FC = () => {
|
||||
if (displayUserDrawer) bottomSheetProfileRef.current?.open()
|
||||
}, [displayUserDrawer])
|
||||
|
||||
React.useEffect(() => {
|
||||
if (displayUserShareDrawer) bottomSheetShareRef.current?.open()
|
||||
}, [displayUserShareDrawer])
|
||||
|
||||
return (
|
||||
<>
|
||||
<Stack.Navigator
|
||||
@ -174,14 +162,6 @@ export const HomeNavigator: React.FC = () => {
|
||||
<Text variant='bodyMedium'>{t('drawers.relaysDescription')}</Text>
|
||||
</View>
|
||||
</RBSheet>
|
||||
<RBSheet
|
||||
ref={bottomSheetShareRef}
|
||||
closeOnDragDown={true}
|
||||
customStyles={bottomSheetStyles}
|
||||
onClose={() => setDisplayUserShareDrawer(undefined)}
|
||||
>
|
||||
<ProfileShare />
|
||||
</RBSheet>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -60,7 +60,6 @@ export const ProfileCreatePage: React.FC<ProfileCreatePageProps> = ({ navigation
|
||||
|
||||
const onPress: () => void = () => {
|
||||
if (step > 1) {
|
||||
console.log(validConfirmation())
|
||||
if (validConfirmation()) {
|
||||
setPrivateKey(key)
|
||||
setUserState('ready')
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useContext, useEffect, useState } from 'react'
|
||||
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
||||
import { RelayPoolContext, WebsocketEvent } from '../../Contexts/RelayPoolContext'
|
||||
import { Kind } from 'nostr-tools'
|
||||
import { AppContext } from '../../Contexts/AppContext'
|
||||
import { UserContext } from '../../Contexts/UserContext'
|
||||
@ -7,28 +7,32 @@ import { getUsers, User } from '../../Functions/DatabaseFunctions/Users'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import getUnixTime from 'date-fns/getUnixTime'
|
||||
import debounce from 'lodash.debounce'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
import { DeviceEventEmitter, StyleSheet, View } from 'react-native'
|
||||
import Logo from '../../Components/Logo'
|
||||
import { Button, Text, useTheme } from 'react-native-paper'
|
||||
import { navigate } from '../../lib/Navigation'
|
||||
import { useFocusEffect } from '@react-navigation/native'
|
||||
import { formatId } from '../../Functions/RelayFunctions/Users'
|
||||
|
||||
export const ProfileLoadPage: React.FC = () => {
|
||||
const theme = useTheme()
|
||||
const { database } = useContext(AppContext)
|
||||
const { relayPool, lastEventId, relayPoolReady } = useContext(RelayPoolContext)
|
||||
const { relayPool, relayPoolReady } = useContext(RelayPoolContext)
|
||||
const { publicKey, reloadUser, setUserState, name } = useContext(UserContext)
|
||||
const { t } = useTranslation('common')
|
||||
const [profileFound, setProfileFound] = useState<boolean>(false)
|
||||
const [contactsCount, setContactsCount] = useState<number>(0)
|
||||
const [lastEventId, setLastEventId] = useState<string>('')
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
DeviceEventEmitter.addListener('WebsocketEvent', (event: WebsocketEvent) =>
|
||||
setLastEventId(event.eventId),
|
||||
)
|
||||
debounce(() => {
|
||||
loadMeta()
|
||||
loadPets()
|
||||
reloadUser()
|
||||
}, 1000)
|
||||
|
||||
return () =>
|
||||
relayPool?.unsubscribe([
|
||||
'profile-load-meta',
|
||||
@ -39,14 +43,16 @@ export const ProfileLoadPage: React.FC = () => {
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
loadMeta()
|
||||
loadPets()
|
||||
reloadUser()
|
||||
if (name) {
|
||||
setProfileFound(true)
|
||||
loadPets()
|
||||
}
|
||||
}, [lastEventId, name])
|
||||
if (!name) reloadUser()
|
||||
}, [lastEventId, publicKey, relayPoolReady])
|
||||
|
||||
useEffect(() => {
|
||||
if (name) setProfileFound(true)
|
||||
}, [name])
|
||||
|
||||
useEffect(() => {
|
||||
if (profileFound) loadPets()
|
||||
}, [profileFound, publicKey, relayPoolReady])
|
||||
|
||||
useEffect(() => {
|
||||
if (publicKey && relayPoolReady) loadMeta()
|
||||
@ -56,23 +62,17 @@ export const ProfileLoadPage: React.FC = () => {
|
||||
if (publicKey && relayPoolReady) {
|
||||
relayPool?.subscribe('profile-load-meta', [
|
||||
{
|
||||
kinds: [Kind.Text, Kind.Contacts, Kind.Metadata],
|
||||
kinds: [Kind.Contacts, Kind.Metadata],
|
||||
authors: [publicKey],
|
||||
},
|
||||
])
|
||||
relayPool?.subscribe('profile-load-meta-pets', [
|
||||
{
|
||||
kinds: [Kind.Contacts],
|
||||
'#p': [publicKey],
|
||||
},
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
const loadPets: () => void = () => {
|
||||
if (database && publicKey && relayPoolReady) {
|
||||
getUsers(database, {}).then((results) => {
|
||||
if (results && results.length > 0) {
|
||||
if (results.length > 0) {
|
||||
setContactsCount(results.filter((user) => user.contact).length)
|
||||
const authors = [...results.map((user: User) => user.id), publicKey]
|
||||
relayPool?.subscribe('profile-load-notes', [
|
||||
@ -103,6 +103,9 @@ export const ProfileLoadPage: React.FC = () => {
|
||||
<Text variant='titleMedium' style={styles.center}>
|
||||
{t('profileLoadPage.foundContacts', { contactsCount })}
|
||||
</Text>
|
||||
<Text variant='titleMedium' style={styles.center}>
|
||||
{t('profileLoadPage.storing', { lastEventId: formatId(lastEventId) })}
|
||||
</Text>
|
||||
<Button mode='contained' onPress={() => setUserState('ready')}>
|
||||
{t('profileLoadPage.home')}
|
||||
</Button>
|
||||
@ -114,6 +117,7 @@ export const ProfileLoadPage: React.FC = () => {
|
||||
style={styles.warningAction}
|
||||
mode='text'
|
||||
onPress={() => {
|
||||
reloadUser()
|
||||
navigate('Relays')
|
||||
}}
|
||||
>
|
||||
|
@ -7,30 +7,28 @@ import {
|
||||
StyleSheet,
|
||||
View,
|
||||
} from 'react-native'
|
||||
import { Surface, Text, IconButton, ActivityIndicator, Snackbar } from 'react-native-paper'
|
||||
import { Surface, Text, ActivityIndicator, Snackbar, Divider } from 'react-native-paper'
|
||||
import { FlashList, ListRenderItem } from '@shopify/flash-list'
|
||||
import { AppContext } from '../../Contexts/AppContext'
|
||||
import { UserContext } from '../../Contexts/UserContext'
|
||||
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
||||
import { getNotes, Note } from '../../Functions/DatabaseFunctions/Notes'
|
||||
import { getUser, updateUserContact, User } from '../../Functions/DatabaseFunctions/Users'
|
||||
import { getUser, User } from '../../Functions/DatabaseFunctions/Users'
|
||||
import { Kind } from 'nostr-tools'
|
||||
import { populatePets, username } from '../../Functions/RelayFunctions/Users'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RelayFilters } from '../../lib/nostr/RelayPool/intex'
|
||||
import NoteCard from '../../Components/NoteCard'
|
||||
import LnPayment from '../../Components/LnPayment'
|
||||
import { handleInfinityScroll } from '../../Functions/NativeFunctions'
|
||||
import { navigate } from '../../lib/Navigation'
|
||||
import { useFocusEffect } from '@react-navigation/native'
|
||||
import ProfileData from '../../Components/ProfileData'
|
||||
import ProfileActions from '../../Components/ProfileActions'
|
||||
|
||||
interface ProfilePageProps {
|
||||
route: { params: { pubKey: string } }
|
||||
}
|
||||
|
||||
export const ProfilePage: React.FC<ProfilePageProps> = ({ route }) => {
|
||||
const { database, setDisplayUserShareDrawer } = useContext(AppContext)
|
||||
const { database } = useContext(AppContext)
|
||||
const { publicKey } = useContext(UserContext)
|
||||
const { lastEventId, relayPool } = useContext(RelayPoolContext)
|
||||
const { t } = useTranslation('common')
|
||||
@ -38,9 +36,7 @@ export const ProfilePage: React.FC<ProfilePageProps> = ({ route }) => {
|
||||
const [showNotification, setShowNotification] = useState<undefined | string>()
|
||||
const [notes, setNotes] = useState<Note[]>()
|
||||
const [user, setUser] = useState<User>()
|
||||
const [openLn, setOpenLn] = React.useState<boolean>(false)
|
||||
const [pageSize, setPageSize] = useState<number>(initialPageSize)
|
||||
const [isContact, setIsContact] = useState<boolean>()
|
||||
const [refreshing, setRefreshing] = useState(false)
|
||||
const [firstLoad, setFirstLoad] = useState(true)
|
||||
|
||||
@ -84,7 +80,6 @@ export const ProfilePage: React.FC<ProfilePageProps> = ({ route }) => {
|
||||
getUser(route.params.pubKey, database).then((result) => {
|
||||
if (result) {
|
||||
setUser(result)
|
||||
setIsContact(result?.contact)
|
||||
} else if (route.params.pubKey === publicKey) {
|
||||
setUser({
|
||||
id: publicKey,
|
||||
@ -133,26 +128,6 @@ export const ProfilePage: React.FC<ProfilePageProps> = ({ route }) => {
|
||||
relayPool?.subscribe(`profile${route.params.pubKey}`, [message])
|
||||
}
|
||||
|
||||
const removeContact: () => void = () => {
|
||||
if (relayPool && database && publicKey) {
|
||||
updateUserContact(route.params.pubKey, database, false).then(() => {
|
||||
populatePets(relayPool, database, publicKey)
|
||||
setIsContact(false)
|
||||
setShowNotification('contactRemoved')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const addContact: () => void = () => {
|
||||
if (relayPool && database && publicKey) {
|
||||
updateUserContact(route.params.pubKey, database, true).then(() => {
|
||||
populatePets(relayPool, database, publicKey)
|
||||
setIsContact(true)
|
||||
setShowNotification('contactAdded')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const onScroll: (event: NativeSyntheticEvent<NativeScrollEvent>) => void = (event) => {
|
||||
if (handleInfinityScroll(event)) {
|
||||
setPageSize(pageSize + initialPageSize)
|
||||
@ -174,70 +149,24 @@ export const ProfilePage: React.FC<ProfilePageProps> = ({ route }) => {
|
||||
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />}
|
||||
>
|
||||
<Surface style={styles.container} elevation={1}>
|
||||
<ProfileData
|
||||
username={user?.name}
|
||||
publicKey={route.params.pubKey}
|
||||
validNip05={user?.valid_nip05}
|
||||
nip05={user?.nip05}
|
||||
lud06={user?.lnurl}
|
||||
picture={user?.picture}
|
||||
avatarSize={56}
|
||||
/>
|
||||
<View style={styles.profileData}>
|
||||
<ProfileData
|
||||
username={user?.name}
|
||||
publicKey={route.params.pubKey}
|
||||
validNip05={user?.valid_nip05}
|
||||
nip05={user?.nip05}
|
||||
lud06={user?.lnurl}
|
||||
picture={user?.picture}
|
||||
avatarSize={56}
|
||||
/>
|
||||
<Text>{user?.follower && user.follower > 0 ? t('profilePage.isFollower') : ''}</Text>
|
||||
</View>
|
||||
<View>
|
||||
<Text>{user?.about}</Text>
|
||||
</View>
|
||||
<View style={styles.mainLayout}>
|
||||
{route.params.pubKey !== publicKey && (
|
||||
<View style={styles.actionButton}>
|
||||
<IconButton
|
||||
icon={
|
||||
isContact ? 'account-multiple-remove-outline' : 'account-multiple-plus-outline'
|
||||
}
|
||||
size={28}
|
||||
onPress={() => {
|
||||
isContact ? removeContact() : addContact()
|
||||
}}
|
||||
disabled={route.params.pubKey === publicKey}
|
||||
/>
|
||||
<Text>{isContact ? t('profilePage.unfollow') : t('profilePage.follow')}</Text>
|
||||
</View>
|
||||
)}
|
||||
<View style={styles.actionButton}>
|
||||
<IconButton
|
||||
icon='message-plus-outline'
|
||||
size={28}
|
||||
onPress={() => {
|
||||
navigate('Conversation', {
|
||||
pubKey: route.params.pubKey,
|
||||
title: user ? username(user) : route.params.pubKey,
|
||||
})
|
||||
}}
|
||||
/>
|
||||
<Text>{t('profilePage.message')}</Text>
|
||||
</View>
|
||||
<View style={styles.actionButton}>
|
||||
<IconButton
|
||||
icon='share-variant-outline'
|
||||
size={28}
|
||||
onPress={() => {
|
||||
setDisplayUserShareDrawer(user?.id)
|
||||
}}
|
||||
/>
|
||||
<Text>{t('profileCard.share')}</Text>
|
||||
</View>
|
||||
<View style={styles.actionButton}>
|
||||
{user?.lnurl && (
|
||||
<>
|
||||
<IconButton
|
||||
icon='lightning-bolt'
|
||||
size={28}
|
||||
onPress={() => setOpenLn(true)}
|
||||
iconColor='#F5D112'
|
||||
/>
|
||||
<Text>{t('profilePage.invoice')}</Text>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
<Divider style={styles.divider} />
|
||||
<View style={styles.profileActions}>
|
||||
{user && <ProfileActions user={user} setUser={setUser} />}
|
||||
</View>
|
||||
</Surface>
|
||||
<View style={styles.list}>
|
||||
@ -265,7 +194,6 @@ export const ProfilePage: React.FC<ProfilePageProps> = ({ route }) => {
|
||||
{t(`profilePage.${showNotification}`)}
|
||||
</Snackbar>
|
||||
)}
|
||||
<LnPayment setOpen={setOpenLn} open={openLn} user={user} />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
@ -274,26 +202,6 @@ const styles = StyleSheet.create({
|
||||
container: {
|
||||
padding: 16,
|
||||
},
|
||||
contacts: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-around',
|
||||
},
|
||||
mainLayout: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
userData: {
|
||||
paddingLeft: 16,
|
||||
},
|
||||
userName: {
|
||||
flexDirection: 'row',
|
||||
},
|
||||
actionButton: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
width: 100,
|
||||
},
|
||||
snackbar: {
|
||||
margin: 16,
|
||||
bottom: 70,
|
||||
@ -301,12 +209,19 @@ const styles = StyleSheet.create({
|
||||
list: {
|
||||
padding: 16,
|
||||
},
|
||||
divider: {
|
||||
marginTop: 16,
|
||||
},
|
||||
profileActions: {
|
||||
marginRight: 16,
|
||||
marginLeft: 16,
|
||||
},
|
||||
noteCard: {
|
||||
marginBottom: 16,
|
||||
},
|
||||
verifyIcon: {
|
||||
paddingTop: 6,
|
||||
paddingLeft: 5,
|
||||
profileData: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -3,7 +3,7 @@ import { FlatList, ListRenderItem, ScrollView, StyleSheet, View } from 'react-na
|
||||
import Clipboard from '@react-native-clipboard/clipboard'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
||||
import { Relay } from '../../Functions/DatabaseFunctions/Relays'
|
||||
import { getRelays, Relay } from '../../Functions/DatabaseFunctions/Relays'
|
||||
import { REGEX_SOCKET_LINK } from '../../Constants/Relay'
|
||||
import {
|
||||
List,
|
||||
@ -21,6 +21,7 @@ import RBSheet from 'react-native-raw-bottom-sheet'
|
||||
import { relayToColor } from '../../Functions/NativeFunctions'
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
|
||||
import { useFocusEffect } from '@react-navigation/native'
|
||||
import { AppContext } from '../../Contexts/AppContext'
|
||||
|
||||
export const defaultRelays = [
|
||||
'wss://brb.io',
|
||||
@ -39,13 +40,14 @@ export const defaultRelays = [
|
||||
|
||||
export const RelaysPage: React.FC = () => {
|
||||
const defaultRelayInput = React.useMemo(() => 'wss://', [])
|
||||
const { updateRelayItem, addRelayItem, removeRelayItem, relays, relayPool } =
|
||||
useContext(RelayPoolContext)
|
||||
const { updateRelayItem, addRelayItem, removeRelayItem, relayPool } = useContext(RelayPoolContext)
|
||||
const { database } = useContext(AppContext)
|
||||
const { t } = useTranslation('common')
|
||||
const theme = useTheme()
|
||||
const bottomSheetAddRef = React.useRef<RBSheet>(null)
|
||||
const bottomSheetEditRef = React.useRef<RBSheet>(null)
|
||||
const bottomSheetResilenseRef = React.useRef<RBSheet>(null)
|
||||
const [relays, setRelays] = React.useState<Relay[]>([])
|
||||
const [selectedRelay, setSelectedRelay] = useState<Relay>()
|
||||
const [addRelayInput, setAddRelayInput] = useState<string>(defaultRelayInput)
|
||||
const [showNotification, setShowNotification] = useState<string>()
|
||||
@ -53,17 +55,23 @@ export const RelaysPage: React.FC = () => {
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
relayPool?.unsubscribeAll()
|
||||
updateRelays()
|
||||
|
||||
return () => {}
|
||||
}, []),
|
||||
)
|
||||
|
||||
const updateRelays: () => void = () => {
|
||||
if (database) getRelays(database).then(setRelays)
|
||||
}
|
||||
|
||||
const addRelay: (url: string) => void = (url) => {
|
||||
addRelayItem({
|
||||
url,
|
||||
active: 1,
|
||||
global_feed: 1,
|
||||
}).then(() => {
|
||||
updateRelays()
|
||||
setShowNotification('add')
|
||||
})
|
||||
}
|
||||
@ -72,6 +80,7 @@ export const RelaysPage: React.FC = () => {
|
||||
removeRelayItem({
|
||||
url,
|
||||
}).then(() => {
|
||||
updateRelays()
|
||||
setShowNotification('remove')
|
||||
})
|
||||
}
|
||||
@ -79,6 +88,7 @@ export const RelaysPage: React.FC = () => {
|
||||
const activeRelay: (relay: Relay) => void = (relay) => {
|
||||
relay.active = 1
|
||||
updateRelayItem(relay).then(() => {
|
||||
updateRelays()
|
||||
setShowNotification('active')
|
||||
})
|
||||
}
|
||||
@ -87,6 +97,7 @@ export const RelaysPage: React.FC = () => {
|
||||
relay.active = 0
|
||||
relay.global_feed = 0
|
||||
updateRelayItem(relay).then(() => {
|
||||
updateRelays()
|
||||
setShowNotification('desactive')
|
||||
})
|
||||
}
|
||||
@ -95,6 +106,7 @@ export const RelaysPage: React.FC = () => {
|
||||
relay.active = 1
|
||||
relay.global_feed = 1
|
||||
updateRelayItem(relay).then(() => {
|
||||
updateRelays()
|
||||
setShowNotification('globalFeedActive')
|
||||
})
|
||||
}
|
||||
@ -102,6 +114,7 @@ export const RelaysPage: React.FC = () => {
|
||||
const desactiveGlobalFeedRelay: (relay: Relay) => void = (relay) => {
|
||||
relay.global_feed = 0
|
||||
updateRelayItem(relay).then(() => {
|
||||
updateRelays()
|
||||
setShowNotification('globalFeedActiveUnactive')
|
||||
})
|
||||
}
|
||||
@ -229,7 +242,7 @@ export const RelaysPage: React.FC = () => {
|
||||
</Text>
|
||||
<IconButton
|
||||
style={styles.titleAction}
|
||||
icon='question'
|
||||
icon='help'
|
||||
size={20}
|
||||
onPress={() => bottomSheetResilenseRef.current?.open()}
|
||||
/>
|
||||
|
@ -126,15 +126,11 @@ export const SendPage: React.FC<SendPageProps> = ({ route }) => {
|
||||
let tags: string[][] = []
|
||||
|
||||
let rawContent = content
|
||||
|
||||
if (note?.id) {
|
||||
tags = note.tags
|
||||
if (route.params?.type === 'reply') {
|
||||
tags = note.tags
|
||||
if (getETags(note).length === 0) {
|
||||
tags.push(['e', note.id, '', 'root'])
|
||||
} else {
|
||||
tags.push(['e', note.id, '', 'reply'])
|
||||
}
|
||||
const eTags = getETags(note)
|
||||
tags.push(['e', note.id, '', eTags.length > 0 ? 'reply' : 'root'])
|
||||
tags.push(['p', note.pubkey, ''])
|
||||
} else if (route.params?.type === 'repost') {
|
||||
rawContent = `#[${tags.length}] ${rawContent}`
|
||||
@ -149,7 +145,7 @@ export const SendPage: React.FC<SendPageProps> = ({ route }) => {
|
||||
const userText = mentionText(user)
|
||||
if (rawContent.includes(userText)) {
|
||||
rawContent = rawContent.replace(userText, `#[${tags.length}]`)
|
||||
tags.push(['p', user.id])
|
||||
tags.push(['p', user.id, ''])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user