mirror of
https://github.com/KoalaSat/nostros.git
synced 2024-09-29 06:30:47 +00:00
Push to relay
This commit is contained in:
parent
9161e7ad90
commit
a125001e63
@ -188,7 +188,7 @@ public class Event {
|
|||||||
protected void saveNote(SQLiteDatabase database, String userPubKey, String relayUrl) {
|
protected void saveNote(SQLiteDatabase database, String userPubKey, String relayUrl) {
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put("id", id);
|
values.put("id", id);
|
||||||
values.put("content", content.replace("'", "''"));
|
values.put("content", content);
|
||||||
values.put("created_at", created_at);
|
values.put("created_at", created_at);
|
||||||
values.put("kind", kind);
|
values.put("kind", kind);
|
||||||
values.put("pubkey", pubkey);
|
values.put("pubkey", pubkey);
|
||||||
|
@ -110,4 +110,22 @@ public class RelayPoolModule extends ReactContextBaseJavaModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void sendAll(String message, boolean isGlobalFeed) {
|
||||||
|
for (Relay relay : relays) {
|
||||||
|
if (relay.active() > 0 && (!isGlobalFeed || relay.globalFeed > 0)) {
|
||||||
|
relay.send(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void sendRelay(String message, String relayUrl) {
|
||||||
|
for (Relay relay : relays) {
|
||||||
|
if (relay.active() > 0 && relayUrl.equals(relay.url)) {
|
||||||
|
relay.send(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
BIN
assets/images/placeholders/placeholder_bluebird.png
Normal file
BIN
assets/images/placeholders/placeholder_bluebird.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.0 KiB |
@ -6,6 +6,7 @@ import { AppContext } from '../../Contexts/AppContext'
|
|||||||
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
||||||
import { UserContext } from '../../Contexts/UserContext'
|
import { UserContext } from '../../Contexts/UserContext'
|
||||||
import {
|
import {
|
||||||
|
addUser,
|
||||||
getUser,
|
getUser,
|
||||||
updateUserBlock,
|
updateUserBlock,
|
||||||
updateUserContact,
|
updateUserContact,
|
||||||
@ -32,6 +33,7 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({ user, setUser })
|
|||||||
const { publicKey } = React.useContext(UserContext)
|
const { publicKey } = React.useContext(UserContext)
|
||||||
const { relayPool, updateRelayItem } = React.useContext(RelayPoolContext)
|
const { relayPool, updateRelayItem } = React.useContext(RelayPoolContext)
|
||||||
const [isContact, setIsContact] = React.useState<boolean>()
|
const [isContact, setIsContact] = React.useState<boolean>()
|
||||||
|
const [isBlocked, setIsBlocked] = React.useState<boolean>()
|
||||||
const [showNotification, setShowNotification] = React.useState<undefined | string>()
|
const [showNotification, setShowNotification] = React.useState<undefined | string>()
|
||||||
const [showNotificationRelay, setShowNotificationRelay] = React.useState<undefined | string>()
|
const [showNotificationRelay, setShowNotificationRelay] = React.useState<undefined | string>()
|
||||||
const bottomSheetRelaysRef = React.useRef<RBSheet>(null)
|
const bottomSheetRelaysRef = React.useRef<RBSheet>(null)
|
||||||
@ -59,6 +61,8 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({ user, setUser })
|
|||||||
getUser(user.id, database).then((result) => {
|
getUser(user.id, database).then((result) => {
|
||||||
if (result) {
|
if (result) {
|
||||||
setUser(result)
|
setUser(result)
|
||||||
|
setIsContact(result.contact)
|
||||||
|
setIsBlocked(result.blocked !== undefined && result.blocked > 0)
|
||||||
} else if (user.id === publicKey) {
|
} else if (user.id === publicKey) {
|
||||||
setUser({
|
setUser({
|
||||||
id: publicKey,
|
id: publicKey,
|
||||||
@ -69,9 +73,12 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({ user, setUser })
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onChangeBlockUser: () => void = () => {
|
const onChangeBlockUser: () => void = () => {
|
||||||
if (database && user?.blocked !== undefined) {
|
if (database) {
|
||||||
updateUserBlock(user.id, database, !user?.blocked).then(() => {
|
addUser(user.id, database).then(() => {
|
||||||
|
updateUserBlock(user.id, database, !isBlocked).then(() => {
|
||||||
loadUser()
|
loadUser()
|
||||||
|
setShowNotificationRelay(isBlocked ? 'userUnblocked' : 'userBlocked')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,7 +167,7 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({ user, setUser })
|
|||||||
}}
|
}}
|
||||||
disabled={user.id === publicKey}
|
disabled={user.id === publicKey}
|
||||||
/>
|
/>
|
||||||
<Text>{isContact ? t('profilePage.unfollow') : t('profilePage.follow')}</Text>
|
<Text>{isContact ? t('profileCard.unfollow') : t('profileCard.follow')}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.actionButton}>
|
<View style={styles.actionButton}>
|
||||||
<IconButton
|
<IconButton
|
||||||
@ -173,7 +180,7 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({ user, setUser })
|
|||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Text>{t('profilePage.message')}</Text>
|
<Text>{t('profileCard.message')}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.actionButton}>
|
<View style={styles.actionButton}>
|
||||||
<IconButton
|
<IconButton
|
||||||
@ -183,7 +190,7 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({ user, setUser })
|
|||||||
disabled={!user?.lnurl}
|
disabled={!user?.lnurl}
|
||||||
iconColor='#F5D112'
|
iconColor='#F5D112'
|
||||||
/>
|
/>
|
||||||
<Text>{t('profilePage.invoice')}</Text>
|
<Text>{t('profileCard.invoice')}</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.mainLayout}>
|
<View style={styles.mainLayout}>
|
||||||
@ -211,14 +218,14 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({ user, setUser })
|
|||||||
size={28}
|
size={28}
|
||||||
onPress={() => bottomSheetRelaysRef.current?.open()}
|
onPress={() => bottomSheetRelaysRef.current?.open()}
|
||||||
/>
|
/>
|
||||||
<Text>{t('profilePage.relaysTitle')}</Text>
|
<Text>{t('profileCard.relaysTitle')}</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<RBSheet ref={bottomSheetRelaysRef} closeOnDragDown={true} customStyles={bottomSheetStyles}>
|
<RBSheet ref={bottomSheetRelaysRef} closeOnDragDown={true} customStyles={bottomSheetStyles}>
|
||||||
<View>
|
<View>
|
||||||
<Text variant='titleLarge'>{t('profilePage.relaysTitle')}</Text>
|
<Text variant='titleLarge'>{t('profileCard.relaysTitle')}</Text>
|
||||||
<Text variant='bodyMedium'>
|
<Text variant='bodyMedium'>
|
||||||
{t('profilePage.relaysDescription', { username: username(user) })}
|
{t('profileCard.relaysDescription', { username: username(user) })}
|
||||||
</Text>
|
</Text>
|
||||||
<List.Item
|
<List.Item
|
||||||
title={t('relaysPage.relayName')}
|
title={t('relaysPage.relayName')}
|
||||||
@ -242,7 +249,7 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({ user, setUser })
|
|||||||
onIconPress={() => setShowNotificationRelay(undefined)}
|
onIconPress={() => setShowNotificationRelay(undefined)}
|
||||||
onDismiss={() => setShowNotificationRelay(undefined)}
|
onDismiss={() => setShowNotificationRelay(undefined)}
|
||||||
>
|
>
|
||||||
{t(`profilePage.${showNotificationRelay}`)}
|
{t(`profileCard.notifications.${showNotificationRelay}`)}
|
||||||
</Snackbar>
|
</Snackbar>
|
||||||
)}
|
)}
|
||||||
</RBSheet>
|
</RBSheet>
|
||||||
@ -258,7 +265,7 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({ user, setUser })
|
|||||||
onIconPress={() => setShowNotification(undefined)}
|
onIconPress={() => setShowNotification(undefined)}
|
||||||
onDismiss={() => setShowNotification(undefined)}
|
onDismiss={() => setShowNotification(undefined)}
|
||||||
>
|
>
|
||||||
{t(`profilePage.${showNotification}`)}
|
{t(`profileCard.notifications.${showNotification}`)}
|
||||||
</Snackbar>
|
</Snackbar>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
@ -1,7 +1,16 @@
|
|||||||
import { t } from 'i18next'
|
import { t } from 'i18next'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { StyleSheet, Switch, View } from 'react-native'
|
import { StyleSheet, Switch, View } from 'react-native'
|
||||||
import { Divider, IconButton, List, Snackbar, Text } from 'react-native-paper'
|
import {
|
||||||
|
Button,
|
||||||
|
Checkbox,
|
||||||
|
Divider,
|
||||||
|
IconButton,
|
||||||
|
List,
|
||||||
|
Snackbar,
|
||||||
|
Text,
|
||||||
|
useTheme,
|
||||||
|
} from 'react-native-paper'
|
||||||
import { AppContext } from '../../Contexts/AppContext'
|
import { AppContext } from '../../Contexts/AppContext'
|
||||||
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
||||||
import RBSheet from 'react-native-raw-bottom-sheet'
|
import RBSheet from 'react-native-raw-bottom-sheet'
|
||||||
@ -12,6 +21,10 @@ import axios from 'axios'
|
|||||||
import { ScrollView } from 'react-native-gesture-handler'
|
import { ScrollView } from 'react-native-gesture-handler'
|
||||||
import Clipboard from '@react-native-clipboard/clipboard'
|
import Clipboard from '@react-native-clipboard/clipboard'
|
||||||
import Logo from '../Logo'
|
import Logo from '../Logo'
|
||||||
|
import { getRawUserNotes } from '../../Functions/DatabaseFunctions/Notes'
|
||||||
|
import { UserContext } from '../../Contexts/UserContext'
|
||||||
|
import { getRawUserReactions } from '../../Functions/DatabaseFunctions/Reactions'
|
||||||
|
import { getRawUserConversation } from '../../Functions/DatabaseFunctions/DirectMessages'
|
||||||
|
|
||||||
interface RelayCardProps {
|
interface RelayCardProps {
|
||||||
url?: string
|
url?: string
|
||||||
@ -19,18 +32,49 @@ interface RelayCardProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const RelayCard: React.FC<RelayCardProps> = ({ url, bottomSheetRef }) => {
|
export const RelayCard: React.FC<RelayCardProps> = ({ url, bottomSheetRef }) => {
|
||||||
const { updateRelayItem } = React.useContext(RelayPoolContext)
|
const theme = useTheme()
|
||||||
|
const { publicKey } = React.useContext(UserContext)
|
||||||
|
const { updateRelayItem, relayPool } = React.useContext(RelayPoolContext)
|
||||||
const { database } = React.useContext(AppContext)
|
const { database } = React.useContext(AppContext)
|
||||||
const [relay, setRelay] = React.useState<Relay>()
|
const [relay, setRelay] = React.useState<Relay>()
|
||||||
const [uri, setUri] = React.useState<string>()
|
const [uri, setUri] = React.useState<string>()
|
||||||
const [relayInfo, setRelayInfo] = React.useState<RelayInfo>()
|
const [relayInfo, setRelayInfo] = React.useState<RelayInfo>()
|
||||||
const [showNotification, setShowNotification] = React.useState<string>()
|
const [showNotification, setShowNotification] = React.useState<string>()
|
||||||
|
const [checkedPush, setCheckedPush] = React.useState<'checked' | 'unchecked' | 'indeterminate'>(
|
||||||
|
'unchecked',
|
||||||
|
)
|
||||||
const [moreInfo, setMoreInfo] = React.useState<boolean>(false)
|
const [moreInfo, setMoreInfo] = React.useState<boolean>(false)
|
||||||
|
const [pushDone, setPushDone] = React.useState<boolean>(false)
|
||||||
|
const [pushUserHistoric, setPushUserHistoric] = React.useState<boolean>(false)
|
||||||
|
const bottomSheetPushRelayRef = React.useRef<RBSheet>(null)
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
loadRelay()
|
loadRelay()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (pushUserHistoric && url && database && publicKey && relayPool) {
|
||||||
|
getRawUserNotes(database, publicKey).then((resultNotes) => {
|
||||||
|
resultNotes.forEach((note) => {
|
||||||
|
note.content = note.content.replace("''", "'")
|
||||||
|
relayPool.sendEvent(note, url)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
getRawUserReactions(database, publicKey).then((resultReactions) => {
|
||||||
|
resultReactions.forEach((reaction) => {
|
||||||
|
relayPool.sendEvent(reaction, url)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
getRawUserConversation(database, publicKey).then((resultConversations) => {
|
||||||
|
resultConversations.forEach((conversation) => {
|
||||||
|
conversation.content = conversation.content.replace("''", "'")
|
||||||
|
relayPool.sendEvent(conversation, url)
|
||||||
|
})
|
||||||
|
setPushDone(true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [pushUserHistoric])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (relay) {
|
if (relay) {
|
||||||
setUri(relay.url)
|
setUri(relay.url)
|
||||||
@ -110,6 +154,21 @@ export const RelayCard: React.FC<RelayCardProps> = ({ url, bottomSheetRef }) =>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bottomSheetStyles = React.useMemo(() => {
|
||||||
|
return {
|
||||||
|
container: {
|
||||||
|
backgroundColor: theme.colors.background,
|
||||||
|
paddingTop: 16,
|
||||||
|
paddingRight: 16,
|
||||||
|
paddingBottom: 32,
|
||||||
|
paddingLeft: 16,
|
||||||
|
borderTopRightRadius: 28,
|
||||||
|
borderTopLeftRadius: 28,
|
||||||
|
height: 'auto',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
return relay ? (
|
return relay ? (
|
||||||
<View>
|
<View>
|
||||||
<View style={styles.relayDescription}>
|
<View style={styles.relayDescription}>
|
||||||
@ -215,6 +274,14 @@ export const RelayCard: React.FC<RelayCardProps> = ({ url, bottomSheetRef }) =>
|
|||||||
</View>
|
</View>
|
||||||
<Divider />
|
<Divider />
|
||||||
<View style={styles.actions}>
|
<View style={styles.actions}>
|
||||||
|
<View style={styles.actionButton}>
|
||||||
|
<IconButton
|
||||||
|
icon={'upload-multiple'}
|
||||||
|
size={28}
|
||||||
|
onPress={() => bottomSheetPushRelayRef.current?.open()}
|
||||||
|
/>
|
||||||
|
<Text>{t('relayCard.pushRelay')}</Text>
|
||||||
|
</View>
|
||||||
<View style={styles.actionButton}>
|
<View style={styles.actionButton}>
|
||||||
<IconButton
|
<IconButton
|
||||||
icon={'share-variant-outline'}
|
icon={'share-variant-outline'}
|
||||||
@ -238,6 +305,50 @@ export const RelayCard: React.FC<RelayCardProps> = ({ url, bottomSheetRef }) =>
|
|||||||
{t(`relayCard.notifications.${showNotification}`)}
|
{t(`relayCard.notifications.${showNotification}`)}
|
||||||
</Snackbar>
|
</Snackbar>
|
||||||
)}
|
)}
|
||||||
|
<RBSheet
|
||||||
|
ref={bottomSheetPushRelayRef}
|
||||||
|
closeOnPressMask={!pushUserHistoric}
|
||||||
|
customStyles={bottomSheetStyles}
|
||||||
|
onClose={() => {}}
|
||||||
|
>
|
||||||
|
<Text variant='titleLarge'>{t('relayCard.pushHistoricTitle')}</Text>
|
||||||
|
<Text>{t('relayCard.pushHistoricDescription')}</Text>
|
||||||
|
<View style={[styles.warning, { backgroundColor: '#683D00' }]}>
|
||||||
|
<Text variant='titleSmall' style={[styles.warningTitle, { color: '#FFDCBB' }]}>
|
||||||
|
{t('relayCard.pushHistoricAlertTitle')}
|
||||||
|
</Text>
|
||||||
|
<Text style={{ color: '#FFDCBB' }}>{t('relayCard.pushHistoricAlert')}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={styles.row}>
|
||||||
|
<Text>{t('relayCard.pushConsent')}</Text>
|
||||||
|
<Checkbox
|
||||||
|
status={checkedPush}
|
||||||
|
onPress={() => setCheckedPush(checkedPush === 'checked' ? 'unchecked' : 'checked')}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<Button
|
||||||
|
style={styles.buttonSpacer}
|
||||||
|
mode='contained'
|
||||||
|
onPress={() => setPushUserHistoric(true)}
|
||||||
|
disabled={pushUserHistoric || checkedPush !== 'checked'}
|
||||||
|
loading={pushUserHistoric && !pushDone}
|
||||||
|
>
|
||||||
|
{pushDone
|
||||||
|
? t('relayCard.pushDone')
|
||||||
|
: pushUserHistoric
|
||||||
|
? t('relayCard.pushingEvent')
|
||||||
|
: t('relayCard.pushHistoricTitle')}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
mode='outlined'
|
||||||
|
onPress={() => {
|
||||||
|
bottomSheetPushRelayRef.current?.close()
|
||||||
|
}}
|
||||||
|
disabled={pushUserHistoric}
|
||||||
|
>
|
||||||
|
{t('relayCard.cancel')}
|
||||||
|
</Button>
|
||||||
|
</RBSheet>
|
||||||
</View>
|
</View>
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
@ -245,6 +356,12 @@ export const RelayCard: React.FC<RelayCardProps> = ({ url, bottomSheetRef }) =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
row: {
|
||||||
|
alignItems: 'center',
|
||||||
|
flexDirection: 'row',
|
||||||
|
height: 56,
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
},
|
||||||
container: {
|
container: {
|
||||||
padding: 16,
|
padding: 16,
|
||||||
},
|
},
|
||||||
@ -287,6 +404,19 @@ const styles = StyleSheet.create({
|
|||||||
marginBottom: 4,
|
marginBottom: 4,
|
||||||
width: '33%',
|
width: '33%',
|
||||||
},
|
},
|
||||||
|
buttonSpacer: {
|
||||||
|
marginTop: 16,
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
warning: {
|
||||||
|
borderRadius: 4,
|
||||||
|
padding: 16,
|
||||||
|
marginTop: 16,
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
warningTitle: {
|
||||||
|
marginBottom: 8,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export default RelayCard
|
export default RelayCard
|
||||||
|
@ -48,6 +48,7 @@ export const TextContent: React.FC<TextContentProps> = ({
|
|||||||
const DEFAULT_COVER = '../../../assets/images/placeholders/placeholder_url.png'
|
const DEFAULT_COVER = '../../../assets/images/placeholders/placeholder_url.png'
|
||||||
const MEDIA_COVER = '../../../assets/images/placeholders/placeholder_media.png'
|
const MEDIA_COVER = '../../../assets/images/placeholders/placeholder_media.png'
|
||||||
const IMAGE_COVER = '../../../assets/images/placeholders/placeholder_image.png'
|
const IMAGE_COVER = '../../../assets/images/placeholders/placeholder_image.png'
|
||||||
|
const BLUEBIRD_COVER = '../../../assets/images/placeholders/placeholder_bluebird.png'
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!linkPreview && url) {
|
if (!linkPreview && url) {
|
||||||
@ -162,11 +163,9 @@ export const TextContent: React.FC<TextContentProps> = ({
|
|||||||
|
|
||||||
const getDefaultCover: () => number = () => {
|
const getDefaultCover: () => number = () => {
|
||||||
if (!linkPreview) return require(DEFAULT_COVER)
|
if (!linkPreview) return require(DEFAULT_COVER)
|
||||||
|
if (linkType === 'blueBird') return require(BLUEBIRD_COVER)
|
||||||
if (linkType === 'audio') return require(MEDIA_COVER)
|
if (linkType === 'audio') return require(MEDIA_COVER)
|
||||||
if (linkType === 'video') return require(MEDIA_COVER)
|
if (linkType === 'video') return require(MEDIA_COVER)
|
||||||
if (linkType === 'blueBird') return require(DEFAULT_COVER)
|
|
||||||
if (linkType === 'image') return require(IMAGE_COVER)
|
|
||||||
|
|
||||||
return require(DEFAULT_COVER)
|
return require(DEFAULT_COVER)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,6 +196,7 @@ export const TextContent: React.FC<TextContentProps> = ({
|
|||||||
{url && (
|
{url && (
|
||||||
<View style={styles.previewCard}>
|
<View style={styles.previewCard}>
|
||||||
<Card onPress={() => handleUrlPress(url)}>
|
<Card onPress={() => handleUrlPress(url)}>
|
||||||
|
{linkType === 'image' ? (
|
||||||
<FastImage
|
<FastImage
|
||||||
style={[
|
style={[
|
||||||
styles.cardCover,
|
styles.cardCover,
|
||||||
@ -208,9 +208,13 @@ export const TextContent: React.FC<TextContentProps> = ({
|
|||||||
uri: getRequireCover(),
|
uri: getRequireCover(),
|
||||||
priority: FastImage.priority.high,
|
priority: FastImage.priority.high,
|
||||||
}}
|
}}
|
||||||
defaultSource={getDefaultCover()}
|
|
||||||
resizeMode={FastImage.resizeMode.contain}
|
resizeMode={FastImage.resizeMode.contain}
|
||||||
|
defaultSource={require(IMAGE_COVER)}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<Card.Cover source={getDefaultCover()} resizeMode='contain' />
|
||||||
|
)}
|
||||||
|
{linkType !== 'image' && (
|
||||||
<Card.Content style={styles.previewContent}>
|
<Card.Content style={styles.previewContent}>
|
||||||
<Text variant='bodyMedium' numberOfLines={3}>
|
<Text variant='bodyMedium' numberOfLines={3}>
|
||||||
{/* {linkPreview?.title ?? linkPreview?.url ?? url} */}
|
{/* {linkPreview?.title ?? linkPreview?.url ?? url} */}
|
||||||
@ -222,6 +226,7 @@ export const TextContent: React.FC<TextContentProps> = ({
|
|||||||
</Text>
|
</Text>
|
||||||
)} */}
|
)} */}
|
||||||
</Card.Content>
|
</Card.Content>
|
||||||
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
@ -274,8 +279,7 @@ const styles = StyleSheet.create({
|
|||||||
cardCover: {
|
cardCover: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
height: 180,
|
height: 180,
|
||||||
borderTopLeftRadius: 16,
|
borderRadius: 16,
|
||||||
borderTopRightRadius: 16,
|
|
||||||
},
|
},
|
||||||
url: {
|
url: {
|
||||||
textDecorationLine: 'underline',
|
textDecorationLine: 'underline',
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { QueryResult, QuickSQLiteConnection } from 'react-native-quick-sqlite'
|
import { QueryResult, QuickSQLiteConnection } from 'react-native-quick-sqlite'
|
||||||
import { getItems } from '..'
|
import { getItems } from '..'
|
||||||
import { Event } from '../../../lib/nostr/Events'
|
import { Event, evetDatabaseToEntity } from '../../../lib/nostr/Events'
|
||||||
|
|
||||||
export interface DirectMessage extends Event {
|
export interface DirectMessage extends Event {
|
||||||
conversation_id: string
|
conversation_id: string
|
||||||
@ -13,6 +13,21 @@ const databaseToEntity: (object: any) => DirectMessage = (object = {}) => {
|
|||||||
return object as DirectMessage
|
return object as DirectMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getRawUserConversation: (
|
||||||
|
db: QuickSQLiteConnection,
|
||||||
|
pubKey: string,
|
||||||
|
) => Promise<Event[]> = async (db, pubKey) => {
|
||||||
|
const notesQuery = `SELECT * FROM nostros_direct_messages
|
||||||
|
WHERE pubkey = ?
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
`
|
||||||
|
const resultSet = await db.execute(notesQuery, [pubKey])
|
||||||
|
const items: object[] = getItems(resultSet)
|
||||||
|
const notes: Event[] = items.map((object) => evetDatabaseToEntity(object))
|
||||||
|
|
||||||
|
return notes
|
||||||
|
}
|
||||||
|
|
||||||
export const updateConversationRead: (
|
export const updateConversationRead: (
|
||||||
conversationId: string,
|
conversationId: string,
|
||||||
db: QuickSQLiteConnection,
|
db: QuickSQLiteConnection,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { QuickSQLiteConnection } from 'react-native-quick-sqlite'
|
import { QuickSQLiteConnection } from 'react-native-quick-sqlite'
|
||||||
import { getItems } from '..'
|
import { getItems } from '..'
|
||||||
import { Event } from '../../../lib/nostr/Events'
|
import { Event, evetDatabaseToEntity } from '../../../lib/nostr/Events'
|
||||||
|
|
||||||
export interface Note extends Event {
|
export interface Note extends Event {
|
||||||
name: string
|
name: string
|
||||||
@ -271,6 +271,21 @@ export const getLastReply: (
|
|||||||
return reaction
|
return reaction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getRawUserNotes: (
|
||||||
|
db: QuickSQLiteConnection,
|
||||||
|
pubKey: string,
|
||||||
|
) => Promise<Event[]> = async (db, pubKey) => {
|
||||||
|
const notesQuery = `SELECT * FROM nostros_notes
|
||||||
|
WHERE pubkey = ?
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
`
|
||||||
|
const resultSet = await db.execute(notesQuery, [pubKey])
|
||||||
|
const items: object[] = getItems(resultSet)
|
||||||
|
const notes: Event[] = items.map((object) => evetDatabaseToEntity(object))
|
||||||
|
|
||||||
|
return notes
|
||||||
|
}
|
||||||
|
|
||||||
export const getNotes: (
|
export const getNotes: (
|
||||||
db: QuickSQLiteConnection,
|
db: QuickSQLiteConnection,
|
||||||
options: {
|
options: {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { QuickSQLiteConnection } from 'react-native-quick-sqlite'
|
import { QuickSQLiteConnection } from 'react-native-quick-sqlite'
|
||||||
import { getItems } from '..'
|
import { getItems } from '..'
|
||||||
import { Event } from '../../../lib/nostr/Events'
|
import { Event, evetDatabaseToEntity } from '../../../lib/nostr/Events'
|
||||||
|
|
||||||
export interface Reaction extends Event {
|
export interface Reaction extends Event {
|
||||||
positive: boolean
|
positive: boolean
|
||||||
@ -12,6 +12,21 @@ const databaseToEntity: (object: object) => Reaction = (object) => {
|
|||||||
return object as Reaction
|
return object as Reaction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getRawUserReactions: (
|
||||||
|
db: QuickSQLiteConnection,
|
||||||
|
pubKey: string,
|
||||||
|
) => Promise<Event[]> = async (db, pubKey) => {
|
||||||
|
const notesQuery = `SELECT * FROM nostros_reactions
|
||||||
|
WHERE pubkey = ?
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
`
|
||||||
|
const resultSet = await db.execute(notesQuery, [pubKey])
|
||||||
|
const items: object[] = getItems(resultSet)
|
||||||
|
const notes: Event[] = items.map((object) => evetDatabaseToEntity(object))
|
||||||
|
|
||||||
|
return notes
|
||||||
|
}
|
||||||
|
|
||||||
export const getReactions: (
|
export const getReactions: (
|
||||||
db: QuickSQLiteConnection,
|
db: QuickSQLiteConnection,
|
||||||
filters: {
|
filters: {
|
||||||
|
@ -36,7 +36,7 @@ export const relayToColor: (string: string) => string = (string) => {
|
|||||||
for (let i = 0; i < string.length; i++) {
|
for (let i = 0; i < string.length; i++) {
|
||||||
hash = string.charCodeAt(i) + ((hash << 5) - hash)
|
hash = string.charCodeAt(i) + ((hash << 5) - hash)
|
||||||
}
|
}
|
||||||
return relayColors[(Math.abs(hash) % relayColors.length) - 1]
|
return relayColors[Math.abs(hash) % (relayColors.length - 1)]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const pickRandomItems = <T extends unknown>(arr: T[], n: number): T[] => {
|
export const pickRandomItems = <T extends unknown>(arr: T[], n: number): T[] => {
|
||||||
@ -65,7 +65,7 @@ export const validMediaUrl: (url: string | undefined) => boolean = (url) => {
|
|||||||
|
|
||||||
export const validBlueBirdUrl: (url: string | undefined) => boolean = (url) => {
|
export const validBlueBirdUrl: (url: string | undefined) => boolean = (url) => {
|
||||||
if (url) {
|
if (url) {
|
||||||
const serviceRegexp = /^(https?:\/\/(?:twitter.com).*)$/
|
const serviceRegexp = /^(https?:\/\/(?:twitter.com|t.co).*)$/
|
||||||
return serviceRegexp.test(url)
|
return serviceRegexp.test(url)
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
|
@ -102,6 +102,8 @@
|
|||||||
"copied": "Privaten Schlüssel kopiert. Verwahre ihn an einem sicheren Ort!",
|
"copied": "Privaten Schlüssel kopiert. Verwahre ihn an einem sicheren Ort!",
|
||||||
"wrongWords": "Die Wörter stimmen nicht überein"
|
"wrongWords": "Die Wörter stimmen nicht überein"
|
||||||
},
|
},
|
||||||
|
"skip": "Skip",
|
||||||
|
"confirmTitle": "Type the words in the right order.",
|
||||||
"snackbarDescription": "Wichtig. Verwahre den Schlüssel an einem sicheren Ort. Bei Verlust kann dieses Konto nie wieder benutzt werden!",
|
"snackbarDescription": "Wichtig. Verwahre den Schlüssel an einem sicheren Ort. Bei Verlust kann dieses Konto nie wieder benutzt werden!",
|
||||||
"snackbarAction": "Privaten Schlüssel kopieren",
|
"snackbarAction": "Privaten Schlüssel kopieren",
|
||||||
"warningTitle": "Wichtig!",
|
"warningTitle": "Wichtig!",
|
||||||
@ -172,6 +174,7 @@
|
|||||||
"newMessages": "{{newNotesCount}} neue Nachrichten. Zum Aktualisieren tippen."
|
"newMessages": "{{newNotesCount}} neue Nachrichten. Zum Aktualisieren tippen."
|
||||||
},
|
},
|
||||||
"relayCard": {
|
"relayCard": {
|
||||||
|
"pushDone": "Completed",
|
||||||
"moreInfo": "Mehr Infos",
|
"moreInfo": "Mehr Infos",
|
||||||
"lessInfo": "Weniger Infos",
|
"lessInfo": "Weniger Infos",
|
||||||
"globalFeed": "Globaler Feed",
|
"globalFeed": "Globaler Feed",
|
||||||
@ -273,7 +276,6 @@
|
|||||||
"isFollower": "folgt dir",
|
"isFollower": "folgt dir",
|
||||||
"unfollow": "Nicht mehr folgen",
|
"unfollow": "Nicht mehr folgen",
|
||||||
"copyNPub": "Schlüssel kopieren",
|
"copyNPub": "Schlüssel kopieren",
|
||||||
"relaysTitle": "Relays",
|
|
||||||
"relaysDescription": "Dies sind {{username}}'s Relays, aktiviere diejenigen, zu denen du verbunden werden möchtest."
|
"relaysDescription": "Dies sind {{username}}'s Relays, aktiviere diejenigen, zu denen du verbunden werden möchtest."
|
||||||
},
|
},
|
||||||
"homePage": {
|
"homePage": {
|
||||||
@ -301,7 +303,9 @@
|
|||||||
"profileCard": {
|
"profileCard": {
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"contactAdded": "Aboniert",
|
"contactAdded": "Aboniert",
|
||||||
"contactRemoved": "Abo entfernt"
|
"contactRemoved": "Abo entfernt",
|
||||||
|
"userUnblocked": "Profile unblocked",
|
||||||
|
"userBlocked": "Profile unblocked"
|
||||||
},
|
},
|
||||||
"invoice": "Zap",
|
"invoice": "Zap",
|
||||||
"message": "Nachricht",
|
"message": "Nachricht",
|
||||||
@ -309,7 +313,8 @@
|
|||||||
"block": "Blockieren",
|
"block": "Blockieren",
|
||||||
"share": "Teilen",
|
"share": "Teilen",
|
||||||
"unblock": "Erlauben",
|
"unblock": "Erlauben",
|
||||||
"unfollow": "Abo entfernen"
|
"unfollow": "Abo entfernen",
|
||||||
|
"relaysTitle": "Relays"
|
||||||
},
|
},
|
||||||
"conversationsFeed": {
|
"conversationsFeed": {
|
||||||
"openMessage": "Unterhaltung beginnen",
|
"openMessage": "Unterhaltung beginnen",
|
||||||
|
@ -103,6 +103,8 @@
|
|||||||
"copied": "Private key copied.\n\nStore this key in a safe place.",
|
"copied": "Private key copied.\n\nStore this key in a safe place.",
|
||||||
"wrongWords": "The words don't match"
|
"wrongWords": "The words don't match"
|
||||||
},
|
},
|
||||||
|
"skip": "Skip",
|
||||||
|
"confirmTitle": "Type the words in the right order.",
|
||||||
"warningTitle": "Important",
|
"warningTitle": "Important",
|
||||||
"warningDescription": "Store your key in a safe place. If lose it, you won't be able to access or recover your profile.",
|
"warningDescription": "Store your key in a safe place. If lose it, you won't be able to access or recover your profile.",
|
||||||
"warningAction": "Copy private key",
|
"warningAction": "Copy private key",
|
||||||
@ -186,7 +188,7 @@
|
|||||||
"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.",
|
"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",
|
"centralized": "Centralized",
|
||||||
"small": "Small",
|
"small": "Small",
|
||||||
"contacts": "# Contacts",
|
"contacts": "Assigned Contacts",
|
||||||
"resilienceMode": "Resilience (experimental)",
|
"resilienceMode": "Resilience (experimental)",
|
||||||
"relayName": "Address",
|
"relayName": "Address",
|
||||||
"globalFeed": "Global feed",
|
"globalFeed": "Global feed",
|
||||||
@ -210,6 +212,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"relayCard": {
|
"relayCard": {
|
||||||
|
"pushDone": "Completed",
|
||||||
|
"pushHistoricTitle": "Push all my data",
|
||||||
|
"pushHistoricDescription": "Nostros stores on his own database all the data received from relays. With this option you can push to any relay all the data Nostros has associated to your profile.",
|
||||||
|
"pushHistoricAlertTitle": "Important",
|
||||||
|
"pushHistoricAlert": "Public relays have strong anti-spam policies and this action might ban your key. Make sure you are allowed to send big chunks of data to this relay.\n\nWe recomend to use this feature only for private relays like Umbrel's Nostr Relay.",
|
||||||
|
"pushConsent": "I'm pushing my events to a private relay",
|
||||||
|
"pushingEvent": "Event {{eventId}} pushed",
|
||||||
|
"pushRelay": "Push all my data",
|
||||||
|
"cancel": "Cancel",
|
||||||
"moreInfo": "More info",
|
"moreInfo": "More info",
|
||||||
"lessInfo": "Less info",
|
"lessInfo": "Less info",
|
||||||
"globalFeed": "Global Feed",
|
"globalFeed": "Global Feed",
|
||||||
@ -284,7 +295,6 @@
|
|||||||
"follow": "Follow",
|
"follow": "Follow",
|
||||||
"unfollow": "Following",
|
"unfollow": "Following",
|
||||||
"copyNPub": "Copy key",
|
"copyNPub": "Copy key",
|
||||||
"relaysTitle": "Relays",
|
|
||||||
"isFollower": "follows you",
|
"isFollower": "follows you",
|
||||||
"relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected."
|
"relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected."
|
||||||
},
|
},
|
||||||
@ -312,7 +322,9 @@
|
|||||||
"profileCard": {
|
"profileCard": {
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"contactAdded": "Profile followed",
|
"contactAdded": "Profile followed",
|
||||||
"contactRemoved": "Profile unfollowed"
|
"contactRemoved": "Profile unfollowed",
|
||||||
|
"userUnblocked": "Profile unblocked",
|
||||||
|
"userBlocked": "Profile unblocked"
|
||||||
},
|
},
|
||||||
"invoice": "Tip",
|
"invoice": "Tip",
|
||||||
"message": "Message",
|
"message": "Message",
|
||||||
@ -320,7 +332,8 @@
|
|||||||
"unfollow": "Following",
|
"unfollow": "Following",
|
||||||
"block": "Block",
|
"block": "Block",
|
||||||
"unblock": "Unblock",
|
"unblock": "Unblock",
|
||||||
"share": "Share"
|
"share": "Share",
|
||||||
|
"relaysTitle": "Relays"
|
||||||
},
|
},
|
||||||
"conversationsFeed": {
|
"conversationsFeed": {
|
||||||
"openMessage": "Start conversation",
|
"openMessage": "Start conversation",
|
||||||
|
@ -102,6 +102,8 @@
|
|||||||
"copied": "Clave privada copiada. Guárdala en un lugar seguro.",
|
"copied": "Clave privada copiada. Guárdala en un lugar seguro.",
|
||||||
"wrongWords": "Las palabras no coinciden."
|
"wrongWords": "Las palabras no coinciden."
|
||||||
},
|
},
|
||||||
|
"skip": "Skip",
|
||||||
|
"confirmTitle": "Type the words in the right order.",
|
||||||
"snackbarDescription": "Importante. Guarda tu clave en un lugar seguro, si la pierdes, no será posible acceder a tu perfil.",
|
"snackbarDescription": "Importante. Guarda tu clave en un lugar seguro, si la pierdes, no será posible acceder a tu perfil.",
|
||||||
"snackbarAction": "Copiar clave privada",
|
"snackbarAction": "Copiar clave privada",
|
||||||
"warningTitle": "Importante",
|
"warningTitle": "Importante",
|
||||||
@ -169,6 +171,7 @@
|
|||||||
"myFeed": "Mi feed"
|
"myFeed": "Mi feed"
|
||||||
},
|
},
|
||||||
"relayCard": {
|
"relayCard": {
|
||||||
|
"pushDone": "Completado",
|
||||||
"moreInfo": "Más información",
|
"moreInfo": "Más información",
|
||||||
"lessInfo": "Menos información",
|
"lessInfo": "Menos información",
|
||||||
"globalFeed": "Feed Global",
|
"globalFeed": "Feed Global",
|
||||||
@ -267,7 +270,6 @@
|
|||||||
"follow": "Seguir",
|
"follow": "Seguir",
|
||||||
"unfollow": "Siguiendo",
|
"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."
|
"relaysDescription": "Estos son los relays de {{username}}, activa aquellos a los que quieras estar conectado."
|
||||||
},
|
},
|
||||||
"homePage": {
|
"homePage": {
|
||||||
@ -297,7 +299,9 @@
|
|||||||
"profileCard": {
|
"profileCard": {
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"contactAdded": "Siguiendo",
|
"contactAdded": "Siguiendo",
|
||||||
"contactRemoved": "Dejando de seguir"
|
"contactRemoved": "Dejando de seguir",
|
||||||
|
"userUnblocked": "Perfil desbloqueado",
|
||||||
|
"userBlocked": "Perfil bloqueado"
|
||||||
},
|
},
|
||||||
"invoice": "Propina",
|
"invoice": "Propina",
|
||||||
"message": "Mensaje",
|
"message": "Mensaje",
|
||||||
@ -305,7 +309,8 @@
|
|||||||
"block": "Bloquear",
|
"block": "Bloquear",
|
||||||
"share": "Share",
|
"share": "Share",
|
||||||
"unblock": "Desbloquear",
|
"unblock": "Desbloquear",
|
||||||
"unfollow": "Siguiendo"
|
"unfollow": "Siguiendo",
|
||||||
|
"relaysTitle": "Relays"
|
||||||
},
|
},
|
||||||
"conversationsFeed": {
|
"conversationsFeed": {
|
||||||
"openMessage": "Comenzar conversación",
|
"openMessage": "Comenzar conversación",
|
||||||
|
@ -102,6 +102,8 @@
|
|||||||
"copied": "Clé privée copiée. Gardez-la dans un endroit sûr.",
|
"copied": "Clé privée copiée. Gardez-la dans un endroit sûr.",
|
||||||
"wrongWords": "The words doesn't match"
|
"wrongWords": "The words doesn't match"
|
||||||
},
|
},
|
||||||
|
"skip": "Skip",
|
||||||
|
"confirmTitle": "Type the words in the right order.",
|
||||||
"snackbarDescription": "Important. Conservez votre clé dans un endroit sûr, si vous le perdez, vous ne pourrez pas accéder à votre compte.",
|
"snackbarDescription": "Important. Conservez votre clé dans un endroit sûr, si vous le perdez, vous ne pourrez pas accéder à votre compte.",
|
||||||
"snackbarAction": "Copier la clé privée",
|
"snackbarAction": "Copier la clé privée",
|
||||||
"warningTitle": "Important",
|
"warningTitle": "Important",
|
||||||
@ -170,6 +172,7 @@
|
|||||||
"myFeed": "Mon flux"
|
"myFeed": "Mon flux"
|
||||||
},
|
},
|
||||||
"relayCard": {
|
"relayCard": {
|
||||||
|
"pushDone": "Completed",
|
||||||
"moreInfo": "Plus d'info",
|
"moreInfo": "Plus d'info",
|
||||||
"lessInfo": "Moins d'info",
|
"lessInfo": "Moins d'info",
|
||||||
"globalFeed": "Flux Global",
|
"globalFeed": "Flux Global",
|
||||||
@ -199,7 +202,7 @@
|
|||||||
"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.",
|
"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",
|
"centralized": "Centralized",
|
||||||
"small": "Small",
|
"small": "Small",
|
||||||
"contacts": "# Contacts",
|
"contacts": "Assigned Contacts",
|
||||||
"resilienceMode": "Resilience (experimental)",
|
"resilienceMode": "Resilience (experimental)",
|
||||||
"relayName": "Adresse",
|
"relayName": "Adresse",
|
||||||
"globalFeed": "Flux global",
|
"globalFeed": "Flux global",
|
||||||
@ -268,7 +271,6 @@
|
|||||||
"isFollower": "follows you",
|
"isFollower": "follows you",
|
||||||
"unfollow": "Abonné",
|
"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."
|
"relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected."
|
||||||
},
|
},
|
||||||
"profileShare": {
|
"profileShare": {
|
||||||
@ -285,14 +287,17 @@
|
|||||||
"profileCard": {
|
"profileCard": {
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"contactAdded": "Abonné",
|
"contactAdded": "Abonné",
|
||||||
"contactRemoved": "Vous ne suivez plus ce profil"
|
"contactRemoved": "Vous ne suivez plus ce profil",
|
||||||
|
"userUnblocked": "Profile unblocked",
|
||||||
|
"userBlocked": "Profile unblocked"
|
||||||
},
|
},
|
||||||
"invoice": "Tip",
|
"invoice": "Tip",
|
||||||
"message": "Message",
|
"message": "Message",
|
||||||
"follow": "Abonné",
|
"follow": "Abonné",
|
||||||
"block": "Bloquer",
|
"block": "Bloquer",
|
||||||
"unblock": "Débloquer",
|
"unblock": "Débloquer",
|
||||||
"unfollow": "Abonné"
|
"unfollow": "Abonné",
|
||||||
|
"relaysTitle": "Relays"
|
||||||
},
|
},
|
||||||
"conversationsFeed": {
|
"conversationsFeed": {
|
||||||
"openMessage": "Commencer la conversation",
|
"openMessage": "Commencer la conversation",
|
||||||
|
@ -103,6 +103,8 @@
|
|||||||
"copied": "Приватный ключ скопирован.\n\nСохраните этот ключ в надежном месте.",
|
"copied": "Приватный ключ скопирован.\n\nСохраните этот ключ в надежном месте.",
|
||||||
"wrongWords": "The words doesn't match"
|
"wrongWords": "The words doesn't match"
|
||||||
},
|
},
|
||||||
|
"skip": "Skip",
|
||||||
|
"confirmTitle": "Type the words in the right order.",
|
||||||
"warningTitle": "Важно",
|
"warningTitle": "Важно",
|
||||||
"warningDescription": "Сохраните этот ключ в надежном месте. В случае утери ключа, Вы не сможете войти или восстановить доступ к профилю.",
|
"warningDescription": "Сохраните этот ключ в надежном месте. В случае утери ключа, Вы не сможете войти или восстановить доступ к профилю.",
|
||||||
"warningAction": "Скопировать приватный ключ",
|
"warningAction": "Скопировать приватный ключ",
|
||||||
@ -169,6 +171,7 @@
|
|||||||
"myFeed": "My feed"
|
"myFeed": "My feed"
|
||||||
},
|
},
|
||||||
"relayCard": {
|
"relayCard": {
|
||||||
|
"pushDone": "Completed",
|
||||||
"moreInfo": "Узнать больше",
|
"moreInfo": "Узнать больше",
|
||||||
"lessInfo": "Скрыть",
|
"lessInfo": "Скрыть",
|
||||||
"globalFeed": "Общая лента",
|
"globalFeed": "Общая лента",
|
||||||
@ -198,7 +201,7 @@
|
|||||||
"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.",
|
"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",
|
"centralized": "Centralized",
|
||||||
"small": "Small",
|
"small": "Small",
|
||||||
"contacts": "# Contacts",
|
"contacts": "Assigned Contacts",
|
||||||
"resilienceMode": "Resilience (experimental)",
|
"resilienceMode": "Resilience (experimental)",
|
||||||
"relayName": "Address",
|
"relayName": "Address",
|
||||||
"globalFeed": "Общая лента",
|
"globalFeed": "Общая лента",
|
||||||
@ -267,7 +270,6 @@
|
|||||||
"unfollow": "Following",
|
"unfollow": "Following",
|
||||||
"isFollower": "follows you",
|
"isFollower": "follows you",
|
||||||
"copyNPub": "Скопировать ключ",
|
"copyNPub": "Скопировать ключ",
|
||||||
"relaysTitle": "Relays",
|
|
||||||
"relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected."
|
"relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected."
|
||||||
},
|
},
|
||||||
"homePage": {
|
"homePage": {
|
||||||
@ -297,7 +299,9 @@
|
|||||||
"profileCard": {
|
"profileCard": {
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"contactAdded": "Profile followed",
|
"contactAdded": "Profile followed",
|
||||||
"contactRemoved": "Profile unfollowed"
|
"contactRemoved": "Profile unfollowed",
|
||||||
|
"userUnblocked": "Profile unblocked",
|
||||||
|
"userBlocked": "Profile unblocked"
|
||||||
},
|
},
|
||||||
"invoice": "Tip",
|
"invoice": "Tip",
|
||||||
"message": "Message",
|
"message": "Message",
|
||||||
@ -305,7 +309,8 @@
|
|||||||
"block": "Block",
|
"block": "Block",
|
||||||
"unblock": "Desbloquear",
|
"unblock": "Desbloquear",
|
||||||
"unfollow": "Following",
|
"unfollow": "Following",
|
||||||
"share": "Share"
|
"share": "Share",
|
||||||
|
"relaysTitle": "Relays"
|
||||||
},
|
},
|
||||||
"conversationsFeed": {
|
"conversationsFeed": {
|
||||||
"openMessage": "Start conversation",
|
"openMessage": "Start conversation",
|
||||||
|
@ -101,6 +101,8 @@
|
|||||||
"copied": "已复制私钥 \n\n 请妥善保管您的私钥",
|
"copied": "已复制私钥 \n\n 请妥善保管您的私钥",
|
||||||
"wrongWords": "助记词不匹配"
|
"wrongWords": "助记词不匹配"
|
||||||
},
|
},
|
||||||
|
"skip": "Skip",
|
||||||
|
"confirmTitle": "Type the words in the right order.",
|
||||||
"warningTitle": "注意",
|
"warningTitle": "注意",
|
||||||
"warningDescription": "请妥善保管您的私钥。如果遗失,您将无法登入或恢复您的账号。",
|
"warningDescription": "请妥善保管您的私钥。如果遗失,您将无法登入或恢复您的账号。",
|
||||||
"warningAction": "复制私钥",
|
"warningAction": "复制私钥",
|
||||||
@ -208,6 +210,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"relayCard": {
|
"relayCard": {
|
||||||
|
"pushDone": "Completed",
|
||||||
"moreInfo": "更多",
|
"moreInfo": "更多",
|
||||||
"lessInfo": "收起",
|
"lessInfo": "收起",
|
||||||
"globalFeed": "全局信息流",
|
"globalFeed": "全局信息流",
|
||||||
@ -280,7 +283,6 @@
|
|||||||
"isFollower": "follows you",
|
"isFollower": "follows you",
|
||||||
"unfollow": "关注中",
|
"unfollow": "关注中",
|
||||||
"copyNPub": "复制公钥",
|
"copyNPub": "复制公钥",
|
||||||
"relaysTitle": "Relays",
|
|
||||||
"relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected."
|
"relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected."
|
||||||
},
|
},
|
||||||
"homePage": {
|
"homePage": {
|
||||||
@ -300,7 +302,9 @@
|
|||||||
"notifications": {
|
"notifications": {
|
||||||
"contactAdded": "已关注",
|
"contactAdded": "已关注",
|
||||||
"contactRemoved": "已取消关注",
|
"contactRemoved": "已取消关注",
|
||||||
"npubCopied": "已复制公钥"
|
"npubCopied": "已复制公钥",
|
||||||
|
"userUnblocked": "Profile unblocked",
|
||||||
|
"userBlocked": "Profile unblocked"
|
||||||
},
|
},
|
||||||
"invoice": "赞赏",
|
"invoice": "赞赏",
|
||||||
"message": "私信",
|
"message": "私信",
|
||||||
@ -310,7 +314,8 @@
|
|||||||
"unblock": "取消屏蔽",
|
"unblock": "取消屏蔽",
|
||||||
"share": "分享",
|
"share": "分享",
|
||||||
"copyNip05": "复制 NIP-05",
|
"copyNip05": "复制 NIP-05",
|
||||||
"copyNPub": "复制公钥"
|
"copyNPub": "复制公钥",
|
||||||
|
"relaysTitle": "Relays"
|
||||||
},
|
},
|
||||||
"conversationsFeed": {
|
"conversationsFeed": {
|
||||||
"openMessage": "发送私信",
|
"openMessage": "发送私信",
|
||||||
|
@ -69,6 +69,8 @@ export const GlobalFeed: React.FC<GlobalFeedProps> = ({ navigation }) => {
|
|||||||
setRefreshing(true)
|
setRefreshing(true)
|
||||||
updateLastLoad()
|
updateLastLoad()
|
||||||
setNewNotesCount(0)
|
setNewNotesCount(0)
|
||||||
|
relayPool?.unsubscribe(['homepage-global-main', 'homepage-global-meta'])
|
||||||
|
subscribeNotes()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const subscribeNotes: (past?: boolean) => void = async (past) => {
|
const subscribeNotes: (past?: boolean) => void = async (past) => {
|
||||||
@ -189,7 +191,9 @@ export const GlobalFeed: React.FC<GlobalFeedProps> = ({ navigation }) => {
|
|||||||
refreshing={refreshing}
|
refreshing={refreshing}
|
||||||
ListEmptyComponent={ListEmptyComponent}
|
ListEmptyComponent={ListEmptyComponent}
|
||||||
horizontal={false}
|
horizontal={false}
|
||||||
ListFooterComponent={<ActivityIndicator animating={true} />}
|
ListFooterComponent={
|
||||||
|
notes.length > 0 ? <ActivityIndicator style={styles.loading} animating={true} /> : <></>
|
||||||
|
}
|
||||||
ref={flashListRef}
|
ref={flashListRef}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@ -198,6 +202,9 @@ export const GlobalFeed: React.FC<GlobalFeedProps> = ({ navigation }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
loading: {
|
||||||
|
paddingTop: 16,
|
||||||
|
},
|
||||||
list: {
|
list: {
|
||||||
height: '100%',
|
height: '100%',
|
||||||
},
|
},
|
||||||
|
@ -63,12 +63,16 @@ export const MyFeed: React.FC<MyFeedProps> = ({ navigation }) => {
|
|||||||
|
|
||||||
const onRefresh = useCallback(() => {
|
const onRefresh = useCallback(() => {
|
||||||
setRefreshing(true)
|
setRefreshing(true)
|
||||||
|
relayPool?.unsubscribe([
|
||||||
|
'homepage-contacts-main',
|
||||||
|
'homepage-contacts-meta',
|
||||||
|
'homepage-contacts-replies',
|
||||||
|
])
|
||||||
subscribeNotes()
|
subscribeNotes()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const subscribeNotes: (past?: boolean) => void = async (past) => {
|
const subscribeNotes: (past?: boolean) => void = async (past) => {
|
||||||
if (!database || !publicKey) return
|
if (!database || !publicKey) return
|
||||||
|
|
||||||
const users: User[] = await getUsers(database, { contacts: true, order: 'created_at DESC' })
|
const users: User[] = await getUsers(database, { contacts: true, order: 'created_at DESC' })
|
||||||
const authors: string[] = [...users.map((user) => user.id), publicKey]
|
const authors: string[] = [...users.map((user) => user.id), publicKey]
|
||||||
|
|
||||||
@ -89,7 +93,6 @@ export const MyFeed: React.FC<MyFeedProps> = ({ navigation }) => {
|
|||||||
|
|
||||||
const loadNotes: () => void = async () => {
|
const loadNotes: () => void = async () => {
|
||||||
if (database && publicKey) {
|
if (database && publicKey) {
|
||||||
relayPool?.unsubscribe(['homepage-reactions', 'homepage-replies', 'homepage-main'])
|
|
||||||
getMainNotes(database, publicKey, pageSize, true).then(async (notes) => {
|
getMainNotes(database, publicKey, pageSize, true).then(async (notes) => {
|
||||||
setNotes(notes)
|
setNotes(notes)
|
||||||
if (notes.length > 0) {
|
if (notes.length > 0) {
|
||||||
@ -175,7 +178,9 @@ export const MyFeed: React.FC<MyFeedProps> = ({ navigation }) => {
|
|||||||
refreshing={refreshing}
|
refreshing={refreshing}
|
||||||
ListEmptyComponent={ListEmptyComponent}
|
ListEmptyComponent={ListEmptyComponent}
|
||||||
horizontal={false}
|
horizontal={false}
|
||||||
ListFooterComponent={<ActivityIndicator animating={true} />}
|
ListFooterComponent={
|
||||||
|
notes.length > 0 ? <ActivityIndicator style={styles.loading} animating={true} /> : <></>
|
||||||
|
}
|
||||||
ref={flashListRef}
|
ref={flashListRef}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@ -183,6 +188,9 @@ export const MyFeed: React.FC<MyFeedProps> = ({ navigation }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
loading: {
|
||||||
|
paddingTop: 16,
|
||||||
|
},
|
||||||
list: {
|
list: {
|
||||||
height: '100%',
|
height: '100%',
|
||||||
},
|
},
|
||||||
|
@ -186,7 +186,9 @@ export const NotificationsFeed: React.FC = () => {
|
|||||||
refreshing={refreshing}
|
refreshing={refreshing}
|
||||||
ListEmptyComponent={ListEmptyComponent}
|
ListEmptyComponent={ListEmptyComponent}
|
||||||
horizontal={false}
|
horizontal={false}
|
||||||
ListFooterComponent={<ActivityIndicator animating={true} />}
|
ListFooterComponent={
|
||||||
|
notes.length > 0 ? <ActivityIndicator style={styles.loading} animating={true} /> : <></>
|
||||||
|
}
|
||||||
ref={flashListRef}
|
ref={flashListRef}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@ -194,6 +196,9 @@ export const NotificationsFeed: React.FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
loading: {
|
||||||
|
paddingTop: 16,
|
||||||
|
},
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
paddingLeft: 16,
|
paddingLeft: 16,
|
||||||
|
@ -71,6 +71,11 @@ export const ProfileCreatePage: React.FC<ProfileCreatePageProps> = ({ navigation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onPressSkip: () => void = () => {
|
||||||
|
setPrivateKey(key)
|
||||||
|
setUserState('ready')
|
||||||
|
}
|
||||||
|
|
||||||
const onChangeTextConfirm: (value: string, position: number) => void = (value, position) => {
|
const onChangeTextConfirm: (value: string, position: number) => void = (value, position) => {
|
||||||
setConfirmWords((prev) => {
|
setConfirmWords((prev) => {
|
||||||
prev[position] = value
|
prev[position] = value
|
||||||
@ -208,6 +213,13 @@ export const ProfileCreatePage: React.FC<ProfileCreatePageProps> = ({ navigation
|
|||||||
{` ${step + 1}/3`}
|
{` ${step + 1}/3`}
|
||||||
</Button>
|
</Button>
|
||||||
</View>
|
</View>
|
||||||
|
{step > 1 && (
|
||||||
|
<View style={styles.bottomButton}>
|
||||||
|
<Button mode='outlined' compact onPress={onPressSkip}>
|
||||||
|
{t('profileCreatePage.skip')}
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
{showNotification && (
|
{showNotification && (
|
||||||
@ -289,6 +301,9 @@ const styles = StyleSheet.create({
|
|||||||
bold: {
|
bold: {
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
},
|
},
|
||||||
|
bottomButton: {
|
||||||
|
marginTop: 16,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export default ProfileCreatePage
|
export default ProfileCreatePage
|
||||||
|
@ -179,7 +179,13 @@ export const ProfilePage: React.FC<ProfilePageProps> = ({ route }) => {
|
|||||||
onScroll={onScroll}
|
onScroll={onScroll}
|
||||||
refreshing={refreshing}
|
refreshing={refreshing}
|
||||||
horizontal={false}
|
horizontal={false}
|
||||||
ListFooterComponent={<ActivityIndicator animating={true} />}
|
ListFooterComponent={
|
||||||
|
notes && notes.length > 0 ? (
|
||||||
|
<ActivityIndicator style={styles.loading} animating={true} />
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
@ -199,6 +205,9 @@ export const ProfilePage: React.FC<ProfilePageProps> = ({ route }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
loading: {
|
||||||
|
paddingTop: 16,
|
||||||
|
},
|
||||||
container: {
|
container: {
|
||||||
padding: 16,
|
padding: 16,
|
||||||
},
|
},
|
||||||
|
@ -61,6 +61,11 @@ export const ReactionsFeed: React.FC<ReactionsFeedProps> = ({ navigation }) => {
|
|||||||
|
|
||||||
const onRefresh = useCallback(() => {
|
const onRefresh = useCallback(() => {
|
||||||
setRefreshing(true)
|
setRefreshing(true)
|
||||||
|
relayPool?.unsubscribe([
|
||||||
|
'homepage-contacts-main',
|
||||||
|
'homepage-contacts-meta',
|
||||||
|
'homepage-contacts-replies',
|
||||||
|
])
|
||||||
subscribeNotes()
|
subscribeNotes()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@ -84,7 +89,6 @@ export const ReactionsFeed: React.FC<ReactionsFeedProps> = ({ navigation }) => {
|
|||||||
|
|
||||||
const loadNotes: () => void = async () => {
|
const loadNotes: () => void = async () => {
|
||||||
if (database && publicKey) {
|
if (database && publicKey) {
|
||||||
relayPool?.unsubscribe(['homepage-reactions', 'homepage-replies', 'homepage-main'])
|
|
||||||
getReactedNotes(database, publicKey, pageSize).then(async (notes) => {
|
getReactedNotes(database, publicKey, pageSize).then(async (notes) => {
|
||||||
setNotes(notes)
|
setNotes(notes)
|
||||||
if (notes.length > 0) {
|
if (notes.length > 0) {
|
||||||
@ -175,7 +179,9 @@ export const ReactionsFeed: React.FC<ReactionsFeedProps> = ({ navigation }) => {
|
|||||||
refreshing={refreshing}
|
refreshing={refreshing}
|
||||||
ListEmptyComponent={ListEmptyComponent}
|
ListEmptyComponent={ListEmptyComponent}
|
||||||
horizontal={false}
|
horizontal={false}
|
||||||
ListFooterComponent={<ActivityIndicator animating={true} />}
|
ListFooterComponent={
|
||||||
|
notes.length > 0 ? <ActivityIndicator style={styles.loading} animating={true} /> : <></>
|
||||||
|
}
|
||||||
ref={flashListRef}
|
ref={flashListRef}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@ -183,6 +189,9 @@ export const ReactionsFeed: React.FC<ReactionsFeedProps> = ({ navigation }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
loading: {
|
||||||
|
paddingTop: 16,
|
||||||
|
},
|
||||||
list: {
|
list: {
|
||||||
height: '100%',
|
height: '100%',
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import React, { useContext, useState } from 'react'
|
import React, { useContext, useState } from 'react'
|
||||||
import { FlatList, ListRenderItem, ScrollView, StyleSheet, View } from 'react-native'
|
import { FlatList, ListRenderItem, ScrollView, StyleSheet, View } from 'react-native'
|
||||||
import Clipboard from '@react-native-clipboard/clipboard'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
||||||
import { getRelays, Relay } from '../../Functions/DatabaseFunctions/Relays'
|
import { getRelays, Relay } from '../../Functions/DatabaseFunctions/Relays'
|
||||||
@ -40,15 +39,14 @@ export const defaultRelays = [
|
|||||||
|
|
||||||
export const RelaysPage: React.FC = () => {
|
export const RelaysPage: React.FC = () => {
|
||||||
const defaultRelayInput = React.useMemo(() => 'wss://', [])
|
const defaultRelayInput = React.useMemo(() => 'wss://', [])
|
||||||
const { updateRelayItem, addRelayItem, removeRelayItem, relayPool } = useContext(RelayPoolContext)
|
const { updateRelayItem, addRelayItem, relayPool, setDisplayrelayDrawer } =
|
||||||
|
useContext(RelayPoolContext)
|
||||||
const { database } = useContext(AppContext)
|
const { database } = useContext(AppContext)
|
||||||
const { t } = useTranslation('common')
|
const { t } = useTranslation('common')
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const bottomSheetAddRef = React.useRef<RBSheet>(null)
|
const bottomSheetAddRef = React.useRef<RBSheet>(null)
|
||||||
const bottomSheetEditRef = React.useRef<RBSheet>(null)
|
|
||||||
const bottomSheetResilenseRef = React.useRef<RBSheet>(null)
|
const bottomSheetResilenseRef = React.useRef<RBSheet>(null)
|
||||||
const [relays, setRelays] = React.useState<Relay[]>([])
|
const [relays, setRelays] = React.useState<Relay[]>([])
|
||||||
const [selectedRelay, setSelectedRelay] = useState<Relay>()
|
|
||||||
const [addRelayInput, setAddRelayInput] = useState<string>(defaultRelayInput)
|
const [addRelayInput, setAddRelayInput] = useState<string>(defaultRelayInput)
|
||||||
const [showNotification, setShowNotification] = useState<string>()
|
const [showNotification, setShowNotification] = useState<string>()
|
||||||
|
|
||||||
@ -66,6 +64,7 @@ export const RelaysPage: React.FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const addRelay: (url: string) => void = (url) => {
|
const addRelay: (url: string) => void = (url) => {
|
||||||
|
if (!relayList.find((relay) => relay.url === url)) {
|
||||||
addRelayItem({
|
addRelayItem({
|
||||||
url,
|
url,
|
||||||
active: 1,
|
active: 1,
|
||||||
@ -75,16 +74,17 @@ export const RelaysPage: React.FC = () => {
|
|||||||
setShowNotification('add')
|
setShowNotification('add')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const removeRelay: (url: string) => void = (url) => {
|
|
||||||
removeRelayItem({
|
|
||||||
url,
|
|
||||||
}).then(() => {
|
|
||||||
updateRelays()
|
|
||||||
setShowNotification('remove')
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// const removeRelay: (url: string) => void = (url) => {
|
||||||
|
// removeRelayItem({
|
||||||
|
// url,
|
||||||
|
// }).then(() => {
|
||||||
|
// updateRelays()
|
||||||
|
// setShowNotification('remove')
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
const activeRelay: (relay: Relay) => void = (relay) => {
|
const activeRelay: (relay: Relay) => void = (relay) => {
|
||||||
relay.active = 1
|
relay.active = 1
|
||||||
updateRelayItem(relay).then(() => {
|
updateRelayItem(relay).then(() => {
|
||||||
@ -184,8 +184,7 @@ export const RelaysPage: React.FC = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
setSelectedRelay(item)
|
setDisplayrelayDrawer(item.url)
|
||||||
bottomSheetEditRef.current?.open()
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
@ -377,35 +376,6 @@ export const RelaysPage: React.FC = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</View>
|
</View>
|
||||||
</RBSheet>
|
</RBSheet>
|
||||||
<RBSheet ref={bottomSheetEditRef} closeOnDragDown={true} customStyles={rbSheetCustomStyles}>
|
|
||||||
<View>
|
|
||||||
<View style={styles.relayActions}>
|
|
||||||
<View style={styles.actionButton}>
|
|
||||||
<IconButton
|
|
||||||
icon='trash-can-outline'
|
|
||||||
size={28}
|
|
||||||
onPress={() => {
|
|
||||||
if (selectedRelay) removeRelay(selectedRelay.url)
|
|
||||||
bottomSheetEditRef.current?.close()
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Text>{t('relaysPage.removeRelay')}</Text>
|
|
||||||
</View>
|
|
||||||
<View style={styles.actionButton}>
|
|
||||||
<IconButton
|
|
||||||
icon='content-copy'
|
|
||||||
size={28}
|
|
||||||
onPress={() => {
|
|
||||||
if (selectedRelay) Clipboard.setString(selectedRelay.url)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Text>{t('relaysPage.copyRelay')}</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
<Divider style={styles.divider} />
|
|
||||||
<Text variant='titleLarge'>{selectedRelay?.url}</Text>
|
|
||||||
</View>
|
|
||||||
</RBSheet>
|
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,11 @@ export const RepostsFeed: React.FC<RepostsFeedProps> = ({ navigation }) => {
|
|||||||
|
|
||||||
const onRefresh = useCallback(() => {
|
const onRefresh = useCallback(() => {
|
||||||
setRefreshing(true)
|
setRefreshing(true)
|
||||||
|
relayPool?.unsubscribe([
|
||||||
|
'homepage-contacts-main',
|
||||||
|
'homepage-contacts-meta',
|
||||||
|
'homepage-contacts-replies',
|
||||||
|
])
|
||||||
subscribeNotes()
|
subscribeNotes()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@ -84,7 +89,6 @@ export const RepostsFeed: React.FC<RepostsFeedProps> = ({ navigation }) => {
|
|||||||
|
|
||||||
const loadNotes: () => void = async () => {
|
const loadNotes: () => void = async () => {
|
||||||
if (database && publicKey) {
|
if (database && publicKey) {
|
||||||
relayPool?.unsubscribe(['homepage-reactions', 'homepage-replies', 'homepage-main'])
|
|
||||||
getRepostedNotes(database, publicKey, pageSize).then(async (notes) => {
|
getRepostedNotes(database, publicKey, pageSize).then(async (notes) => {
|
||||||
setNotes(notes)
|
setNotes(notes)
|
||||||
if (notes.length > 0) {
|
if (notes.length > 0) {
|
||||||
@ -167,7 +171,9 @@ export const RepostsFeed: React.FC<RepostsFeedProps> = ({ navigation }) => {
|
|||||||
refreshing={refreshing}
|
refreshing={refreshing}
|
||||||
ListEmptyComponent={ListEmptyComponent}
|
ListEmptyComponent={ListEmptyComponent}
|
||||||
horizontal={false}
|
horizontal={false}
|
||||||
ListFooterComponent={<ActivityIndicator animating={true} />}
|
ListFooterComponent={
|
||||||
|
notes.length > 0 ? <ActivityIndicator style={styles.loading} animating={true} /> : <></>
|
||||||
|
}
|
||||||
ref={flashListRef}
|
ref={flashListRef}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@ -175,6 +181,9 @@ export const RepostsFeed: React.FC<RepostsFeedProps> = ({ navigation }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
loading: {
|
||||||
|
paddingTop: 16,
|
||||||
|
},
|
||||||
list: {
|
list: {
|
||||||
height: '100%',
|
height: '100%',
|
||||||
},
|
},
|
||||||
|
@ -260,7 +260,9 @@ export const SendPage: React.FC<SendPageProps> = ({ route }) => {
|
|||||||
<Button
|
<Button
|
||||||
mode='contained'
|
mode='contained'
|
||||||
onPress={onPressSend}
|
onPress={onPressSend}
|
||||||
disabled={route.params?.type !== 'repost' && (!content || content === '')}
|
disabled={
|
||||||
|
isSending || (route.params?.type !== 'repost' && (!content || content === ''))
|
||||||
|
}
|
||||||
loading={isSending || uploadingFile}
|
loading={isSending || uploadingFile}
|
||||||
>
|
>
|
||||||
{t('sendPage.send')}
|
{t('sendPage.send')}
|
||||||
|
@ -2,7 +2,8 @@ import { NativeModules } from 'react-native'
|
|||||||
const { RelayPoolModule } = NativeModules
|
const { RelayPoolModule } = NativeModules
|
||||||
|
|
||||||
interface RelayPoolInterface {
|
interface RelayPoolInterface {
|
||||||
send: (message: string, globalFeed: boolean) => void
|
sendAll: (message: string, globalFeed: boolean) => void
|
||||||
|
sendRelay: (message: string, relayUrl: string) => void
|
||||||
connect: (pubKey: string, callback: (eventId: string) => void) => void
|
connect: (pubKey: string, callback: (eventId: string) => void) => void
|
||||||
add: (url: string, callback: () => void) => void
|
add: (url: string, callback: () => void) => void
|
||||||
remove: (url: string, callback: () => void) => void
|
remove: (url: string, callback: () => void) => void
|
||||||
|
@ -11,6 +11,19 @@ export interface Event {
|
|||||||
tags: string[][]
|
tags: string[][]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const evetDatabaseToEntity: (object: any) => Event = (object = {}) => {
|
||||||
|
const event: Event = {
|
||||||
|
created_at: object.created_at,
|
||||||
|
content: object.content,
|
||||||
|
id: object.id,
|
||||||
|
kind: object.kind,
|
||||||
|
pubkey: object.pubkey,
|
||||||
|
sig: object.sig,
|
||||||
|
tags: object.tags ? JSON.parse(object.tags) : [],
|
||||||
|
}
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
|
||||||
export const serializeEvent: (event: Event) => string = (event) => {
|
export const serializeEvent: (event: Event) => string = (event) => {
|
||||||
return JSON.stringify([0, event.pubkey, event.created_at, event.kind, event.tags, event.content])
|
return JSON.stringify([0, event.pubkey, event.created_at, event.kind, event.tags, event.content])
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ export interface ResilientAssignation {
|
|||||||
resilientRelays: Record<string, string[]>
|
resilientRelays: Record<string, string[]>
|
||||||
smallRelays: Record<string, string[]>
|
smallRelays: Record<string, string[]>
|
||||||
centralizedRelays: Record<string, string[]>
|
centralizedRelays: Record<string, string[]>
|
||||||
|
fallback: Record<string, string[]>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fallbackRelays = [
|
export const fallbackRelays = [
|
||||||
@ -62,12 +63,20 @@ class RelayPool {
|
|||||||
private subscriptions: Record<string, string[]>
|
private subscriptions: Record<string, string[]>
|
||||||
public resilientAssignation: ResilientAssignation
|
public resilientAssignation: ResilientAssignation
|
||||||
|
|
||||||
private readonly send: (message: object, globalFeed?: boolean) => void = async (
|
private readonly sendAll: (message: object, globalFeed?: boolean) => void = async (
|
||||||
message,
|
message,
|
||||||
globalFeed,
|
globalFeed,
|
||||||
) => {
|
) => {
|
||||||
const tosend = JSON.stringify(message)
|
const tosend = JSON.stringify(message)
|
||||||
RelayPoolModule.send(tosend, globalFeed ?? false)
|
RelayPoolModule.sendAll(tosend, globalFeed ?? false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly sendRelay: (message: object, relayUrl: string) => void = async (
|
||||||
|
message,
|
||||||
|
relayUrl,
|
||||||
|
) => {
|
||||||
|
const tosend = JSON.stringify(message)
|
||||||
|
RelayPoolModule.sendRelay(tosend, relayUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly connect: (publicKey: string, onEventId: (eventId: string) => void) => void =
|
public readonly connect: (publicKey: string, onEventId: (eventId: string) => void) => void =
|
||||||
@ -181,13 +190,23 @@ class RelayPool {
|
|||||||
RelayPoolModule.update(relayUrl, active, globalfeed, callback)
|
RelayPoolModule.update(relayUrl, active, globalfeed, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly sendEvent: (event: Event) => Promise<Event | null> = async (event) => {
|
public readonly sendEvent: (event: Event, relayUrl?: string) => Promise<Event | null> = async (
|
||||||
|
event,
|
||||||
|
relayUrl,
|
||||||
|
) => {
|
||||||
if (this.privateKey) {
|
if (this.privateKey) {
|
||||||
const signedEvent: Event = await signEvent(event, this.privateKey)
|
let signedEvent: Event = event
|
||||||
|
|
||||||
|
if (!event.sig) {
|
||||||
|
signedEvent = await signEvent(event, this.privateKey)
|
||||||
|
}
|
||||||
|
|
||||||
if (validateEvent(signedEvent)) {
|
if (validateEvent(signedEvent)) {
|
||||||
this.send(['EVENT', event])
|
if (relayUrl) {
|
||||||
|
this.sendRelay(['EVENT', event], relayUrl)
|
||||||
|
} else {
|
||||||
|
this.sendAll(['EVENT', event])
|
||||||
|
}
|
||||||
return signedEvent
|
return signedEvent
|
||||||
} else {
|
} else {
|
||||||
console.log('Not valid event', event)
|
console.log('Not valid event', event)
|
||||||
@ -206,7 +225,7 @@ class RelayPool {
|
|||||||
if (this.subscriptions[subId]?.includes(id)) {
|
if (this.subscriptions[subId]?.includes(id)) {
|
||||||
console.log('Subscription already done!', subId)
|
console.log('Subscription already done!', subId)
|
||||||
} else {
|
} else {
|
||||||
this.send([...['REQ', subId], ...(filters ?? [])], subId.includes('-global-'))
|
this.sendAll([...['REQ', subId], ...(filters ?? [])], subId.includes('-global-'))
|
||||||
const newSubscriptions = [...(this.subscriptions[subId] ?? []), id]
|
const newSubscriptions = [...(this.subscriptions[subId] ?? []), id]
|
||||||
this.subscriptions[subId] = newSubscriptions
|
this.subscriptions[subId] = newSubscriptions
|
||||||
}
|
}
|
||||||
@ -214,7 +233,7 @@ class RelayPool {
|
|||||||
|
|
||||||
public readonly unsubscribe: (subIds: string[]) => void = async (subIds) => {
|
public readonly unsubscribe: (subIds: string[]) => void = async (subIds) => {
|
||||||
subIds.forEach((subId: string) => {
|
subIds.forEach((subId: string) => {
|
||||||
this.send(['CLOSE', subId])
|
this.sendAll(['CLOSE', subId])
|
||||||
delete this.subscriptions[subId]
|
delete this.subscriptions[subId]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user