New login view (#445)

This commit is contained in:
KoalaSat 2023-03-18 14:32:45 +00:00 committed by GitHub
commit 9f120fd44d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 606 additions and 397 deletions

View File

@ -13,7 +13,7 @@ interface ProfileCardProps {
publicKey?: string
lnurl?: string
lnAddress?: string
validNip05?: number
validNip05?: number | undefined
nip05?: string
picture?: string
avatarSize?: number

View File

@ -1,4 +1,14 @@
import { endOfYesterday, format, formatDistanceToNow, fromUnixTime, isBefore } from 'date-fns'
import {
differenceInDays,
endOfYesterday,
format,
formatDistanceToNow,
fromUnixTime,
isBefore,
isToday,
isYesterday,
} from 'date-fns'
import { t } from 'i18next'
export const handleInfinityScroll: (event: any) => boolean = (event) => {
const mHeight = event.nativeEvent.layoutMeasurement.height
@ -89,7 +99,7 @@ export const validNip21: (string: string | undefined) => boolean = (string) => {
}
}
export const formatDate: (unix: number | undefined) => string = (unix) => {
export const formatHour: (unix: number | undefined) => string = (unix) => {
if (!unix) return ''
const date = fromUnixTime(unix)
@ -100,6 +110,27 @@ export const formatDate: (unix: number | undefined) => string = (unix) => {
}
}
export const formatDate: (timestamp: number | undefined, showTime?: boolean) => string = (
timestamp,
showTime = true,
) => {
if (!timestamp) return ''
const date = fromUnixTime(timestamp)
let result = format(date, 'MM-dd-yy')
if (isToday(date)) {
result = t('time.today')
} else if (isYesterday(date)) {
result = t('time.yesterday')
} else if (differenceInDays(new Date(), date) < 6) {
result = format(date, 'EEEE')
}
if (showTime) result += `, ${format(date, 'HH:mm')}`
return result
}
export const formatBigNumber: (num: number | undefined) => string = (num) => {
if (num === undefined) return ''

View File

@ -1,5 +1,9 @@
{
"common": {
"time": {
"today": "Today",
"yerterday": "Yesterday"
},
"drawers": {
"relaysTitle": "Relays",
"relaysDescription": "Relays sind Nodes (Netzknoten) im Netzwerk, die als Vermittler von Nachrichten zwischen den Anwendungen dienen.\n\n\nRelays können die Belastbarkeit und die Verfügbarkeit des Netzwerks verbessern, indem sie dafür sorgen, das Nachrichten trotz Unterbrechungen oder Ausfällen der Verfügbarkeit ausgeliefert werden.\n\n\nRelays können Privatsphäre und Netzwerksicherheit erhöhen, indem sie Aufenthaltsort und Identität der Anwendungen bzw. der Benutzer, die miteinander kommunizieren, verbergen\n\n\nDies kann von Wert sein in Umgebungen, in denen Zensur oder Überwachung ein Problem ist.\n\n\nEs ist wichtig darauf hinzuweisen, das Relays für schadhafte Zwecke missbraucht werden können, wie zum Beispiel Sniffing oder das Zensieren von Netzwerkverkehr.\n\n\nDeswegen ist es von Bedeutung, die Nutzung von Relays sorgfältig abzuwägen, und angemessenene Sichheitsmassnahmen anzuwenden, um Identität, Privatsphäre und Netzwerksicherheit zu schützen.",
@ -10,15 +14,24 @@
"privateKey": "Privater Schlüssel",
"privateKeyDescription": "Behandele den privaten Schlüssel wie ein Passwort",
"privateKeysSnackbarTitle": "Wichtig!",
"privateKeysSnackbarDescription": "Verwahre den privaten Schlüssel an einem sicheren Ort. Geht der Schlüssel verloren, kann er nicht wiederhergestellt werden. Das Konto kann nie wieder benutzt werden."
"privateKeysSnackbarDescription": "Verwahre den privaten Schlüssel an einem sicheren Ort. Geht der Schlüssel verloren, kann er nicht wiederhergestellt werden. Das Konto kann nie wieder benutzt werden.",
"loginTitle": "Resilient login",
"loginDescription": "The \"resilient login\" process has three steps that help make the network stronger and more decentralized.",
"loginStep1Title": "1. Connect to random relays",
"loginStep1Description": "Randomly connect to 8 relays to search for your profile and your list of relays.",
"loginStep2Title": "2. Search for contacts in your relay list",
"loginStep2Description": "Connecting to your relays and searching for your contacts.",
"loginStep3Title": "3. Search the relays of your contacts",
"loginStep3Description": "You can add the relays used by your contacts to your list and connect to them to strengthen the network.",
"loginskip": "You can skip this process but you may miss out on the opportunity to connect to a diverse range of relays and expand your network's reach"
},
"homeNavigator": {
"ProfileCreate": "Profil anlegen",
"Search": "",
"ImageGallery": "",
"ProfileConnect": "",
"Group": "",
"ProfileLoad": "",
"Group": "",
"ProfileLoad": "Login",
"Landing": "",
"QrReader": "",
"Contacts": "Kontakte",
@ -40,7 +53,7 @@
"emptyTitle": "Tip",
"emptyDescription": "Tippe @ um jemanden zu finden\n\nTippe # um nach Themen zu suchen"
},
"conversationPage": {
"unableDecypt": "{{username}} hat dich erwähnt",
"typeMessage": "Nachricht schreiben",
@ -49,24 +62,26 @@
}
},
"profileLoadPage": {
"contactsRelays": "Relay Liste",
"connect": "Verbinden und zum Start gehen",
"foundRelays": "Relays gefunden",
"searchingContacts": "Suche nach deinen Kontakten",
"retry": "Wiederholen",
"connectedRelays": "Relays verbinden",
"nextStep": "Nächster Schritt",
"searchingRelays": "Suche nach deinen Relays",
"reconnectOther": "Zu den anderen Relays neu verbinden",
"relaysDescripion": "Verbinde dich zu einem anderen Relay falls deine Daten nicht gefunden werden.",
"relays": "Deine Relays",
"home": "Start",
"searchingProfile": "Durchsuche Profil",
"foundProfile": "Profil gefunden",
"foundContacts": "{{contactsCount}} Kontakte gefunden",
"storing": "Speichere {{lastEventId}} in Datenbank."
},
"qrReaderPage": {
"connectingRandomRelays": "1. Connect to random relays",
"connectingRandomRelaysDescription": "Randomly connect to 8 relays to search for your profile and your list of relays.",
"randomRelays": "Random relays",
"connectedRelays": "{{activeRelays}} connected",
"myProfile": "My profile",
"myRelays": "My relays",
"relaysTooLong": "Taking too long?",
"relaysReconnect": "Reconnect to other relays",
"skip": "Überspringen",
"continue": "Weiter",
"searchContacts": "2. Search contacts in your relays",
"searchContactsDescription": "Connecting to your relays and searching for your contacts.",
"contactsCount": "Contacts found",
"searchContactsRelays": "3. Search your contacts relays",
"searchContactsRelaysDescription": "You can add the relays used by your contacts to your list and connect to them to strengthen the network.",
"contatcsRelays": "Contatcs Relays",
"contatcsRelaysCount": "{{activeRelays}} lists found",
"connectAccess": "Connect and access"
},
"qrReaderPage": {
"emptyTitle": "Berechtigung nicht gewährt",
"emptyDescription": "Nostros Kamera Berechtigungen gewähren um QRCodes zu scannen",
"QRreader": "QR Leser"
@ -168,7 +183,7 @@
"replied": "Geantwortet",
"emptyTitle": "Keine Benachrichtigung.",
"emptyDescription": "Poste etwas und erhalte Antworten und Reaktionen.",
"emptyButton": "Schreibe etwas"
"emptyButton": "Schreibe etwas",
"notificationsFeed": "Schreibe etwas"
},
"profileCreatePage": {
@ -200,8 +215,8 @@
"privateKey": "Privater Schlüssel",
"publicKey": "Öffentlicher Schlüssel",
"loginMethod": "Einloggen mit",
"mnemonic": "Mnemonic"
"mnemonicInput": "Zum Einloggen Mnemonic Wörter in richtiger Reihenfolge eingeben"
"mnemonic": "Mnemonic",
"mnemonicInput": "Zum Einloggen Mnemonic Wörter in richtiger Reihenfolge eingeben"
},
"contactsPage": {
"notifications": {

View File

@ -1,5 +1,9 @@
{
"common": {
"time": {
"today": "Today",
"yerterday": "Yesterday"
},
"drawers": {
"relaysTitle": "Relays",
"relaysDescription": "Relays are nodes on the network that act as intermediaries for the transmission of messages between applications.\n\n\nRelays can be used to improve network resiliency and availability by allowing messages to be delivered even when there are failures or interruptions in connectivity.\n\n\nRelays can also be used to improve privacy and network security, as they can hide the location and identity of applications that communicate with each other. This can be useful in environments where censorship or surveillance is an issue.\n\n\nIt is important to note that relays can also be used for malicious purposes, such as sniffing or censoring network traffic.\n\n\nTherefore, it is important to carefully evaluate the use of relays and consider appropriate security measures to protect privacy and network security.",
@ -10,7 +14,16 @@
"privateKey": "Private key",
"privateKeyDescription": "Think of your private key as your password.",
"privateKeysSnackbarTitle": "Important.",
"privateKeysSnackbarDescription": "Keep your private key in a safe place. If you lose it, you will not be able to access it again or recover your account."
"privateKeysSnackbarDescription": "Keep your private key in a safe place. If you lose it, you will not be able to access it again or recover your account.",
"loginTitle": "Resilient login",
"loginDescription": "The \"resilient login\" process has three steps that help make the network stronger and more decentralized.",
"loginStep1Title": "1. Connect to random relays",
"loginStep1Description": "Randomly connect to 8 relays to search for your profile and your list of relays.",
"loginStep2Title": "2. Search for contacts in your relay list",
"loginStep2Description": "Connecting to your relays and searching for your contacts.",
"loginStep3Title": "3. Search the relays of your contacts",
"loginStep3Description": "You can add the relays used by your contacts to your list and connect to them to strengthen the network.",
"loginskip": "You can skip this process but you may miss out on the opportunity to connect to a diverse range of relays and expand your network's reach"
},
"homeNavigator": {
"ProfileCreate": "Create profile",
@ -18,7 +31,7 @@
"ImageGallery": "",
"ProfileConnect": "",
"Group": "",
"ProfileLoad": "",
"ProfileLoad": "Login",
"Landing": "",
"QrReader": "",
"Contacts": "Contacts",
@ -48,24 +61,27 @@
}
},
"profileLoadPage": {
"contactsRelays": "Lists of relays ",
"connect": "Connect and go home",
"foundRelays": "Relays found",
"searchingContacts": "Searching for your contacts",
"retry": "Retry",
"connectedRelays": "Connected relays ",
"nextStep": "Next step",
"searchingRelays": "Searching for your relays",
"reconnectOther": "Reconnect to other relays",
"contactRelays": "Contact's relays",
"contactRelaysDescription": "Searching for relays where your contacts can be found",
"relaysDescripion": "Connect with other relays if you have problems finding your data.",
"relays": "See relays",
"home": "Go Home",
"searchingProfile": "Searching for your profile",
"foundProfile": "Profile found",
"foundContacts": "{{contactsCount}} contacts found",
"storing": "Event {{lastEventId}} stored on database."
"connectingRandomRelays": "1. Connect to random relays",
"connectingRandomRelaysDescription": "Randomly connect to 8 relays to search for your profile and your list of relays.",
"randomRelays": "Random relays",
"connectedRelays": "{{activeRelays}} connected",
"myProfile": "My profile",
"myRelays": "My relays",
"relaysTooLong": "Taking too long?",
"relaysReconnect": "Reconnect to other relays",
"skip": "Skip",
"continue": "Continue",
"searchContacts": "2. Search contacts in your relays",
"searchContactsDescription": "Connecting to your relays and searching for your contacts.",
"contactsCount": "Contacts found",
"searchContactsRelays": "3. Search your contacts relays",
"searchContactsRelaysDescription": "You can add the relays used by your contacts to your list and connect to them to strengthen the network.",
"contatcsRelays": "Contatcs Relays",
"contatcsRelaysCount": "{{activeRelays}} lists found",
"connectAccess": "Connect and access",
"skipTitle": "Skip resilient login",
"skipDescription": "By skipping this login process, it may take you more time to find your contacts and view events.\n\nThis login process improves the decentralization of the network and its resilience.",
"continueLogin": "Continue with resilient login"
},
"qrReaderPage": {
"emptyTitle": "Permissions not granted",

View File

@ -1,5 +1,9 @@
{
"common": {
"time": {
"today": "Hoy",
"yerterday": "Ayer"
},
"drawers": {
"relaysTitle": "Relés",
"relaysDescription": "Los relays son nodos en la red que actúan como intermediarios para la transmisión demensajes entre aplicaciones.\n\n\nLos relays pueden ser utilizados para mejorar la resiliencia yla disponibilidad de la red, ya que permiten que los mensajes sean entregados aun cuandohay fallos o interrupciones en la conectividad.\n\n\nLos relays también pueden ser utilizadospara mejorar la privacidad y la seguridad de la red, ya que pueden ocultar la ubicación yel identidad de las aplicaciones que se comunican entre sí a través de ellos. Esto puedeser útil en entornos donde la censura o la vigilancia son un problema.\n\n\nEs importante teneren cuenta que los relays también pueden ser utilizados para propósitos malintencionados,como para rastrear o censurar el tráfico de la red.\n\n\nPor lo tanto, es importante evaluarcuidadosamente el uso de relays y considerar medidas de seguridad adecuadas para protegerla privacidad y la seguridad de la red.",
@ -10,7 +14,16 @@
"privateKey": "Clave privada",
"privateKeyDescription": "Piensa en tu clave privada como tu contraseña.",
"privateKeysSnackbarTitle": "Muy importante.",
"privateKeysSnackbarDescription": "Guarda tu clave privada en un lugar seguro, si la pierdes no podrás volver a acceder con ella ni recuperar tu cuenta."
"privateKeysSnackbarDescription": "Guarda tu clave privada en un lugar seguro, si la pierdes no podrás volver a acceder con ella ni recuperar tu cuenta.",
"loginTitle": "Resilient login",
"loginDescription": "The \"resilient login\" process has three steps that help make the network stronger and more decentralized.",
"loginStep1Title": "1. Connect to random relays",
"loginStep1Description": "Randomly connect to 8 relays to search for your profile and your list of relays.",
"loginStep2Title": "2. Search for contacts in your relay list",
"loginStep2Description": "Connecting to your relays and searching for your contacts.",
"loginStep3Title": "3. Search the relays of your contacts",
"loginStep3Description": "You can add the relays used by your contacts to your list and connect to them to strengthen the network.",
"loginskip": "You can skip this process but you may miss out on the opportunity to connect to a diverse range of relays and expand your network's reach"
},
"searchPage": {
"placeholder": "Busca for claves públicas, notas, ...",
@ -29,7 +42,7 @@
"ImageGallery": "",
"ProfileCreate": "Crear perfil",
"ProfileConnect": "",
"ProfileLoad": "",
"ProfileLoad": "Login",
"Landing": "",
"Contacts": "Contactos",
"Conversation": "Conversación",
@ -53,21 +66,24 @@
}
},
"profileLoadPage": {
"contactsRelays": "Listas de relays ",
"foundRelays": "Relays encontrados",
"searchingContacts": "Buscando tus contactos",
"retry": "Reintentar",
"connectedRelays": "Relays conectados ",
"nextStep": "Siguiente",
"searchingRelays": "Buscando tus elays",
"reconnectOther": "Reconectar a otros relays",
"relaysDescripion": "Conéctate a otros relays si tienes problemas encontrando tus datos.",
"relays": "Ver relays",
"home": "Acceder",
"searchingProfile": "Buscando tu perfil",
"foundProfile": "Perfil encontrado",
"foundContacts": "{{contactsCount}} contactos encontrados",
"storing": "Evento {{lastEventId}} guardado en base de datos."
"connectingRandomRelays": "1. Connectar a relays aleatorios",
"connectingRandomRelaysDescription": "Connexión aleatoria a 8 relays para buscar tu perfil y list de contactos.",
"randomRelays": "Relays aleatorios",
"connectedRelays": "{{activeRelays}} connectados",
"myProfile": "Mi perfil",
"myRelays": "Mis relays",
"relaysTooLong": "¿Tarda demasiado?",
"relaysReconnect": "Reconectar a otros relays",
"skip": "Saltar",
"continue": "Continuar",
"searchContacts": "2. Buscar contactos en tus relays",
"searchContactsDescription": "Conectando a tus relays y buscando tus contactos",
"contactsCount": "Contactos encontrados",
"searchContactsRelays": "3. Buscar los relays de tus contactos",
"searchContactsRelaysDescription": "Puedes añadir los relays donde se encuentran tus contactos para reforzar al red.",
"contatcsRelays": "Relays de contactos",
"contatcsRelaysCount": "{{activeRelays}} listas encontradas",
"connectAccess": "Connectar y acceder"
},
"sendPage": {
"isContact": "Siguiendo",

View File

@ -1,5 +1,9 @@
{
"common": {
"time": {
"today": "Today",
"yerterday": "Yesterday"
},
"drawers": {
"relaysTitle": "Relais",
"relaysDescription": "Les relais sont des nœuds du réseau qui servent d'intermédiaires pour la transmission de messages entre les applications.\n\nLes relais peuvent être utilisés pour améliorer la résilience et la disponibilité des réseaux en permettant la transmission des messages même en cas de défaillance ou d'interruption de la connectivité.\n\nLes relais peuvent également être utilisés pour améliorer la confidentialité et la sécurité des réseaux, car ils peuvent cacher l'emplacement et l'identité des applications qui communiquent entre elles par leur intermédiaire. Cela peut être utile dans les environnements où la censure ou la surveillance est un problème.\n\nIl est important de noter que les relais peuvent également être utilisés à des fins malveillantes, par exemple pour suivre ou censurer le trafic réseau.\n\nIl est donc important d'évaluer soigneusement l'utilisation des relais et d'envisager des mesures de sécurité appropriées pour protéger la vie privée et la sécurité du réseau.",
@ -10,7 +14,16 @@
"privateKey": "Clé privée",
"privateKeyDescription": "Considérez votre clé privée comme votre mot de passe.",
"privateKeysSnackbarTitle": "Très important.",
"privateKeysSnackbarDescription": "Conservez votre clé privée dans un endroit sûr. Si vous la perdez, vous ne pourrez plus avoir accès ni récupérer votre compte."
"privateKeysSnackbarDescription": "Conservez votre clé privée dans un endroit sûr. Si vous la perdez, vous ne pourrez plus avoir accès ni récupérer votre compte.",
"loginTitle": "Resilient login",
"loginDescription": "The \"resilient login\" process has three steps that help make the network stronger and more decentralized.",
"loginStep1Title": "1. Connect to random relays",
"loginStep1Description": "Randomly connect to 8 relays to search for your profile and your list of relays.",
"loginStep2Title": "2. Search for contacts in your relay list",
"loginStep2Description": "Connecting to your relays and searching for your contacts.",
"loginStep3Title": "3. Search the relays of your contacts",
"loginStep3Description": "You can add the relays used by your contacts to your list and connect to them to strengthen the network.",
"loginskip": "You can skip this process but you may miss out on the opportunity to connect to a diverse range of relays and expand your network's reach"
},
"searchPage": {
"placeholder": "Look for public keys, notes, hashtags...",
@ -29,7 +42,7 @@
"Search": "",
"ProfileCreate": "Create profile",
"ProfileConnect": "",
"ProfileLoad": "",
"ProfileLoad": "Login",
"Landing": "",
"Contacts": "Contacts",
"Conversation": "Conversation",
@ -71,21 +84,24 @@
}
},
"profileLoadPage": {
"contactsRelays": "Lists of relays ",
"foundRelays": "Relays found",
"searchingContacts": "Searching for your contacts",
"retry": "Retry",
"connectedRelays": "Connected relays ",
"nextStep": "Next step",
"searchingRelays": "Searching for your relays",
"reconnectOther": "Reconnect to other relays",
"relaysDescripion": "Connectez-vous à d'autres relais si vous avez des problèmes pour trouver vos données.",
"relays": "Voir relais",
"home": "Accès",
"searchingProfile": "A la recherche de votre profil",
"foundProfile": "Profil trouvé",
"foundContacts": "{{contactsCount}} contacts trouvés",
"storing": "Event {{lastEventId}} stored on database."
"connectingRandomRelays": "1. Connect to random relays",
"connectingRandomRelaysDescription": "Randomly connect to 8 relays to search for your profile and your list of relays.",
"randomRelays": "Random relays",
"connectedRelays": "{{activeRelays}} connected",
"myProfile": "My profile",
"myRelays": "My relays",
"relaysTooLong": "Taking too long?",
"relaysReconnect": "Reconnect to other relays",
"skip": "Skip",
"continue": "Continue",
"searchContacts": "2. Search contacts in your relays",
"searchContactsDescription": "Connecting to your relays and searching for your contacts.",
"contactsCount": "Contacts found",
"searchContactsRelays": "3. Search your contacts relays",
"searchContactsRelaysDescription": "You can add the relays used by your contacts to your list and connect to them to strengthen the network.",
"contatcsRelays": "Contatcs Relays",
"contatcsRelaysCount": "{{activeRelays}} lists found",
"connectAccess": "Connect and access"
},
"sendPage": {
"isContact": "Abonné",

View File

@ -1,5 +1,9 @@
{
"common": {
"time": {
"today": "Today",
"yerterday": "Yesterday"
},
"drawers": {
"relaysTitle": "Реле",
"relaysDescription": "Реле(ретрансляторы) — это сетевые узлы, которые работают как посредники для передачи сообщений между приложениями.\n\n\nРетрансляторы можно использовать для повышения отказоустойчивости и доступности сети, позволяя доставлять сообщения даже при сбоях и проблемах с подключением. n\n\nРеле также можно использовать для повышения конфиденциальности и сетевой безопасности, поскольку они могут скрывать местоположение и идентификационные данные приложений, которые обмениваются данными. Это может быть полезно в условиях цензуры или слежки.\n\n \nВажно отметить, что реле также могут использоваться в злонамеренных целях, таких как прослушивание или цензура сетевого трафика.\n \n\nПоэтому важно тщательно оценивать использование реле и принимать соответствующие меры безопасности для защиты конфиденциальности и сетевой безопасности.",
@ -10,7 +14,16 @@
"privateKey": "Приватный ключ",
"privateKeyDescription": "Представьте, что приватный(секретный) ключ это пароль.",
"privateKeysSnackbarTitle": "Важно",
"privateKeysSnackbarDescription": "Keep your private key in a safe place, if you lose it you will not be able to access it again or recover your account."
"privateKeysSnackbarDescription": "Keep your private key in a safe place, if you lose it you will not be able to access it again or recover your account.",
"loginTitle": "Resilient login",
"loginDescription": "The \"resilient login\" process has three steps that help make the network stronger and more decentralized.",
"loginStep1Title": "1. Connect to random relays",
"loginStep1Description": "Randomly connect to 8 relays to search for your profile and your list of relays.",
"loginStep2Title": "2. Search for contacts in your relay list",
"loginStep2Description": "Connecting to your relays and searching for your contacts.",
"loginStep3Title": "3. Search the relays of your contacts",
"loginStep3Description": "You can add the relays used by your contacts to your list and connect to them to strengthen the network.",
"loginskip": "You can skip this process but you may miss out on the opportunity to connect to a diverse range of relays and expand your network's reach"
},
"searchPage": {
"placeholder": "Look for public keys, notes, hashtags...",
@ -29,7 +42,7 @@
"Search": "",
"ProfileCreate": "Create profile",
"ProfileConnect": "",
"ProfileLoad": "",
"ProfileLoad": "Login",
"Landing": "",
"Contacts": "Contacts",
"Conversation": "Диалог",
@ -71,21 +84,24 @@
}
},
"profileLoadPage": {
"contactsRelays": "Lists of relays ",
"foundRelays": "Relays found",
"searchingContacts": "Searching for your contacts",
"retry": "Retry",
"connectedRelays": "Connected relays ",
"nextStep": "Next step",
"searchingRelays": "Searching for your relays",
"reconnectOther": "Reconnect to other relays",
"relaysDescripion": "При проблемах с получением данных, подключитесь к другим реле.",
"relays": "Посмотреть реле",
"home": "На главную",
"searchingProfile": "Ищем Ваш профиль.",
"foundProfile": "Профиль найден.",
"foundContacts": "{{contactsCount}} контакта(ов) найдено",
"storing": "Event {{lastEventId}} stored on database."
"connectingRandomRelays": "1. Connect to random relays",
"connectingRandomRelaysDescription": "Randomly connect to 8 relays to search for your profile and your list of relays.",
"randomRelays": "Random relays",
"connectedRelays": "{{activeRelays}} connected",
"myProfile": "My profile",
"myRelays": "My relays",
"relaysTooLong": "Taking too long?",
"relaysReconnect": "Reconnect to other relays",
"skip": "Skip",
"continue": "Continue",
"searchContacts": "2. Search contacts in your relays",
"searchContactsDescription": "Connecting to your relays and searching for your contacts.",
"contactsCount": "Contacts found",
"searchContactsRelays": "3. Search your contacts relays",
"searchContactsRelaysDescription": "You can add the relays used by your contacts to your list and connect to them to strengthen the network.",
"contatcsRelays": "Contatcs Relays",
"contatcsRelaysCount": "{{activeRelays}} lists found",
"connectAccess": "Connect and access"
},
"sendPage": {
"isContact": "Подписаны",

View File

@ -1,5 +1,9 @@
{
"common": {
"time": {
"today": "Today",
"yerterday": "Yesterday"
},
"drawers": {
"relaysTitle": "关于中继",
"relaysDescription": "中继是网络上的节点,作为应用程序之间传输消息的中介。\n\n\n中继可用于提高网络的弹性和可用性即使在连接出现故障或中断的情况下也能传递消息。 \n\n\n中继还可用于提高隐私和网络安全因为它们可以隐藏相互通信的用户的位置和身份。 \n\n\n这在审查或监视是一个问题的环境中是很有用的。 \n\n\n需要注意的是中继也可以用于恶意的目的如嗅探或审查网络流量。",
@ -10,7 +14,16 @@
"privateKey": "私钥",
"privateKeyDescription": "您可以将私钥看作是您的密码",
"privateKeysSnackbarTitle": "注意",
"privateKeysSnackbarDescription": "请妥善保管您的私钥。如果遗失,您将无法访问或恢复您的账号。"
"privateKeysSnackbarDescription": "请妥善保管您的私钥。如果遗失,您将无法访问或恢复您的账号。",
"loginTitle": "Resilient login",
"loginDescription": "The \"resilient login\" process has three steps that help make the network stronger and more decentralized.",
"loginStep1Title": "1. Connect to random relays",
"loginStep1Description": "Randomly connect to 8 relays to search for your profile and your list of relays.",
"loginStep2Title": "2. Search for contacts in your relay list",
"loginStep2Description": "Connecting to your relays and searching for your contacts.",
"loginStep3Title": "3. Search the relays of your contacts",
"loginStep3Description": "You can add the relays used by your contacts to your list and connect to them to strengthen the network.",
"loginskip": "You can skip this process but you may miss out on the opportunity to connect to a diverse range of relays and expand your network's reach"
},
"searchPage": {
"placeholder": "Look for public keys, notes, hashtags...",
@ -30,7 +43,7 @@
"ProfileCreate": "创建用户",
"ProfileConnect": "",
"Contacts": "联系人",
"ProfileLoad": "",
"ProfileLoad": "Login",
"Landing": "",
"Conversation": "会话",
"Repost": "转发",
@ -70,21 +83,24 @@
}
},
"profileLoadPage": {
"contactsRelays": "Lists of relays ",
"foundRelays": "Relays found",
"searchingContacts": "Searching for your contacts",
"retry": "Retry",
"connectedRelays": "Connected relays ",
"nextStep": "Next step",
"searchingRelays": "Searching for your relays",
"reconnectOther": "Reconnect to other relays",
"relaysDescripion": "若查看您的数据时遇到问题,可尝试连接其他中继重试",
"relays": "查看中继",
"home": "去首页",
"searchingProfile": "搜索用户",
"foundProfile": "已找到的用户",
"foundContacts": "已找到 {{contactsCount}} 个联系人",
"storing": "事件 {{lastEventId}} 已存储到数据库"
"connectingRandomRelays": "1. Connect to random relays",
"connectingRandomRelaysDescription": "Randomly connect to 8 relays to search for your profile and your list of relays.",
"randomRelays": "Random relays",
"connectedRelays": "{{activeRelays}} connected",
"myProfile": "My profile",
"myRelays": "My relays",
"relaysTooLong": "Taking too long?",
"relaysReconnect": "Reconnect to other relays",
"skip": "跳过",
"continue": "继续",
"searchContacts": "2. Search contacts in your relays",
"searchContactsDescription": "Connecting to your relays and searching for your contacts.",
"contactsCount": "Contacts found",
"searchContactsRelays": "3. Search your contacts relays",
"searchContactsRelaysDescription": "You can add the relays used by your contacts to your list and connect to them to strengthen the network.",
"contatcsRelays": "Contatcs Relays",
"contatcsRelaysCount": "{{activeRelays}} lists found",
"connectAccess": "Connect and access"
},
"sendPage": {
"isContact": "正在关注",

View File

@ -35,7 +35,7 @@ import { UserContext } from '../../Contexts/UserContext'
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
import { useFocusEffect } from '@react-navigation/native'
import { Kind } from 'nostr-tools'
import { formatDate, handleInfinityScroll } from '../../Functions/NativeFunctions'
import { handleInfinityScroll } from '../../Functions/NativeFunctions'
import NostrosAvatar from '../../Components/NostrosAvatar'
import UploadImage from '../../Components/UploadImage'
import { Swipeable } from 'react-native-gesture-handler'
@ -249,7 +249,7 @@ export const ConversationPage: React.FC<ConversationPageProps> = ({ route }) =>
/>
</View>
)}
<Text>{formatDate(message?.created_at)}</Text>
<Text>{formatHour(message?.created_at)}</Text>
</View>
</View>
{message ? (

View File

@ -37,7 +37,12 @@ const FAQ: React.FC<{ item: FAQItem }> = ({ item }) => {
}}
titleStyle={styles.faqItemTitle}
>
<Text numberOfLines={expanded ? undefined : 3} style={StyleSheet.flatten([{color: theme.colors.onBackground}, styles.faqItemContent])}>{item.answer}</Text>
<Text
numberOfLines={expanded ? undefined : 3}
style={StyleSheet.flatten([{ color: theme.colors.onBackground }, styles.faqItemContent])}
>
{item.answer}
</Text>
</List.Accordion>
)
}
@ -130,7 +135,7 @@ const FaqPage: React.FC = () => {
return (
<View style={[styles.container, { backgroundColor: theme.colors.background }]}>
<Searchbar placeholder={t('faq.searchLabel') ?? ''} value={search} onChangeText={setSearch} />
<FlatList data={visibleFaqs} renderItem={renderItem} style={styles.list} />
<FlatList data={visibleFaqs} renderItem={renderItem} />
</View>
)
}
@ -141,12 +146,12 @@ const styles = StyleSheet.create({
flex: 1,
},
faqItemTitle: {
fontSize: 18
fontSize: 18,
},
faqItemContent: {
fontSize: 16,
lineHeight: 24,
}
},
})
export default FaqPage

View File

@ -28,7 +28,7 @@ import { UserContext } from '../../Contexts/UserContext'
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
import { useFocusEffect } from '@react-navigation/native'
import { Kind } from 'nostr-tools'
import { formatDate, handleInfinityScroll } from '../../Functions/NativeFunctions'
import { formatHour, handleInfinityScroll } from '../../Functions/NativeFunctions'
import NostrosAvatar from '../../Components/NostrosAvatar'
import UploadImage from '../../Components/UploadImage'
import { getGroupMessages, type GroupMessage } from '../../Functions/DatabaseFunctions/Groups'
@ -301,7 +301,7 @@ export const GroupPage: React.FC<GroupPageProps> = ({ route }) => {
/>
</View>
)}
<Text>{formatDate(message?.created_at)}</Text>
<Text>{formatHour(message?.created_at)}</Text>
</View>
</View>
{message ? (

View File

@ -12,12 +12,15 @@ import { type DrawerNavigationProp } from '@react-navigation/drawer'
import RelaysPage from '../RelaysPage'
import ConfigPage from '../ConfigPage'
import QrReaderPage from '../QrReaderPage'
import { UserContext } from '../../Contexts/UserContext'
export const HomeNavigator: React.FC = () => {
const theme = useTheme()
const { t } = useTranslation('common')
const { logout } = React.useContext(UserContext)
const bottomSheetKeysRef = React.useRef<RBSheet>(null)
const bottomSheetRelaysRef = React.useRef<RBSheet>(null)
const bottomSheetLoginRef = React.useRef<RBSheet>(null)
const Stack = React.useMemo(() => createStackNavigator(), [])
const cardStyleInterpolator = React.useMemo(
() =>
@ -27,9 +30,13 @@ export const HomeNavigator: React.FC = () => {
[],
)
const onPressQuestion: (pageName: string) => void = (pageName) => {
pageName === 'Relays'
? bottomSheetRelaysRef.current?.open()
: bottomSheetKeysRef.current?.open()
if (pageName === 'Relays') {
bottomSheetRelaysRef.current?.open()
} else if (pageName === 'ProfileLoad') {
bottomSheetLoginRef.current?.open()
} else {
bottomSheetKeysRef.current?.open()
}
}
const BottomSheetKeys = React.useMemo(
@ -52,6 +59,45 @@ export const HomeNavigator: React.FC = () => {
[],
)
const BottomLogin = React.useMemo(
() => (
<View style={styles.bottomSheetKeysContainer}>
<View style={styles.drawerParagraph}>
<Text variant='headlineSmall'>{t('drawers.loginTitle')}</Text>
</View>
<View style={styles.drawerParagraph}>
<Text variant='bodyMedium' style={{ color: theme.colors.onSurfaceVariant }}>
{t('drawers.loginDescription')}
</Text>
</View>
<View style={styles.drawerParagraph}>
<Text variant='titleMedium'>{t('drawers.loginStep1Title')}</Text>
<Text variant='bodyMedium' style={{ color: theme.colors.onSurfaceVariant }}>
{t('drawers.loginStep1Description')}
</Text>
</View>
<View style={styles.drawerParagraph}>
<Text variant='titleMedium'>{t('drawers.loginStep2Title')}</Text>
<Text variant='bodyMedium' style={{ color: theme.colors.onSurfaceVariant }}>
{t('drawers.loginStep2Description')}
</Text>
</View>
<View style={styles.drawerParagraph}>
<Text variant='titleMedium'>{t('drawers.loginStep3Title')}</Text>
<Text variant='bodyMedium' style={{ color: theme.colors.onSurfaceVariant }}>
{t('drawers.loginStep3Description')}
</Text>
</View>
<View>
<Text variant='bodyMedium' style={{ color: theme.colors.onSurfaceVariant }}>
{t('drawers.loginskip')}
</Text>
</View>
</View>
),
[],
)
const BottomSheetRelays = React.useMemo(
() => (
<View>
@ -62,6 +108,21 @@ export const HomeNavigator: React.FC = () => {
[],
)
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 (
<>
<Stack.Navigator
@ -71,8 +132,15 @@ export const HomeNavigator: React.FC = () => {
cardStyleInterpolator,
header: ({ navigation, route, back }) => {
const leftAction: () => JSX.Element = () => {
if (back && route.name !== 'ProfileLoad') {
return <Appbar.BackAction onPress={() => navigation.goBack()} />
if (back) {
return (
<Appbar.BackAction
onPress={() => {
logout()
navigation.goBack()
}}
/>
)
} else if ((navigation as any as DrawerNavigationProp<any>).openDrawer) {
return (
<Appbar.Action
@ -117,38 +185,16 @@ export const HomeNavigator: React.FC = () => {
ref={bottomSheetKeysRef}
closeOnDragDown={true}
height={420}
customStyles={{
container: {
backgroundColor: theme.colors.background,
paddingTop: 16,
paddingRight: 16,
paddingBottom: 32,
paddingLeft: 16,
borderTopRightRadius: 28,
borderTopLeftRadius: 28,
},
}}
customStyles={bottomSheetStyles}
>
{BottomSheetKeys}
</RBSheet>
<RBSheet
ref={bottomSheetRelaysRef}
closeOnDragDown={true}
customStyles={{
container: {
backgroundColor: theme.colors.background,
paddingTop: 16,
paddingRight: 16,
paddingBottom: 32,
paddingLeft: 16,
borderTopRightRadius: 28,
borderTopLeftRadius: 28,
height: 'auto',
},
}}
>
<RBSheet ref={bottomSheetRelaysRef} closeOnDragDown={true} customStyles={bottomSheetStyles}>
{BottomSheetRelays}
</RBSheet>
<RBSheet ref={bottomSheetLoginRef} closeOnDragDown={true} customStyles={bottomSheetStyles}>
{BottomLogin}
</RBSheet>
</>
)
}
@ -171,12 +217,14 @@ const styles = StyleSheet.create({
justifyContent: 'flex-end',
},
bottomSheetKeysContainer: {
flex: 1,
justifyContent: 'space-between',
},
bold: {
fontWeight: 'bold',
},
drawerParagraph: {
marginBottom: 16,
},
})
export default HomeNavigator

View File

@ -38,7 +38,7 @@ import { useTranslation } from 'react-i18next'
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
import { useFocusEffect } from '@react-navigation/native'
import ProfileData from '../../../Components/ProfileData'
import { formatDate, handleInfinityScroll } from '../../../Functions/NativeFunctions'
import { handleInfinityScroll } from '../../../Functions/NativeFunctions'
export const ConversationsFeed: React.FC = () => {
const initialPageSize = 14
@ -154,7 +154,7 @@ export const ConversationsFeed: React.FC = () => {
</View>
<View style={styles.contactInfo}>
<View style={styles.contactDate}>
<Text>{formatDate(item?.created_at)}</Text>
<Text>{formatHour(item?.created_at, false)}</Text>
{item.pubkey !== publicKey && !item.read && <Badge size={16}></Badge>}
</View>
</View>

View File

@ -109,7 +109,7 @@ export const HomeFeed: React.FC<HomeFeedProps> = ({ navigation }) => {
return (
<View>
<Tabs
tabs={['globalFeed', 'myFeed', 'zaps', 'bookmarks']}
tabs={['myFeed', 'globalFeed', 'zaps', 'bookmarks']}
setActiveTab={setActiveTab}
defaultTab='myFeed'
/>

View File

@ -14,10 +14,9 @@ import { Kind } from 'nostr-tools'
import { UserContext } from '../../../Contexts/UserContext'
import { ActivityIndicator, Button, Divider, Text, useTheme } from 'react-native-paper'
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
import { useTranslation } from 'react-i18next'
import { navigate } from '../../../lib/Navigation'
import { useFocusEffect } from '@react-navigation/native'
import { format, formatRelative, fromUnixTime, getUnixTime } from 'date-fns'
import { format, fromUnixTime, getUnixTime } from 'date-fns'
import { FlashList, type ListRenderItem } from '@shopify/flash-list'
import { getETags } from '../../../Functions/RelayFunctions/Events'
import { getReactions, type Reaction } from '../../../Functions/DatabaseFunctions/Reactions'
@ -25,10 +24,11 @@ import { getUsers, type User } from '../../../Functions/DatabaseFunctions/Users'
import { username } from '../../../Functions/RelayFunctions/Users'
import { TouchableWithoutFeedback } from 'react-native-gesture-handler'
import { getUserZaps, type Zap } from '../../../Functions/DatabaseFunctions/Zaps'
import { handleInfinityScroll } from '../../../Functions/NativeFunctions'
import { formatDate, handleInfinityScroll } from '../../../Functions/NativeFunctions'
import { useTranslation } from 'react-i18next'
export const NotificationsFeed: React.FC = () => {
const initialLimitDate = React.useMemo(() => getUnixTime(new Date()) - 43200, [])
const initialLimitDate = React.useMemo(() => getUnixTime(new Date()) - 86400, [])
const theme = useTheme()
const { t } = useTranslation('common')
const { database, setNotificationSeenAt, pushedTab, getSatoshiSymbol } = useContext(AppContext)
@ -238,7 +238,6 @@ export const NotificationsFeed: React.FC = () => {
const renderItem: ListRenderItem<Note | Reaction | Zap> = ({ item }) => {
const date = fromUnixTime(item.created_at)
const { user, icon, iconColor, description, content, eventId } = generateItemVariables(item)
return (
@ -265,9 +264,7 @@ export const NotificationsFeed: React.FC = () => {
</Text>
</View>
<View style={styles.itemCardDates}>
<Text style={styles.itemCardDatesText}>
{formatRelative(date, new Date()).split(' at ')[0]}
</Text>
<Text style={styles.itemCardDatesText}>{formatDate(item.created_at, false)}</Text>
<Text style={styles.itemCardDatesText}>{format(date, 'HH:mm')}</Text>
</View>
</View>

View File

@ -63,6 +63,23 @@ export const ProfileCreatePage: React.FC<ProfileCreatePageProps> = ({ navigation
}
}
const publishRelays: () => void = () => {
if (publicKey) {
const activeRelays = relays.filter(
(relay) => relay?.active && (!relay.resilient || relay.resilient < 0),
)
const tags: string[][] = activeRelays.map((relay) => ['r', relay.url ?? '', relay.mode ?? ''])
const event: Event = {
content: '',
created_at: getUnixTime(new Date()),
kind: 10002,
pubkey: publicKey,
tags,
}
sendEvent(event)
}
}
const onPress: () => void = () => {
if (step > 1) {
if (publicKey) {
@ -77,6 +94,7 @@ export const ProfileCreatePage: React.FC<ProfileCreatePageProps> = ({ navigation
}
if (validConfirmation()) {
setPrivateKey(key)
publishRelays()
setUserState('ready')
} else {
setShowNotification('wrongWords')
@ -88,6 +106,7 @@ export const ProfileCreatePage: React.FC<ProfileCreatePageProps> = ({ navigation
const onPressSkip: () => void = () => {
setPrivateKey(key)
publishRelays()
setUserState('ready')
}

View File

@ -3,20 +3,22 @@ import { RelayPoolContext } from '../../../Contexts/RelayPoolContext'
import { Kind } from 'nostr-tools'
import { UserContext } from '../../../Contexts/UserContext'
import { StyleSheet, View } from 'react-native'
import Logo from '../../../Components/Logo'
import { ActivityIndicator, Button, Text } from 'react-native-paper'
import { ActivityIndicator, Button, Card, Divider, Text, useTheme } from 'react-native-paper'
import { useTranslation } from 'react-i18next'
import { AppContext } from '../../../Contexts/AppContext'
import {
getRelayMetadata,
type RelayMetadata,
} from '../../../Functions/DatabaseFunctions/RelayMetadatas'
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
interface FirstStepProps {
nextStep: () => void
skip: () => void
}
export const FirstStep: React.FC<FirstStepProps> = ({ nextStep }) => {
export const FirstStep: React.FC<FirstStepProps> = ({ nextStep, skip }) => {
const theme = useTheme()
const { t } = useTranslation('common')
const { database } = useContext(AppContext)
const {
@ -28,7 +30,7 @@ export const FirstStep: React.FC<FirstStepProps> = ({ nextStep }) => {
addRelayItem,
createRandomRelays,
} = useContext(RelayPoolContext)
const { publicKey, reloadUser, setUserState, name } = useContext(UserContext)
const { publicKey, reloadUser, name } = useContext(UserContext)
const [profileFound, setProfileFound] = useState<boolean>(false)
const [activeRelays, setActiveRelays] = React.useState<number>()
const [metadata, setMetadata] = React.useState<RelayMetadata>()
@ -90,40 +92,73 @@ export const FirstStep: React.FC<FirstStepProps> = ({ nextStep }) => {
return (
<View style={styles.container}>
<View style={styles.main}>
<View>
<View style={styles.loadingProfile}>
<Text variant='titleMedium'>{t('profileLoadPage.connectedRelays')}</Text>
<Text variant='titleMedium' style={{ color: '#7ADC70' }}>
{activeRelays}
<Text variant='titleMedium'>{t('profileLoadPage.connectingRandomRelays')}</Text>
</View>
<View style={styles.loadingProfile}>
<Text style={{ color: theme.colors.onSurfaceVariant }}>
{t('profileLoadPage.connectingRandomRelaysDescription')}
</Text>
</View>
<View style={styles.logo}>
<Logo onlyIcon size='medium' />
</View>
<Card style={styles.card}>
<Card.Content>
<View style={styles.loadingProfile}>
<Text>{t('profileLoadPage.randomRelays')}</Text>
<Text style={{ color: '#7ADC70' }}>
{t('profileLoadPage.connectedRelays', { activeRelays })}
</Text>
</View>
<View style={styles.loadingProfile}>
<Text>{t('profileLoadPage.myProfile')}</Text>
{profileFound ? (
<MaterialCommunityIcons
style={{ color: '#7ADC70' }}
name='check-circle-outline'
size={20}
/>
) : (
<ActivityIndicator animating={true} size={20} />
)}
</View>
<View style={styles.loadingProfile}>
<Text>{t('profileLoadPage.myRelays')}</Text>
{metadata ? (
<MaterialCommunityIcons
style={{ color: '#7ADC70' }}
name='check-circle-outline'
size={20}
/>
) : (
<ActivityIndicator animating={true} size={20} />
)}
</View>
<Divider style={styles.loadingProfile} />
<View style={styles.loadingProfile}>
<Text>{t('profileLoadPage.relaysTooLong')}</Text>
</View>
<View>
<Button onPress={reconnectRelays}>{t('profileLoadPage.relaysReconnect')}</Button>
</View>
</Card.Content>
</Card>
<View style={styles.loadingProfile}>
{!profileFound && <ActivityIndicator animating={true} style={styles.activityIndicator} />}
<Text variant='titleMedium' style={styles.center}>
{profileFound
? t('profileLoadPage.foundProfile')
: t('profileLoadPage.searchingProfile')}
<Text style={{ color: theme.colors.onSurfaceVariant }} variant='titleMedium'>
{t('profileLoadPage.searchContacts')}
</Text>
</View>
<View style={styles.loadingProfile}>
{!metadata && <ActivityIndicator animating={true} style={styles.activityIndicator} />}
<Text variant='titleMedium' style={styles.center}>
{metadata ? t('profileLoadPage.foundRelays') : t('profileLoadPage.searchingRelays')}
<Text style={{ color: theme.colors.onSurfaceVariant }} variant='titleMedium'>
{t('profileLoadPage.searchContactsRelays')}
</Text>
</View>
</View>
<View style={styles.buttons}>
<Button mode='outlined' onPress={() => reconnectRelays()}>
{t('profileLoadPage.reconnectOther')}
<Button style={styles.button} mode='outlined' onPress={skip}>
{t('profileLoadPage.skip')}
</Button>
<Button mode='contained' onPress={finish} disabled={!profileFound}>
{t('profileLoadPage.nextStep')}
</Button>
<Button mode='outlined' onPress={() => setUserState('ready')}>
{t('profileLoadPage.home')}
{t('profileLoadPage.continue')}
</Button>
</View>
</View>
@ -136,13 +171,12 @@ const styles = StyleSheet.create({
justifyContent: 'space-between',
flex: 1,
},
main: {
height: 160,
},
buttons: {
height: 160,
justifyContent: 'space-between',
},
button: {
marginBottom: 16,
},
logo: {
justifyContent: 'center',
alignContent: 'center',
@ -152,13 +186,13 @@ const styles = StyleSheet.create({
alignContent: 'center',
textAlign: 'center',
},
loadingProfile: {
justifyContent: 'center',
alignContent: 'center',
flexDirection: 'row',
card: {
marginBottom: 16,
},
activityIndicator: {
paddingRight: 16,
loadingProfile: {
flexDirection: 'row',
marginBottom: 16,
justifyContent: 'space-between',
},
})

View File

@ -1,34 +1,25 @@
import { Kind } from 'nostr-tools'
import React, { useContext, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { type Relay } from '../../../Functions/DatabaseFunctions/Relays'
import {
ActivityIndicator,
FlatList,
type ListRenderItem,
ScrollView,
StyleSheet,
View,
} from 'react-native'
import { Button, Divider, List, Text } from 'react-native-paper'
import { ActivityIndicator, StyleSheet, View } from 'react-native'
import { Button, Card, Text, useTheme } from 'react-native-paper'
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
import Logo from '../../../Components/Logo'
import { AppContext } from '../../../Contexts/AppContext'
import { RelayPoolContext } from '../../../Contexts/RelayPoolContext'
import { UserContext } from '../../../Contexts/UserContext'
import { getUsers, type User } from '../../../Functions/DatabaseFunctions/Users'
import { relayToColor } from '../../../Functions/NativeFunctions'
interface SecondStepProps {
nextStep: () => void
skip: () => void
}
export const SecondStep: React.FC<SecondStepProps> = ({ nextStep }) => {
export const SecondStep: React.FC<SecondStepProps> = ({ nextStep, skip }) => {
const theme = useTheme()
const { t } = useTranslation('common')
const { database } = useContext(AppContext)
const { relayPool, relayPoolReady, lastEventId, relays, updateRelayItem } =
useContext(RelayPoolContext)
const { publicKey, setUserState } = useContext(UserContext)
const { relayPool, relayPoolReady, lastEventId, relays } = useContext(RelayPoolContext)
const { publicKey } = useContext(UserContext)
const [contactsCount, setContactsCount] = useState<number>()
React.useEffect(() => {
@ -88,93 +79,57 @@ export const SecondStep: React.FC<SecondStepProps> = ({ nextStep }) => {
}
}
const activeGlobalFeedRelay: (relay: Relay) => void = (relay) => {
relay.active = 1
relay.global_feed = 1
updateRelayItem(relay)
}
const desactiveGlobalFeedRelay: (relay: Relay) => void = (relay) => {
relay.global_feed = 0
updateRelayItem(relay)
}
const renderItem: ListRenderItem<Relay> = ({ item, index }) => {
return (
<List.Item
key={index}
title={item.url.replace('wss://', '').replace('ws://', '')}
right={() => (
<Button
style={styles.relayButton}
mode={item.global_feed !== undefined && item.global_feed > 0 ? 'contained' : 'outlined'}
onPress={() => {
item.global_feed ? desactiveGlobalFeedRelay(item) : activeGlobalFeedRelay(item)
}}
>
{t('relaysPage.globalFeed')}
</Button>
)}
left={() => (
<MaterialCommunityIcons
style={styles.relayColor}
name='circle'
color={relayToColor(item.url)}
/>
)}
/>
)
}
return (
<View style={styles.container}>
<View>
<View style={styles.loadingProfile}>
<Text variant='titleMedium'>{t('profileLoadPage.connectedRelays')}</Text>
<Text variant='titleMedium' style={{ color: '#7ADC70' }}>
{relays.length}
<Text style={{ color: theme.colors.onSurfaceVariant }} variant='titleMedium'>
{t('profileLoadPage.connectingRandomRelays')}
</Text>
</View>
<View style={styles.logo}>
<Logo onlyIcon size='medium' />
<MaterialCommunityIcons
style={{ color: '#7ADC70' }}
name='check-circle-outline'
size={20}
/>
</View>
<View style={styles.loadingProfile}>
{!contactsCount && (
<ActivityIndicator animating={true} style={styles.activityIndicator} />
)}
<Text variant='titleMedium' style={styles.center}>
{contactsCount
? t('profileLoadPage.foundContacts', { contactsCount })
: t('profileLoadPage.searchingContacts')}
<Text variant='titleMedium'>{t('profileLoadPage.searchContacts')}</Text>
</View>
<View style={styles.loadingProfile}>
<Text style={{ color: theme.colors.onSurfaceVariant }}>
{t('profileLoadPage.searchContactsDescription')}
</Text>
</View>
<View style={styles.list}>
<View style={styles.titleWrapper}>
<Text style={styles.title} variant='titleMedium'>
{t('relaysPage.myList')}
</Text>
<Divider />
</View>
<ScrollView horizontal={false}>
<FlatList
showsVerticalScrollIndicator={false}
data={relays.sort((a, b) => {
if (a.url > b.url) return 1
if (a.url < b.url) return -1
return 0
})}
renderItem={renderItem}
ItemSeparatorComponent={Divider}
/>
</ScrollView>
<Card style={styles.card}>
<Card.Content>
<View style={styles.loadingProfile}>
<Text>{t('profileLoadPage.myRelays')}</Text>
<Text style={{ color: '#7ADC70' }}>
{t('profileLoadPage.connectedRelays', { activeRelays: relays.length })}
</Text>
</View>
<View style={styles.loadingProfile}>
<Text>{t('profileLoadPage.contactsCount')}</Text>
{contactsCount ? (
<Text>{contactsCount}</Text>
) : (
<ActivityIndicator animating={true} size={20} />
)}
</View>
</Card.Content>
</Card>
<View style={styles.loadingProfile}>
<Text style={{ color: theme.colors.onSurfaceVariant }} variant='titleMedium'>
{t('profileLoadPage.searchContactsRelays')}
</Text>
</View>
</View>
<View style={styles.buttons}>
<Button mode='contained' onPress={nextStep} disabled={!contactsCount}>
{t('profileLoadPage.nextStep')}
<Button style={styles.button} mode='outlined' onPress={skip}>
{t('profileLoadPage.skip')}
</Button>
<Button mode='outlined' onPress={() => setUserState('ready')}>
{t('profileLoadPage.home')}
<Button mode='contained' onPress={nextStep} disabled={contactsCount === undefined}>
{t('profileLoadPage.continue')}
</Button>
</View>
</View>
@ -188,49 +143,28 @@ const styles = StyleSheet.create({
flex: 1,
},
buttons: {
height: 100,
justifyContent: 'space-between',
},
button: {
marginBottom: 16,
},
logo: {
justifyContent: 'center',
alignContent: 'center',
flexDirection: 'row',
},
list: {
maxHeight: 400,
},
center: {
alignContent: 'center',
textAlign: 'center',
},
card: {
marginBottom: 16,
},
loadingProfile: {
justifyContent: 'center',
alignContent: 'center',
flexDirection: 'row',
},
activityIndicator: {
paddingRight: 16,
},
titleWrapper: {
marginBottom: 4,
marginTop: 24,
},
title: {
paddingLeft: 16,
paddingRight: 16,
marginBottom: 8,
flexDirection: 'row',
marginBottom: 16,
justifyContent: 'space-between',
},
relayActionButtons: {
flexDirection: 'row',
},
relayColor: {
paddingTop: 9,
},
relayButton: {
marginRight: -22,
},
})
export default SecondStep

View File

@ -1,9 +1,8 @@
import React, { useContext, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { FlatList, type ListRenderItem, ScrollView, StyleSheet, View } from 'react-native'
import { Button, Divider, List, Text } from 'react-native-paper'
import { type ListRenderItem, StyleSheet, View, FlatList } from 'react-native'
import { Button, Card, Divider, List, Text, useTheme } from 'react-native-paper'
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
import Logo from '../../../Components/Logo'
import { AppContext } from '../../../Contexts/AppContext'
import { RelayPoolContext } from '../../../Contexts/RelayPoolContext'
import { UserContext } from '../../../Contexts/UserContext'
@ -17,9 +16,11 @@ import { getContactsRelays } from '../../../Functions/RelayFunctions/Metadata'
interface ThirdStepProps {
nextStep: () => void
skip: () => void
}
export const ThirdStep: React.FC<ThirdStepProps> = ({ nextStep }) => {
export const ThirdStep: React.FC<ThirdStepProps> = ({ nextStep, skip }) => {
const theme = useTheme()
const { t } = useTranslation('common')
const { database } = useContext(AppContext)
const { relayPool, relayPoolReady, lastEventId, relays, addRelayItem } =
@ -28,18 +29,21 @@ export const ThirdStep: React.FC<ThirdStepProps> = ({ nextStep }) => {
const [asignation, setAsignation] = useState<string[]>()
const [contactsRelays, setContactsRelays] = useState<RelayMetadata[]>([])
React.useEffect(() => {
loadPetsRelays()
}, [])
React.useEffect(() => {
const calculateRelays: () => void = () => {
if (database) {
getAllRelayMetadata(database).then((relayMetadata) => {
setContactsRelays(relayMetadata)
getContactsRelays(relays, relayMetadata).then(setAsignation)
})
}
}, [lastEventId])
}
React.useEffect(() => {
loadPetsRelays()
calculateRelays()
}, [])
React.useEffect(calculateRelays, [lastEventId])
const loadPetsRelays: () => void = () => {
if (database && publicKey && relayPoolReady) {
@ -86,48 +90,56 @@ export const ThirdStep: React.FC<ThirdStepProps> = ({ nextStep }) => {
<View style={styles.container}>
<View>
<View style={styles.loadingProfile}>
<Text variant='titleMedium'>{t('profileLoadPage.connectedRelays')}</Text>
<Text variant='titleMedium' style={{ color: '#7ADC70' }}>
{relays.length}
<Text style={{ color: theme.colors.onSurfaceVariant }} variant='titleMedium'>
{t('profileLoadPage.connectingRandomRelays')}
</Text>
</View>
<View style={styles.logo}>
<Logo onlyIcon size='medium' />
<MaterialCommunityIcons
style={{ color: '#7ADC70' }}
name='check-circle-outline'
size={20}
/>
</View>
<View style={styles.loadingProfile}>
<Text variant='titleMedium' style={styles.center}>
{t('profileLoadPage.contactRelaysDescription')}
<Text style={{ color: theme.colors.onSurfaceVariant }} variant='titleMedium'>
{t('profileLoadPage.searchContacts')}
</Text>
<MaterialCommunityIcons
style={{ color: '#7ADC70' }}
name='check-circle-outline'
size={20}
/>
</View>
<View style={styles.loadingProfile}>
<Text variant='titleMedium'>{t('profileLoadPage.contactsRelays')}</Text>
<Text variant='titleMedium' style={{ color: '#7ADC70' }}>
{contactsRelays.length}
<Text variant='titleMedium'>{t('profileLoadPage.searchContactsRelays')}</Text>
</View>
<View style={styles.loadingProfile}>
<Text style={{ color: theme.colors.onSurfaceVariant }}>
{t('profileLoadPage.searchContactsRelaysDescription')}
</Text>
</View>
<View style={styles.list}>
<View style={styles.titleWrapper}>
<Text style={styles.title} variant='titleMedium'>
{t('profileLoadPage.contactRelays')}
</Text>
<Divider />
</View>
<ScrollView horizontal={false}>
<Card style={styles.card}>
<Card.Content>
<View style={styles.loadingProfile}>
<Text>{t('profileLoadPage.contatcsRelays')}</Text>
<Text style={{ color: '#7ADC70' }}>
{t('profileLoadPage.contatcsRelaysCount', { activeRelays: contactsRelays.length })}
</Text>
</View>
<FlatList
showsVerticalScrollIndicator={false}
data={asignation}
renderItem={renderItem}
ItemSeparatorComponent={Divider}
/>
</ScrollView>
</View>
</Card.Content>
</Card>
</View>
<View style={styles.buttons}>
<Button mode='contained' onPress={connect}>
{t('profileLoadPage.connect')}
<Button style={styles.button} mode='outlined' onPress={skip}>
{t('profileLoadPage.skip')}
</Button>
<Button mode='outlined' onPress={() => setUserState('ready')}>
{t('profileLoadPage.home')}
<Button mode='contained' onPress={connect} disabled={contactsRelays === undefined}>
{t('profileLoadPage.connectAccess')}
</Button>
</View>
</View>
@ -141,55 +153,32 @@ const styles = StyleSheet.create({
flex: 1,
},
buttons: {
height: 100,
justifyContent: 'space-between',
},
button: {
marginBottom: 16,
},
logo: {
justifyContent: 'center',
alignContent: 'center',
flexDirection: 'row',
},
list: {
maxHeight: 450,
},
center: {
alignContent: 'center',
textAlign: 'center',
},
card: {
marginBottom: 16,
},
loadingProfile: {
justifyContent: 'center',
alignContent: 'center',
flexDirection: 'row',
},
activityIndicator: {
paddingRight: 16,
},
titleWrapper: {
marginBottom: 4,
marginTop: 24,
},
title: {
paddingLeft: 16,
paddingRight: 16,
marginBottom: 8,
flexDirection: 'row',
marginBottom: 16,
justifyContent: 'space-between',
},
relayItem: {
paddingLeft: 16,
paddingRight: 16,
},
relayButtons: {
paddingBottom: 16,
flexDirection: 'row',
justifyContent: 'space-between',
},
relayButton: {
marginRight: 16,
},
relayActionButtons: {
flexDirection: 'row',
},
relayColor: {
paddingTop: 9,
},

View File

@ -1,14 +1,22 @@
import React, { useContext, useState } from 'react'
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
import { StyleSheet, View } from 'react-native'
import { useFocusEffect } from '@react-navigation/native'
import { useFocusEffect, useTheme } from '@react-navigation/native'
import FirstStep from './FirstStep'
import SecondStep from './SecondStep'
import ThirdStep from './ThirdStep'
import RBSheet from 'react-native-raw-bottom-sheet'
import { Button, Text } from 'react-native-paper'
import { useTranslation } from 'react-i18next'
import { UserContext } from '../../Contexts/UserContext'
export const ProfileLoadPage: React.FC = () => {
const theme = useTheme()
const { t } = useTranslation('common')
const { setUserState } = useContext(UserContext)
const { relayPool } = useContext(RelayPoolContext)
const [step, setStep] = useState<number>(0)
const bottomSkipRef = React.useRef<RBSheet>(null)
useFocusEffect(
React.useCallback(() => {
@ -20,11 +28,48 @@ export const ProfileLoadPage: React.FC = () => {
setStep((prev) => prev + 1)
}
const skip: () => void = () => {
bottomSkipRef.current?.open()
}
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 (
<View style={styles.container}>
{step === 0 && <FirstStep nextStep={nextStep} />}
{step === 1 && <SecondStep nextStep={nextStep} />}
{step === 2 && <ThirdStep nextStep={nextStep} />}
{step === 0 && <FirstStep nextStep={nextStep} skip={skip} />}
{step === 1 && <SecondStep nextStep={nextStep} skip={skip} />}
{step === 2 && <ThirdStep nextStep={nextStep} skip={skip} />}
<RBSheet ref={bottomSkipRef} closeOnDragDown={true} customStyles={bottomSheetStyles}>
<View style={styles.drawerParagraph}>
<Text variant='headlineSmall'>{t('profileLoadPage.skipTitle')}</Text>
</View>
<View style={styles.drawerParagraph}>
<Text variant='bodyMedium' style={{ color: theme.colors.onSurfaceVariant }}>
{t('profileLoadPage.skipDescription')}
</Text>
</View>
<View style={styles.buttons}>
<Button style={styles.button} mode='outlined' onPress={() => setUserState('ready')}>
{t('profileLoadPage.skip')}
</Button>
<Button mode='contained' onPress={() => bottomSkipRef.current?.close()}>
{t('profileLoadPage.continueLogin')}
</Button>
</View>
</RBSheet>
</View>
)
}
@ -35,6 +80,15 @@ const styles = StyleSheet.create({
justifyContent: 'space-between',
height: '100%',
},
drawerParagraph: {
marginBottom: 16,
},
buttons: {
justifyContent: 'space-between',
},
button: {
marginBottom: 16,
},
})
export default ProfileLoadPage

View File

@ -232,10 +232,8 @@ export const RelaysPage: React.FC = () => {
{t('relaysPage.active')}
</Chip>
<Chip
compact
mode={
item.global_feed !== undefined && item.global_feed > 0 ? 'flat' : 'outlined'
}
compact
mode={item.global_feed !== undefined && item.global_feed > 0 ? 'flat' : 'outlined'}
style={styles.relayButton}
onPress={() => {
item.global_feed ? desactiveGlobalFeedRelay(item) : activeGlobalFeedRelay(item)

View File

@ -6,7 +6,7 @@ import { Kind } from 'nostr-tools'
import { decode } from 'nostr-tools/nip19'
import * as React from 'react'
import { StyleSheet, View } from 'react-native'
import { Text, TextInput, TouchableRipple, useTheme } from 'react-native-paper'
import { ActivityIndicator, Text, TextInput, TouchableRipple, useTheme } from 'react-native-paper'
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
import NoteCard from '../../Components/NoteCard'
import ProfileData from '../../Components/ProfileData'
@ -209,6 +209,13 @@ export const SearchPage: React.FC<SearchPageProps> = ({ route }) => {
data={resultsNotes}
renderItem={renderItemNote}
horizontal={false}
ListFooterComponent={
/^#.*/.test(searchInput) ? (
<ActivityIndicator style={styles.loading} animating={true} />
) : (
<></>
)
}
/>
)}
{searchInput !== '' && /^@.*/.test(searchInput) && (

View File

@ -174,8 +174,6 @@ export const SendPage: React.FC<SendPageProps> = ({ route }) => {
value={content}
onChangeText={onChangeText}
scrollEnabled
// cursorColor={theme.colors.inverseOnSurface}
// selectionColor={theme.colors.inverseOnSurface}
/>
</View>
</ScrollView>