From a125001e63c50b4ab068b6e0ddece6fd05341cdc Mon Sep 17 00:00:00 2001 From: KoalaSat Date: Thu, 9 Feb 2023 23:10:50 +0100 Subject: [PATCH] Push to relay --- .../main/java/com/nostros/classes/Event.java | 2 +- .../com/nostros/modules/RelayPoolModule.java | 18 +++ .../placeholders/placeholder_bluebird.png | Bin 0 -> 7214 bytes frontend/Components/ProfileActions/index.tsx | 29 ++-- frontend/Components/RelayCard/index.tsx | 134 +++++++++++++++++- frontend/Components/TextContent/index.tsx | 56 ++++---- .../DatabaseFunctions/DirectMessages/index.ts | 17 ++- .../DatabaseFunctions/Notes/index.ts | 17 ++- .../DatabaseFunctions/Reactions/index.ts | 17 ++- frontend/Functions/NativeFunctions/index.ts | 4 +- frontend/Locales/de.json | 13 +- frontend/Locales/en.json | 23 ++- frontend/Locales/es.json | 13 +- frontend/Locales/fr.json | 15 +- frontend/Locales/ru.json | 15 +- frontend/Locales/zhCn.json | 13 +- frontend/Pages/GlobalFeed/index.tsx | 9 +- frontend/Pages/MyFeed/index.tsx | 14 +- frontend/Pages/NotificationsFeed/index.tsx | 7 +- frontend/Pages/ProfileCreatePage/index.tsx | 15 ++ frontend/Pages/ProfilePage/index.tsx | 11 +- frontend/Pages/ReactionsFeed/index.tsx | 13 +- frontend/Pages/RelaysPage/index.tsx | 72 +++------- frontend/Pages/RepostsFeed/index.tsx | 13 +- frontend/Pages/SendPage/index.tsx | 4 +- frontend/lib/Native/WebsocketModule/index.ts | 3 +- frontend/lib/nostr/Events/index.ts | 13 ++ frontend/lib/nostr/RelayPool/intex.ts | 35 +++-- 28 files changed, 452 insertions(+), 143 deletions(-) create mode 100644 assets/images/placeholders/placeholder_bluebird.png diff --git a/android/app/src/main/java/com/nostros/classes/Event.java b/android/app/src/main/java/com/nostros/classes/Event.java index 27003cd..f8c6b94 100644 --- a/android/app/src/main/java/com/nostros/classes/Event.java +++ b/android/app/src/main/java/com/nostros/classes/Event.java @@ -188,7 +188,7 @@ public class Event { protected void saveNote(SQLiteDatabase database, String userPubKey, String relayUrl) { ContentValues values = new ContentValues(); values.put("id", id); - values.put("content", content.replace("'", "''")); + values.put("content", content); values.put("created_at", created_at); values.put("kind", kind); values.put("pubkey", pubkey); diff --git a/android/app/src/main/java/com/nostros/modules/RelayPoolModule.java b/android/app/src/main/java/com/nostros/modules/RelayPoolModule.java index 0665f5f..df8d4ac 100644 --- a/android/app/src/main/java/com/nostros/modules/RelayPoolModule.java +++ b/android/app/src/main/java/com/nostros/modules/RelayPoolModule.java @@ -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); + } + } + } } diff --git a/assets/images/placeholders/placeholder_bluebird.png b/assets/images/placeholders/placeholder_bluebird.png new file mode 100644 index 0000000000000000000000000000000000000000..6a312f5af0d275b28ae2c474ae089949b15e62c8 GIT binary patch literal 7214 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 literal 0 HcmV?d00001 diff --git a/frontend/Components/ProfileActions/index.tsx b/frontend/Components/ProfileActions/index.tsx index 5fe23be..8dfe6db 100644 --- a/frontend/Components/ProfileActions/index.tsx +++ b/frontend/Components/ProfileActions/index.tsx @@ -6,6 +6,7 @@ import { AppContext } from '../../Contexts/AppContext' import { RelayPoolContext } from '../../Contexts/RelayPoolContext' import { UserContext } from '../../Contexts/UserContext' import { + addUser, getUser, updateUserBlock, updateUserContact, @@ -32,6 +33,7 @@ export const ProfileActions: React.FC = ({ user, setUser }) const { publicKey } = React.useContext(UserContext) const { relayPool, updateRelayItem } = React.useContext(RelayPoolContext) const [isContact, setIsContact] = React.useState() + const [isBlocked, setIsBlocked] = React.useState() const [showNotification, setShowNotification] = React.useState() const [showNotificationRelay, setShowNotificationRelay] = React.useState() const bottomSheetRelaysRef = React.useRef(null) @@ -59,6 +61,8 @@ export const ProfileActions: React.FC = ({ user, setUser }) getUser(user.id, database).then((result) => { if (result) { setUser(result) + setIsContact(result.contact) + setIsBlocked(result.blocked !== undefined && result.blocked > 0) } else if (user.id === publicKey) { setUser({ id: publicKey, @@ -69,9 +73,12 @@ export const ProfileActions: React.FC = ({ user, setUser }) } const onChangeBlockUser: () => void = () => { - if (database && user?.blocked !== undefined) { - updateUserBlock(user.id, database, !user?.blocked).then(() => { - loadUser() + if (database) { + addUser(user.id, database).then(() => { + updateUserBlock(user.id, database, !isBlocked).then(() => { + loadUser() + setShowNotificationRelay(isBlocked ? 'userUnblocked' : 'userBlocked') + }) }) } } @@ -160,7 +167,7 @@ export const ProfileActions: React.FC = ({ user, setUser }) }} disabled={user.id === publicKey} /> - {isContact ? t('profilePage.unfollow') : t('profilePage.follow')} + {isContact ? t('profileCard.unfollow') : t('profileCard.follow')} = ({ user, setUser }) }) }} /> - {t('profilePage.message')} + {t('profileCard.message')} = ({ user, setUser }) disabled={!user?.lnurl} iconColor='#F5D112' /> - {t('profilePage.invoice')} + {t('profileCard.invoice')} @@ -211,14 +218,14 @@ export const ProfileActions: React.FC = ({ user, setUser }) size={28} onPress={() => bottomSheetRelaysRef.current?.open()} /> - {t('profilePage.relaysTitle')} + {t('profileCard.relaysTitle')} - {t('profilePage.relaysTitle')} + {t('profileCard.relaysTitle')} - {t('profilePage.relaysDescription', { username: username(user) })} + {t('profileCard.relaysDescription', { username: username(user) })} = ({ user, setUser }) onIconPress={() => setShowNotificationRelay(undefined)} onDismiss={() => setShowNotificationRelay(undefined)} > - {t(`profilePage.${showNotificationRelay}`)} + {t(`profileCard.notifications.${showNotificationRelay}`)} )} @@ -258,7 +265,7 @@ export const ProfileActions: React.FC = ({ user, setUser }) onIconPress={() => setShowNotification(undefined)} onDismiss={() => setShowNotification(undefined)} > - {t(`profilePage.${showNotification}`)} + {t(`profileCard.notifications.${showNotification}`)} )} diff --git a/frontend/Components/RelayCard/index.tsx b/frontend/Components/RelayCard/index.tsx index df6d86c..d40faff 100644 --- a/frontend/Components/RelayCard/index.tsx +++ b/frontend/Components/RelayCard/index.tsx @@ -1,7 +1,16 @@ import { t } from 'i18next' import * as React from 'react' 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 { RelayPoolContext } from '../../Contexts/RelayPoolContext' import RBSheet from 'react-native-raw-bottom-sheet' @@ -12,6 +21,10 @@ import axios from 'axios' import { ScrollView } from 'react-native-gesture-handler' import Clipboard from '@react-native-clipboard/clipboard' 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 { url?: string @@ -19,18 +32,49 @@ interface RelayCardProps { } export const RelayCard: React.FC = ({ 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 [relay, setRelay] = React.useState() const [uri, setUri] = React.useState() const [relayInfo, setRelayInfo] = React.useState() const [showNotification, setShowNotification] = React.useState() + const [checkedPush, setCheckedPush] = React.useState<'checked' | 'unchecked' | 'indeterminate'>( + 'unchecked', + ) const [moreInfo, setMoreInfo] = React.useState(false) + const [pushDone, setPushDone] = React.useState(false) + const [pushUserHistoric, setPushUserHistoric] = React.useState(false) + const bottomSheetPushRelayRef = React.useRef(null) React.useEffect(() => { 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(() => { if (relay) { setUri(relay.url) @@ -110,6 +154,21 @@ export const RelayCard: React.FC = ({ 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 ? ( @@ -215,6 +274,14 @@ export const RelayCard: React.FC = ({ url, bottomSheetRef }) => + + bottomSheetPushRelayRef.current?.open()} + /> + {t('relayCard.pushRelay')} + = ({ url, bottomSheetRef }) => {t(`relayCard.notifications.${showNotification}`)} )} + {}} + > + {t('relayCard.pushHistoricTitle')} + {t('relayCard.pushHistoricDescription')} + + + {t('relayCard.pushHistoricAlertTitle')} + + {t('relayCard.pushHistoricAlert')} + + + {t('relayCard.pushConsent')} + setCheckedPush(checkedPush === 'checked' ? 'unchecked' : 'checked')} + /> + + + + ) : ( <> @@ -245,6 +356,12 @@ export const RelayCard: React.FC = ({ url, bottomSheetRef }) => } const styles = StyleSheet.create({ + row: { + alignItems: 'center', + flexDirection: 'row', + height: 56, + justifyContent: 'space-between', + }, container: { padding: 16, }, @@ -287,6 +404,19 @@ const styles = StyleSheet.create({ marginBottom: 4, width: '33%', }, + buttonSpacer: { + marginTop: 16, + marginBottom: 16, + }, + warning: { + borderRadius: 4, + padding: 16, + marginTop: 16, + marginBottom: 16, + }, + warningTitle: { + marginBottom: 8, + }, }) export default RelayCard diff --git a/frontend/Components/TextContent/index.tsx b/frontend/Components/TextContent/index.tsx index 73551ba..d8537f2 100644 --- a/frontend/Components/TextContent/index.tsx +++ b/frontend/Components/TextContent/index.tsx @@ -48,6 +48,7 @@ export const TextContent: React.FC = ({ const DEFAULT_COVER = '../../../assets/images/placeholders/placeholder_url.png' const MEDIA_COVER = '../../../assets/images/placeholders/placeholder_media.png' const IMAGE_COVER = '../../../assets/images/placeholders/placeholder_image.png' + const BLUEBIRD_COVER = '../../../assets/images/placeholders/placeholder_bluebird.png' useEffect(() => { if (!linkPreview && url) { @@ -162,11 +163,9 @@ export const TextContent: React.FC = ({ const getDefaultCover: () => number = () => { if (!linkPreview) return require(DEFAULT_COVER) + if (linkType === 'blueBird') return require(BLUEBIRD_COVER) if (linkType === 'audio') 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) } @@ -197,31 +196,37 @@ export const TextContent: React.FC = ({ {url && ( handleUrlPress(url)}> - - - - {/* {linkPreview?.title ?? linkPreview?.url ?? url} */} - {url} - - {/* {linkPreview?.description && ( + {linkType === 'image' ? ( + + ) : ( + + )} + {linkType !== 'image' && ( + + + {/* {linkPreview?.title ?? linkPreview?.url ?? url} */} + {url} + + {/* {linkPreview?.description && ( {linkPreview.description} )} */} - + + )} )} @@ -274,8 +279,7 @@ const styles = StyleSheet.create({ cardCover: { flex: 1, height: 180, - borderTopLeftRadius: 16, - borderTopRightRadius: 16, + borderRadius: 16, }, url: { textDecorationLine: 'underline', diff --git a/frontend/Functions/DatabaseFunctions/DirectMessages/index.ts b/frontend/Functions/DatabaseFunctions/DirectMessages/index.ts index b5177c6..8a0d984 100644 --- a/frontend/Functions/DatabaseFunctions/DirectMessages/index.ts +++ b/frontend/Functions/DatabaseFunctions/DirectMessages/index.ts @@ -1,6 +1,6 @@ import { QueryResult, QuickSQLiteConnection } from 'react-native-quick-sqlite' import { getItems } from '..' -import { Event } from '../../../lib/nostr/Events' +import { Event, evetDatabaseToEntity } from '../../../lib/nostr/Events' export interface DirectMessage extends Event { conversation_id: string @@ -13,6 +13,21 @@ const databaseToEntity: (object: any) => DirectMessage = (object = {}) => { return object as DirectMessage } +export const getRawUserConversation: ( + db: QuickSQLiteConnection, + pubKey: string, +) => Promise = 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: ( conversationId: string, db: QuickSQLiteConnection, diff --git a/frontend/Functions/DatabaseFunctions/Notes/index.ts b/frontend/Functions/DatabaseFunctions/Notes/index.ts index aa7199a..c51b5a7 100644 --- a/frontend/Functions/DatabaseFunctions/Notes/index.ts +++ b/frontend/Functions/DatabaseFunctions/Notes/index.ts @@ -1,6 +1,6 @@ import { QuickSQLiteConnection } from 'react-native-quick-sqlite' import { getItems } from '..' -import { Event } from '../../../lib/nostr/Events' +import { Event, evetDatabaseToEntity } from '../../../lib/nostr/Events' export interface Note extends Event { name: string @@ -271,6 +271,21 @@ export const getLastReply: ( return reaction } +export const getRawUserNotes: ( + db: QuickSQLiteConnection, + pubKey: string, +) => Promise = 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: ( db: QuickSQLiteConnection, options: { diff --git a/frontend/Functions/DatabaseFunctions/Reactions/index.ts b/frontend/Functions/DatabaseFunctions/Reactions/index.ts index bba502a..f483137 100644 --- a/frontend/Functions/DatabaseFunctions/Reactions/index.ts +++ b/frontend/Functions/DatabaseFunctions/Reactions/index.ts @@ -1,6 +1,6 @@ import { QuickSQLiteConnection } from 'react-native-quick-sqlite' import { getItems } from '..' -import { Event } from '../../../lib/nostr/Events' +import { Event, evetDatabaseToEntity } from '../../../lib/nostr/Events' export interface Reaction extends Event { positive: boolean @@ -12,6 +12,21 @@ const databaseToEntity: (object: object) => Reaction = (object) => { return object as Reaction } +export const getRawUserReactions: ( + db: QuickSQLiteConnection, + pubKey: string, +) => Promise = 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: ( db: QuickSQLiteConnection, filters: { diff --git a/frontend/Functions/NativeFunctions/index.ts b/frontend/Functions/NativeFunctions/index.ts index 0bab2f2..f3c084b 100644 --- a/frontend/Functions/NativeFunctions/index.ts +++ b/frontend/Functions/NativeFunctions/index.ts @@ -36,7 +36,7 @@ export const relayToColor: (string: string) => string = (string) => { for (let i = 0; i < string.length; i++) { 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 = (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) => { if (url) { - const serviceRegexp = /^(https?:\/\/(?:twitter.com).*)$/ + const serviceRegexp = /^(https?:\/\/(?:twitter.com|t.co).*)$/ return serviceRegexp.test(url) } else { return false diff --git a/frontend/Locales/de.json b/frontend/Locales/de.json index ca05872..ec0f592 100644 --- a/frontend/Locales/de.json +++ b/frontend/Locales/de.json @@ -102,6 +102,8 @@ "copied": "Privaten Schlüssel kopiert. Verwahre ihn an einem sicheren Ort!", "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!", "snackbarAction": "Privaten Schlüssel kopieren", "warningTitle": "Wichtig!", @@ -134,7 +136,7 @@ "contactRemoved": "Abo wurde entfernt", "contactUnblocked": "Profile unblocked." }, - "emptyTitleBlocked": "You have no blocked profiles", + "emptyTitleBlocked": "You have no blocked profiles", "emptyDescriptionBlocked": "You can always block a someone on the profile view.", "emptyTitleFollowing": "Du folgst niemandem", "emptyDescriptionFollowing": "Folge anderen, und sieh hier was sie posten", @@ -172,6 +174,7 @@ "newMessages": "{{newNotesCount}} neue Nachrichten. Zum Aktualisieren tippen." }, "relayCard": { + "pushDone": "Completed", "moreInfo": "Mehr Infos", "lessInfo": "Weniger Infos", "globalFeed": "Globaler Feed", @@ -273,7 +276,6 @@ "isFollower": "folgt dir", "unfollow": "Nicht mehr folgen", "copyNPub": "Schlüssel kopieren", - "relaysTitle": "Relays", "relaysDescription": "Dies sind {{username}}'s Relays, aktiviere diejenigen, zu denen du verbunden werden möchtest." }, "homePage": { @@ -301,7 +303,9 @@ "profileCard": { "notifications": { "contactAdded": "Aboniert", - "contactRemoved": "Abo entfernt" + "contactRemoved": "Abo entfernt", + "userUnblocked": "Profile unblocked", + "userBlocked": "Profile unblocked" }, "invoice": "Zap", "message": "Nachricht", @@ -309,7 +313,8 @@ "block": "Blockieren", "share": "Teilen", "unblock": "Erlauben", - "unfollow": "Abo entfernen" + "unfollow": "Abo entfernen", + "relaysTitle": "Relays" }, "conversationsFeed": { "openMessage": "Unterhaltung beginnen", diff --git a/frontend/Locales/en.json b/frontend/Locales/en.json index 7a953e3..885f539 100644 --- a/frontend/Locales/en.json +++ b/frontend/Locales/en.json @@ -103,6 +103,8 @@ "copied": "Private key copied.\n\nStore this key in a safe place.", "wrongWords": "The words don't match" }, + "skip": "Skip", + "confirmTitle": "Type the words in the right order.", "warningTitle": "Important", "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", @@ -139,7 +141,7 @@ "emptyButtonFollowing": "Paste public key", "emptyTitleFollower": "You have no followers", "emptyDescriptionFollower": "Share your public key so people can start following you.", - "emptyTitleBlocked": "You have no blocked profiles", + "emptyTitleBlocked": "You have no blocked profiles", "emptyDescriptionBlocked": "You can always block a someone on the profile view.", "emptyButtonFollower": "Copy public key", "cancel": "Cancel", @@ -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.", "centralized": "Centralized", "small": "Small", - "contacts": "# Contacts", + "contacts": "Assigned Contacts", "resilienceMode": "Resilience (experimental)", "relayName": "Address", "globalFeed": "Global feed", @@ -210,6 +212,15 @@ } }, "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", "lessInfo": "Less info", "globalFeed": "Global Feed", @@ -284,7 +295,6 @@ "follow": "Follow", "unfollow": "Following", "copyNPub": "Copy key", - "relaysTitle": "Relays", "isFollower": "follows you", "relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected." }, @@ -312,7 +322,9 @@ "profileCard": { "notifications": { "contactAdded": "Profile followed", - "contactRemoved": "Profile unfollowed" + "contactRemoved": "Profile unfollowed", + "userUnblocked": "Profile unblocked", + "userBlocked": "Profile unblocked" }, "invoice": "Tip", "message": "Message", @@ -320,7 +332,8 @@ "unfollow": "Following", "block": "Block", "unblock": "Unblock", - "share": "Share" + "share": "Share", + "relaysTitle": "Relays" }, "conversationsFeed": { "openMessage": "Start conversation", diff --git a/frontend/Locales/es.json b/frontend/Locales/es.json index 58a7b84..a988d9f 100644 --- a/frontend/Locales/es.json +++ b/frontend/Locales/es.json @@ -102,6 +102,8 @@ "copied": "Clave privada copiada. Guárdala en un lugar seguro.", "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.", "snackbarAction": "Copiar clave privada", "warningTitle": "Importante", @@ -134,7 +136,7 @@ "contactRemoved": "Has dejado de seguir a un perfil", "contactUnblocked": "Perfil desbloqueado." }, - "emptyTitleBlocked": "No tienes perfiles bloqueado", + "emptyTitleBlocked": "No tienes perfiles bloqueado", "emptyDescriptionBlocked": "Siempre puede bloquear a alguien en su vista de perfil.", "emptyTitleFollowing": "No sigues a nadie", "emptyDescriptionFollowing": "Sigue otros perfiles para ver contenido aquí.", @@ -169,6 +171,7 @@ "myFeed": "Mi feed" }, "relayCard": { + "pushDone": "Completado", "moreInfo": "Más información", "lessInfo": "Menos información", "globalFeed": "Feed Global", @@ -267,7 +270,6 @@ "follow": "Seguir", "unfollow": "Siguiendo", "copyNPub": "Copiar clave", - "relaysTitle": "Relays", "relaysDescription": "Estos son los relays de {{username}}, activa aquellos a los que quieras estar conectado." }, "homePage": { @@ -297,7 +299,9 @@ "profileCard": { "notifications": { "contactAdded": "Siguiendo", - "contactRemoved": "Dejando de seguir" + "contactRemoved": "Dejando de seguir", + "userUnblocked": "Perfil desbloqueado", + "userBlocked": "Perfil bloqueado" }, "invoice": "Propina", "message": "Mensaje", @@ -305,7 +309,8 @@ "block": "Bloquear", "share": "Share", "unblock": "Desbloquear", - "unfollow": "Siguiendo" + "unfollow": "Siguiendo", + "relaysTitle": "Relays" }, "conversationsFeed": { "openMessage": "Comenzar conversación", diff --git a/frontend/Locales/fr.json b/frontend/Locales/fr.json index 7fee8d4..374cb8c 100644 --- a/frontend/Locales/fr.json +++ b/frontend/Locales/fr.json @@ -102,6 +102,8 @@ "copied": "Clé privée copiée. Gardez-la dans un endroit sûr.", "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.", "snackbarAction": "Copier la clé privée", "warningTitle": "Important", @@ -135,7 +137,7 @@ "contactRemoved": "Vous ne suivez plus ce profil", "contactUnblocked": "Profile unblocked." }, - "emptyTitleBlocked": "You have no blocked profiles", + "emptyTitleBlocked": "You have no blocked profiles", "emptyDescriptionBlocked": "You can always block a someone on the profile view.", "emptyTitleFollowing": "Vous ne suivez personne", "emptyDescriptionFollowing": "Suivez les autres profils pour voir le contenu ici.", @@ -170,6 +172,7 @@ "myFeed": "Mon flux" }, "relayCard": { + "pushDone": "Completed", "moreInfo": "Plus d'info", "lessInfo": "Moins d'info", "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.", "centralized": "Centralized", "small": "Small", - "contacts": "# Contacts", + "contacts": "Assigned Contacts", "resilienceMode": "Resilience (experimental)", "relayName": "Adresse", "globalFeed": "Flux global", @@ -268,7 +271,6 @@ "isFollower": "follows you", "unfollow": "Abonné", "copyNPub": "Copier la clé", - "relaysTitle": "Relays", "relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected." }, "profileShare": { @@ -285,14 +287,17 @@ "profileCard": { "notifications": { "contactAdded": "Abonné", - "contactRemoved": "Vous ne suivez plus ce profil" + "contactRemoved": "Vous ne suivez plus ce profil", + "userUnblocked": "Profile unblocked", + "userBlocked": "Profile unblocked" }, "invoice": "Tip", "message": "Message", "follow": "Abonné", "block": "Bloquer", "unblock": "Débloquer", - "unfollow": "Abonné" + "unfollow": "Abonné", + "relaysTitle": "Relays" }, "conversationsFeed": { "openMessage": "Commencer la conversation", diff --git a/frontend/Locales/ru.json b/frontend/Locales/ru.json index db05160..9444a5e 100644 --- a/frontend/Locales/ru.json +++ b/frontend/Locales/ru.json @@ -103,6 +103,8 @@ "copied": "Приватный ключ скопирован.\n\nСохраните этот ключ в надежном месте.", "wrongWords": "The words doesn't match" }, + "skip": "Skip", + "confirmTitle": "Type the words in the right order.", "warningTitle": "Важно", "warningDescription": "Сохраните этот ключ в надежном месте. В случае утери ключа, Вы не сможете войти или восстановить доступ к профилю.", "warningAction": "Скопировать приватный ключ", @@ -134,7 +136,7 @@ "contactRemoved": "Вы отписались.", "contactUnblocked": "Profile unblocked." }, - "emptyTitleBlocked": "You have no blocked profiles", + "emptyTitleBlocked": "You have no blocked profiles", "emptyDescriptionBlocked": "You can always block a someone on the profile view.", "emptyTitleFollowing": "Вы ни на кого не подписаны", "emptyDescriptionFollowing": "Подпишитесь на другие профили, чтобы увидеть их заметки", @@ -169,6 +171,7 @@ "myFeed": "My feed" }, "relayCard": { + "pushDone": "Completed", "moreInfo": "Узнать больше", "lessInfo": "Скрыть", "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.", "centralized": "Centralized", "small": "Small", - "contacts": "# Contacts", + "contacts": "Assigned Contacts", "resilienceMode": "Resilience (experimental)", "relayName": "Address", "globalFeed": "Общая лента", @@ -267,7 +270,6 @@ "unfollow": "Following", "isFollower": "follows you", "copyNPub": "Скопировать ключ", - "relaysTitle": "Relays", "relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected." }, "homePage": { @@ -297,7 +299,9 @@ "profileCard": { "notifications": { "contactAdded": "Profile followed", - "contactRemoved": "Profile unfollowed" + "contactRemoved": "Profile unfollowed", + "userUnblocked": "Profile unblocked", + "userBlocked": "Profile unblocked" }, "invoice": "Tip", "message": "Message", @@ -305,7 +309,8 @@ "block": "Block", "unblock": "Desbloquear", "unfollow": "Following", - "share": "Share" + "share": "Share", + "relaysTitle": "Relays" }, "conversationsFeed": { "openMessage": "Start conversation", diff --git a/frontend/Locales/zhCn.json b/frontend/Locales/zhCn.json index 4dd6077..52b0a0e 100644 --- a/frontend/Locales/zhCn.json +++ b/frontend/Locales/zhCn.json @@ -101,6 +101,8 @@ "copied": "已复制私钥 \n\n 请妥善保管您的私钥", "wrongWords": "助记词不匹配" }, + "skip": "Skip", + "confirmTitle": "Type the words in the right order.", "warningTitle": "注意", "warningDescription": "请妥善保管您的私钥。如果遗失,您将无法登入或恢复您的账号。", "warningAction": "复制私钥", @@ -132,7 +134,7 @@ "contactRemoved": "已取消关注", "contactUnblocked": "Profile unblocked." }, - "emptyTitleBlocked": "You have no blocked profiles", + "emptyTitleBlocked": "You have no blocked profiles", "emptyDescriptionBlocked": "You can always block a someone on the profile view.", "emptyTitleFollowing": "您还没有关注任何用户", "emptyDescriptionFollowing": "关注一些用户以查看内容", @@ -208,6 +210,7 @@ } }, "relayCard": { + "pushDone": "Completed", "moreInfo": "更多", "lessInfo": "收起", "globalFeed": "全局信息流", @@ -280,7 +283,6 @@ "isFollower": "follows you", "unfollow": "关注中", "copyNPub": "复制公钥", - "relaysTitle": "Relays", "relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected." }, "homePage": { @@ -300,7 +302,9 @@ "notifications": { "contactAdded": "已关注", "contactRemoved": "已取消关注", - "npubCopied": "已复制公钥" + "npubCopied": "已复制公钥", + "userUnblocked": "Profile unblocked", + "userBlocked": "Profile unblocked" }, "invoice": "赞赏", "message": "私信", @@ -310,7 +314,8 @@ "unblock": "取消屏蔽", "share": "分享", "copyNip05": "复制 NIP-05", - "copyNPub": "复制公钥" + "copyNPub": "复制公钥", + "relaysTitle": "Relays" }, "conversationsFeed": { "openMessage": "发送私信", diff --git a/frontend/Pages/GlobalFeed/index.tsx b/frontend/Pages/GlobalFeed/index.tsx index 64f793a..5d0fda6 100644 --- a/frontend/Pages/GlobalFeed/index.tsx +++ b/frontend/Pages/GlobalFeed/index.tsx @@ -69,6 +69,8 @@ export const GlobalFeed: React.FC = ({ navigation }) => { setRefreshing(true) updateLastLoad() setNewNotesCount(0) + relayPool?.unsubscribe(['homepage-global-main', 'homepage-global-meta']) + subscribeNotes() }, []) const subscribeNotes: (past?: boolean) => void = async (past) => { @@ -189,7 +191,9 @@ export const GlobalFeed: React.FC = ({ navigation }) => { refreshing={refreshing} ListEmptyComponent={ListEmptyComponent} horizontal={false} - ListFooterComponent={} + ListFooterComponent={ + notes.length > 0 ? : <> + } ref={flashListRef} /> @@ -198,6 +202,9 @@ export const GlobalFeed: React.FC = ({ navigation }) => { } const styles = StyleSheet.create({ + loading: { + paddingTop: 16, + }, list: { height: '100%', }, diff --git a/frontend/Pages/MyFeed/index.tsx b/frontend/Pages/MyFeed/index.tsx index 41de422..fc3e679 100644 --- a/frontend/Pages/MyFeed/index.tsx +++ b/frontend/Pages/MyFeed/index.tsx @@ -63,12 +63,16 @@ export const MyFeed: React.FC = ({ navigation }) => { const onRefresh = useCallback(() => { setRefreshing(true) + relayPool?.unsubscribe([ + 'homepage-contacts-main', + 'homepage-contacts-meta', + 'homepage-contacts-replies', + ]) subscribeNotes() }, []) const subscribeNotes: (past?: boolean) => void = async (past) => { if (!database || !publicKey) return - const users: User[] = await getUsers(database, { contacts: true, order: 'created_at DESC' }) const authors: string[] = [...users.map((user) => user.id), publicKey] @@ -89,7 +93,6 @@ export const MyFeed: React.FC = ({ navigation }) => { const loadNotes: () => void = async () => { if (database && publicKey) { - relayPool?.unsubscribe(['homepage-reactions', 'homepage-replies', 'homepage-main']) getMainNotes(database, publicKey, pageSize, true).then(async (notes) => { setNotes(notes) if (notes.length > 0) { @@ -175,7 +178,9 @@ export const MyFeed: React.FC = ({ navigation }) => { refreshing={refreshing} ListEmptyComponent={ListEmptyComponent} horizontal={false} - ListFooterComponent={} + ListFooterComponent={ + notes.length > 0 ? : <> + } ref={flashListRef} /> @@ -183,6 +188,9 @@ export const MyFeed: React.FC = ({ navigation }) => { } const styles = StyleSheet.create({ + loading: { + paddingTop: 16, + }, list: { height: '100%', }, diff --git a/frontend/Pages/NotificationsFeed/index.tsx b/frontend/Pages/NotificationsFeed/index.tsx index d782d97..11d272c 100644 --- a/frontend/Pages/NotificationsFeed/index.tsx +++ b/frontend/Pages/NotificationsFeed/index.tsx @@ -186,7 +186,9 @@ export const NotificationsFeed: React.FC = () => { refreshing={refreshing} ListEmptyComponent={ListEmptyComponent} horizontal={false} - ListFooterComponent={} + ListFooterComponent={ + notes.length > 0 ? : <> + } ref={flashListRef} /> @@ -194,6 +196,9 @@ export const NotificationsFeed: React.FC = () => { } const styles = StyleSheet.create({ + loading: { + paddingTop: 16, + }, container: { flex: 1, paddingLeft: 16, diff --git a/frontend/Pages/ProfileCreatePage/index.tsx b/frontend/Pages/ProfileCreatePage/index.tsx index 79f611b..9c20e0a 100644 --- a/frontend/Pages/ProfileCreatePage/index.tsx +++ b/frontend/Pages/ProfileCreatePage/index.tsx @@ -71,6 +71,11 @@ export const ProfileCreatePage: React.FC = ({ navigation } } + const onPressSkip: () => void = () => { + setPrivateKey(key) + setUserState('ready') + } + const onChangeTextConfirm: (value: string, position: number) => void = (value, position) => { setConfirmWords((prev) => { prev[position] = value @@ -208,6 +213,13 @@ export const ProfileCreatePage: React.FC = ({ navigation {` ${step + 1}/3`} + {step > 1 && ( + + + + )} )} {showNotification && ( @@ -289,6 +301,9 @@ const styles = StyleSheet.create({ bold: { fontWeight: 'bold', }, + bottomButton: { + marginTop: 16, + }, }) export default ProfileCreatePage diff --git a/frontend/Pages/ProfilePage/index.tsx b/frontend/Pages/ProfilePage/index.tsx index c92defd..f9793b6 100644 --- a/frontend/Pages/ProfilePage/index.tsx +++ b/frontend/Pages/ProfilePage/index.tsx @@ -179,7 +179,13 @@ export const ProfilePage: React.FC = ({ route }) => { onScroll={onScroll} refreshing={refreshing} horizontal={false} - ListFooterComponent={} + ListFooterComponent={ + notes && notes.length > 0 ? ( + + ) : ( + <> + ) + } /> @@ -199,6 +205,9 @@ export const ProfilePage: React.FC = ({ route }) => { } const styles = StyleSheet.create({ + loading: { + paddingTop: 16, + }, container: { padding: 16, }, diff --git a/frontend/Pages/ReactionsFeed/index.tsx b/frontend/Pages/ReactionsFeed/index.tsx index 819722f..f8d0a4c 100644 --- a/frontend/Pages/ReactionsFeed/index.tsx +++ b/frontend/Pages/ReactionsFeed/index.tsx @@ -61,6 +61,11 @@ export const ReactionsFeed: React.FC = ({ navigation }) => { const onRefresh = useCallback(() => { setRefreshing(true) + relayPool?.unsubscribe([ + 'homepage-contacts-main', + 'homepage-contacts-meta', + 'homepage-contacts-replies', + ]) subscribeNotes() }, []) @@ -84,7 +89,6 @@ export const ReactionsFeed: React.FC = ({ navigation }) => { const loadNotes: () => void = async () => { if (database && publicKey) { - relayPool?.unsubscribe(['homepage-reactions', 'homepage-replies', 'homepage-main']) getReactedNotes(database, publicKey, pageSize).then(async (notes) => { setNotes(notes) if (notes.length > 0) { @@ -175,7 +179,9 @@ export const ReactionsFeed: React.FC = ({ navigation }) => { refreshing={refreshing} ListEmptyComponent={ListEmptyComponent} horizontal={false} - ListFooterComponent={} + ListFooterComponent={ + notes.length > 0 ? : <> + } ref={flashListRef} /> @@ -183,6 +189,9 @@ export const ReactionsFeed: React.FC = ({ navigation }) => { } const styles = StyleSheet.create({ + loading: { + paddingTop: 16, + }, list: { height: '100%', }, diff --git a/frontend/Pages/RelaysPage/index.tsx b/frontend/Pages/RelaysPage/index.tsx index 9c52af2..5cd6cf5 100644 --- a/frontend/Pages/RelaysPage/index.tsx +++ b/frontend/Pages/RelaysPage/index.tsx @@ -1,6 +1,5 @@ import React, { useContext, useState } from 'react' import { FlatList, ListRenderItem, ScrollView, StyleSheet, View } from 'react-native' -import Clipboard from '@react-native-clipboard/clipboard' import { useTranslation } from 'react-i18next' import { RelayPoolContext } from '../../Contexts/RelayPoolContext' import { getRelays, Relay } from '../../Functions/DatabaseFunctions/Relays' @@ -40,15 +39,14 @@ export const defaultRelays = [ export const RelaysPage: React.FC = () => { const defaultRelayInput = React.useMemo(() => 'wss://', []) - const { updateRelayItem, addRelayItem, removeRelayItem, relayPool } = useContext(RelayPoolContext) + const { updateRelayItem, addRelayItem, relayPool, setDisplayrelayDrawer } = + useContext(RelayPoolContext) const { database } = useContext(AppContext) const { t } = useTranslation('common') const theme = useTheme() const bottomSheetAddRef = React.useRef(null) - const bottomSheetEditRef = React.useRef(null) const bottomSheetResilenseRef = React.useRef(null) const [relays, setRelays] = React.useState([]) - const [selectedRelay, setSelectedRelay] = useState() const [addRelayInput, setAddRelayInput] = useState(defaultRelayInput) const [showNotification, setShowNotification] = useState() @@ -66,24 +64,26 @@ export const RelaysPage: React.FC = () => { } const addRelay: (url: string) => void = (url) => { - addRelayItem({ - url, - active: 1, - global_feed: 1, - }).then(() => { - updateRelays() - setShowNotification('add') - }) + if (!relayList.find((relay) => relay.url === url)) { + addRelayItem({ + url, + active: 1, + global_feed: 1, + }).then(() => { + updateRelays() + 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) => { relay.active = 1 @@ -184,8 +184,7 @@ export const RelaysPage: React.FC = () => { /> )} onPress={() => { - setSelectedRelay(item) - bottomSheetEditRef.current?.open() + setDisplayrelayDrawer(item.url) }} /> ) @@ -377,35 +376,6 @@ export const RelaysPage: React.FC = () => { - - - - - { - if (selectedRelay) removeRelay(selectedRelay.url) - bottomSheetEditRef.current?.close() - }} - /> - {t('relaysPage.removeRelay')} - - - { - if (selectedRelay) Clipboard.setString(selectedRelay.url) - }} - /> - {t('relaysPage.copyRelay')} - - - - {selectedRelay?.url} - - ) } diff --git a/frontend/Pages/RepostsFeed/index.tsx b/frontend/Pages/RepostsFeed/index.tsx index 8f0f314..f8667e4 100644 --- a/frontend/Pages/RepostsFeed/index.tsx +++ b/frontend/Pages/RepostsFeed/index.tsx @@ -61,6 +61,11 @@ export const RepostsFeed: React.FC = ({ navigation }) => { const onRefresh = useCallback(() => { setRefreshing(true) + relayPool?.unsubscribe([ + 'homepage-contacts-main', + 'homepage-contacts-meta', + 'homepage-contacts-replies', + ]) subscribeNotes() }, []) @@ -84,7 +89,6 @@ export const RepostsFeed: React.FC = ({ navigation }) => { const loadNotes: () => void = async () => { if (database && publicKey) { - relayPool?.unsubscribe(['homepage-reactions', 'homepage-replies', 'homepage-main']) getRepostedNotes(database, publicKey, pageSize).then(async (notes) => { setNotes(notes) if (notes.length > 0) { @@ -167,7 +171,9 @@ export const RepostsFeed: React.FC = ({ navigation }) => { refreshing={refreshing} ListEmptyComponent={ListEmptyComponent} horizontal={false} - ListFooterComponent={} + ListFooterComponent={ + notes.length > 0 ? : <> + } ref={flashListRef} /> @@ -175,6 +181,9 @@ export const RepostsFeed: React.FC = ({ navigation }) => { } const styles = StyleSheet.create({ + loading: { + paddingTop: 16, + }, list: { height: '100%', }, diff --git a/frontend/Pages/SendPage/index.tsx b/frontend/Pages/SendPage/index.tsx index 8bf9996..3a74f73 100644 --- a/frontend/Pages/SendPage/index.tsx +++ b/frontend/Pages/SendPage/index.tsx @@ -260,7 +260,9 @@ export const SendPage: React.FC = ({ route }) => {