NIP-65 Publish relay list

This commit is contained in:
KoalaSat 2023-02-16 23:32:02 +01:00
parent fd711c0c35
commit b6532b83e1
No known key found for this signature in database
GPG Key ID: 2F7F61C6146AB157
21 changed files with 307 additions and 121 deletions

View File

@ -29,5 +29,4 @@ jobs:
~/go/bin/noscl relay add "wss://nostr.ono.re"
~/go/bin/noscl relay add "wss://relay.grunch.dev"
~/go/bin/noscl relay add "wss://nostr.developer.li"
~/go/bin/noscl publish '${{ github.event.release.body }}'
~/go/bin/noscl publish ${{ github.event.release.body }}
~/go/bin/noscl publish "${{ github.event.release.body }}"

View File

@ -71,7 +71,9 @@ public class Event {
} else if (kind.equals("43")) {
hideGroupMessage(database);
} else if (kind.equals("44")) {
blockUser(database);
muteUser(database);
} else if (kind.equals("1002")) {
saveRelays(database);
}
} catch (JSONException e) {
e.printStackTrace();
@ -209,13 +211,14 @@ public class Event {
database.replace("nostros_notes", null, values);
}
protected void blockUser(SQLiteDatabase database) throws JSONException {
protected void muteUser(SQLiteDatabase database) throws JSONException {
JSONArray pTags = filterTags("p");
String groupId = pTags.getJSONArray(0).getString(1);
String query = "SELECT id FROM nostros_users WHERE id = ?";
@SuppressLint("Recycle") Cursor cursor = database.rawQuery(query, new String[] {groupId});
if (cursor.getCount() == 0) {
} else {
ContentValues values = new ContentValues();
values.put("muted_groups", 1);
String whereClause = "id = ?";
@ -409,7 +412,7 @@ public class Event {
values.put("valid_nip05", validateNip05(nip05) ? 1 : 0);
values.put("blocked", 0);
database.insert("nostros_users", null, values);
} else if (cursor.moveToFirst() && (cursor.isNull(0) || created_at > cursor.getInt(0))) {
} else if (cursor.moveToFirst() && created_at > cursor.getInt(0)) {
if (cursor.getInt(1) == 0 || !cursor.getString(2).equals(nip05)) {
values.put("valid_nip05", validateNip05(nip05) ? 1 : 0);
}
@ -422,23 +425,71 @@ public class Event {
}
protected void savePets(SQLiteDatabase database) throws JSONException {
String queryLast = "SELECT pet_at FROM nostros_users ORDER BY pet_at DESC LIMIT 1";
Cursor cursorLast = database.rawQuery(queryLast, new String[] {});
if (cursorLast.moveToFirst() && created_at > cursorLast.getInt(0)) {
ContentValues valuesIntial = new ContentValues();
valuesIntial.put("contact", 0);
String whereClauseInitial = "id = ?";
database.update("nostros_users", valuesIntial, whereClauseInitial, new String[]{});
for (int i = 0; i < tags.length(); ++i) {
JSONArray tag = tags.getJSONArray(i);
String petId = tag.getString(1);
String name = "";
if (tag.length() >= 4) {
name = tag.getString(3);
}
String query = "SELECT * FROM nostros_users WHERE id = ?";
Cursor cursor = database.rawQuery(query, new String[] {petId});
ContentValues values = new ContentValues();
values.put("pet_at", created_at);
values.put("contact", 1);
values.put("name", name);
values.put("blocked", 0);
if (cursor.getCount() == 0) {
values.put("id", petId);
database.insert("nostros_users", null, values);
} else {
String whereClause = "id = ?";
String[] whereArgs = new String[] {
petId
};
database.update("nostros_users", values, whereClause, whereArgs);
}
}
}
}
protected void saveRelays(SQLiteDatabase database) throws JSONException {
for (int i = 0; i < tags.length(); ++i) {
JSONArray tag = tags.getJSONArray(i);
String petId = tag.getString(1);
String name = "";
if (tag.length() >= 4) {
name = tag.getString(3);
String url = tag.getString(1);
String mode = "";
if (tag.length() > 1) {
mode = tag.getString(2);
}
String query = "SELECT * FROM nostros_users WHERE id = ?";
Cursor cursor = database.rawQuery(query, new String[] {petId});
String query = "SELECT updated_at FROM nostros_relays WHERE url = ?";
Cursor cursor = database.rawQuery(query, new String[] {url});
ContentValues values = new ContentValues();
values.put("url", url);
values.put("mode", mode);
if (cursor.getCount() == 0) {
ContentValues values = new ContentValues();
values.put("id", petId);
values.put("name", name);
values.put("contact", true);
values.put("blocked", 0);
values.put("pet_at", created_at);
database.insert("nostros_users", null, values);
values.put("active", 0);
values.put("global_feed", 0);
values.put("manual", 1);
database.insert("nostros_relays", null, values);
} else if (cursor.moveToFirst() && created_at > cursor.getInt(0)) {
values.put("updated_at", created_at);
String whereClause = "url = ?";
String[] whereArgs = new String[] {
url
};
database.update("nostros_relays", values, whereClause, whereArgs);
}
}
}

View File

@ -173,6 +173,10 @@ public class DatabaseModule {
database.execSQL("ALTER TABLE nostros_group_messages ADD COLUMN read INT DEFAULT 0;");
database.execSQL("ALTER TABLE nostros_group_messages ADD COLUMN user_mentioned INT DEFAULT 0;");
} catch (SQLException e) { }
try {
database.execSQL("ALTER TABLE updated_at ADD COLUMN mode INT DEFAULT 0;");
database.execSQL("ALTER TABLE nostros_relays ADD COLUMN mode TEXT;");
} catch (SQLException e) { }
}
public void saveEvent(JSONObject data, String userPubKey, String relayUrl) throws JSONException {

View File

@ -27,6 +27,12 @@ export const MenuItems: React.FC = () => {
const { t } = useTranslation('common')
const theme = useTheme()
const [activerelays, setActiveRelays] = React.useState<number>(0)
React.useEffect(() => {
setActiveRelays(relays.filter((relay) => relay.active).length)
}, [relays])
const onPressLogout: () => void = () => {
logout()
}
@ -110,12 +116,12 @@ export const MenuItems: React.FC = () => {
onPress={() => onPressItem('relays', 0)}
onTouchEnd={() => setDrawerItemIndex(-1)}
right={() =>
relays.length < 1 ? (
activerelays < 1 ? (
<Text style={{ color: theme.colors.error }}>{t('menuItems.notConnected')}</Text>
) : (
<Text style={{ color: theme.colors.inversePrimary }}>
<Text style={{ color: '#7ADC70' }}>
{t('menuItems.connectedRelays', {
number: relays.filter((relay) => relay.active).length,
number: activerelays,
})}
</Text>
)

View File

@ -1,7 +1,7 @@
import { t } from 'i18next'
import * as React from 'react'
import { StyleSheet, View, ListRenderItem, Switch, FlatList } from 'react-native'
import { IconButton, List, Snackbar, Text, useTheme } from 'react-native-paper'
import { Button, IconButton, List, Snackbar, Text, useTheme } from 'react-native-paper'
import { AppContext } from '../../Contexts/AppContext'
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
import { UserContext } from '../../Contexts/UserContext'
@ -10,6 +10,7 @@ import {
getUser,
updateUserBlock,
updateUserContact,
updateUserMutesGroups,
User,
} from '../../Functions/DatabaseFunctions/Users'
import { populatePets, username } from '../../Functions/RelayFunctions/Users'
@ -22,6 +23,8 @@ import { relayToColor } from '../../Functions/NativeFunctions'
import { Relay } from '../../Functions/DatabaseFunctions/Relays'
import ProfileShare from '../ProfileShare'
import { ScrollView } from 'react-native-gesture-handler'
import { Kind } from 'nostr-tools'
import { getUnixTime } from 'date-fns'
interface ProfileActionsProps {
user: User
@ -40,10 +43,12 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({
const { relayPool, updateRelayItem } = React.useContext(RelayPoolContext)
const [isContact, setIsContact] = React.useState<boolean>()
const [isBlocked, setIsBlocked] = React.useState<boolean>()
const [isMuted, setIsMuted] = React.useState<boolean>()
const [showNotification, setShowNotification] = React.useState<undefined | string>()
const [showNotificationRelay, setShowNotificationRelay] = React.useState<undefined | string>()
const bottomSheetRelaysRef = React.useRef<RBSheet>(null)
const bottomSheetShareRef = React.useRef<RBSheet>(null)
const bottomSheetMuteRef = React.useRef<RBSheet>(null)
const [userRelays, setUserRelays] = React.useState<NoteRelay[]>([])
const [openLn, setOpenLn] = React.useState<boolean>(false)
@ -52,6 +57,27 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({
loadRelays()
}, [])
const muteUser: () => void = () => {
if (publicKey && relayPool && database && user.id) {
relayPool
?.sendEvent({
content: '',
created_at: getUnixTime(new Date()),
kind: Kind.ChannelMuteUser,
pubkey: publicKey,
tags: [['p', user.id]],
})
.then(() => {
if (database) {
updateUserMutesGroups(database, user.id, true).then(() => {
setIsMuted(true)
bottomSheetMuteRef.current?.close()
})
}
})
}
}
const loadRelays: () => void = () => {
if (database) {
getUserRelays(database, user.id).then((results) => {
@ -69,6 +95,7 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({
setUser(result)
setIsContact(result.contact)
setIsBlocked(result.blocked !== undefined && result.blocked > 0)
setIsMuted(result.muted_groups !== undefined && result.muted_groups > 0)
} else if (user.id === publicKey) {
setUser({
id: publicKey,
@ -203,12 +230,13 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({
<View style={styles.mainLayout}>
<View style={styles.actionButton}>
<IconButton
icon={user?.blocked && user?.blocked > 0 ? 'account-cancel' : 'account-cancel-outline'}
icon='account-cancel-outline'
iconColor={isBlocked ? theme.colors.error : theme.colors.onSecondaryContainer}
size={28}
onPress={onChangeBlockUser}
/>
<Text>
{t(user?.blocked && user?.blocked > 0 ? 'profileCard.unblock' : 'profileCard.block')}
<Text style={isBlocked ? { color: theme.colors.error } : {}}>
{t(isBlocked ? 'profileCard.blocked' : 'profileCard.block')}
</Text>
</View>
<View style={styles.actionButton}>
@ -228,6 +256,20 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({
<Text>{t('profileCard.relaysTitle')}</Text>
</View>
</View>
<View style={styles.mainLayout}>
<View style={styles.actionButton}>
<IconButton
icon={isMuted ? 'volume-off' : 'volume-high'}
iconColor={isMuted ? theme.colors.error : theme.colors.onSecondaryContainer}
size={28}
onPress={() => !isMuted && bottomSheetMuteRef.current?.open()}
disabled={user.id === publicKey}
/>
<Text style={isMuted ? { color: theme.colors.error } : {}}>
{t(isMuted ? 'profileCard.muted' : 'profileCard.mute')}
</Text>
</View>
</View>
<RBSheet ref={bottomSheetRelaysRef} closeOnDragDown={true} customStyles={bottomSheetStyles}>
<View>
<Text variant='titleLarge'>{t('profileCard.relaysTitle')}</Text>
@ -265,6 +307,30 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({
<RBSheet ref={bottomSheetShareRef} closeOnDragDown={true} customStyles={bottomSheetStyles}>
<ProfileShare user={user} />
</RBSheet>
<RBSheet ref={bottomSheetMuteRef} closeOnDragDown={true} customStyles={bottomSheetStyles}>
<View style={styles.muteContainer}>
<Text variant='titleLarge'>
{t('profileCard.muteUser', { username: username(user) })}
</Text>
<View style={[styles.warning, { backgroundColor: '#683D00' }]}>
<Text variant='titleSmall' style={[styles.warningTitle, { color: '#FFDCBB' }]}>
{t('profileCard.muteWarningTitle')}
</Text>
<Text style={{ color: '#FFDCBB' }}>{t('profileCard.muteWarning')}</Text>
</View>
<Button style={styles.buttonSpacer} mode='contained' onPress={muteUser}>
{t('profileCard.muteForever', { username: username(user) })}
</Button>
<Button
mode='outlined'
onPress={() => {
bottomSheetMuteRef.current?.close()
}}
>
{t('profileCard.cancel')}
</Button>
</View>
</RBSheet>
<LnPayment setOpen={setOpenLn} open={openLn} user={user} />
{showNotification && (
<Snackbar
@ -307,6 +373,22 @@ const styles = StyleSheet.create({
paddingLeft: 16,
textAlign: 'center',
},
warning: {
borderRadius: 4,
padding: 16,
marginTop: 16,
marginBottom: 16,
},
warningTitle: {
marginBottom: 8,
},
buttonSpacer: {
marginTop: 16,
marginBottom: 16,
},
muteContainer: {
paddingRight: 16,
},
})
export default ProfileActions

View File

@ -6,6 +6,8 @@ import debounce from 'lodash.debounce'
import { getActiveRelays, getRelays, Relay } from '../Functions/DatabaseFunctions/Relays'
import { UserContext } from './UserContext'
import { randomInt } from '../Functions/NativeFunctions'
import { getUnixTime } from 'date-fns'
import { Event } from '../../lib/nostr/Events'
export interface RelayPoolContextProps {
relayPoolReady: boolean
@ -54,6 +56,19 @@ export const RelayPoolContextProvider = ({
const [relays, setRelays] = React.useState<Relay[]>([])
const [displayRelayDrawer, setDisplayrelayDrawer] = React.useState<string>()
const sendRelays: (relayList: Relay[]) => void = (relayList) => {
if (publicKey && relayList.length > 0) {
const event: Event = {
content: '',
created_at: getUnixTime(new Date()),
kind: 1002,
pubkey: publicKey,
tags: relayList.map((relay) => ['r', relay.url, relay.mode ?? '']),
}
relayPool?.sendEvent(event)
}
}
const changeEventIdHandler: (event: WebsocketEvent) => void = (event) => {
setLastEventId(event.eventId)
}
@ -92,15 +107,15 @@ export const RelayPoolContextProvider = ({
}
}
const loadRelays: () => Promise<void> = async () => {
return await new Promise<void>((resolve, _reject) => {
const loadRelays: () => Promise<Relay[]> = async () => {
return await new Promise<Relay[]>((resolve, _reject) => {
if (database) {
getRelays(database).then((results) => {
setRelays(results)
resolve()
resolve(results)
})
} else {
resolve()
resolve([])
}
})
}
@ -118,7 +133,7 @@ export const RelayPoolContextProvider = ({
return await new Promise((resolve, _reject) => {
if (relayPool && database && publicKey) {
relayPool.update(relay.url, relay.active ?? 1, relay.global_feed ?? 1, () => {
loadRelays().then(resolve)
loadRelays().then(() => resolve())
})
}
})
@ -129,7 +144,10 @@ export const RelayPoolContextProvider = ({
return await new Promise((resolve, _reject) => {
if (relayPool && database && publicKey) {
relayPool.add(relay.url, () => {
loadRelays().then(resolve)
loadRelays().then((results) => {
sendRelays(results)
resolve()
})
})
}
})
@ -140,7 +158,10 @@ export const RelayPoolContextProvider = ({
return await new Promise((resolve, _reject) => {
if (relayPool && database && publicKey) {
relayPool.remove(relay.url, () => {
loadRelays().then(resolve)
loadRelays().then((results) => {
sendRelays(results)
resolve()
})
})
}
})

View File

@ -37,9 +37,9 @@ export const updateConversationRead: (
return db.execute(userQuery, [1, conversationId])
}
export const updateAllRead: (db: QuickSQLiteConnection) => Promise<QueryResult | null> = async (
db,
) => {
export const updateAllDirectMessagesRead: (
db: QuickSQLiteConnection,
) => Promise<QueryResult | null> = async (db) => {
const userQuery = `UPDATE nostros_direct_messages SET read = ?`
return db.execute(userQuery, [1])
}

View File

@ -146,6 +146,13 @@ export const deleteGroup: (
return db.execute(userQuery, [groupId])
}
export const updateAllDirectMessagesRead: (
db: QuickSQLiteConnection,
) => Promise<QueryResult | null> = async (db) => {
const userQuery = `UPDATE nostros_group_messages SET read = ?`
return db.execute(userQuery, [1])
}
export const activateGroup: (
db: QuickSQLiteConnection,
groupId: string,

View File

@ -10,6 +10,7 @@ export interface Relay {
global_feed?: number
resilient?: number
manual?: number
mode?: 'read' | 'write' | ''
}
export interface RelayInfo {

View File

@ -14,6 +14,7 @@ export interface User {
created_at?: number
valid_nip05?: boolean
blocked?: number
muted_groups?: number
}
const databaseToEntity: (object: object) => User = (object) => {
@ -42,6 +43,17 @@ export const updateUserBlock: (
return db.execute(userQuery, [blocked ? 1 : 0, userId])
}
export const updateUserMutesGroups: (
db: QuickSQLiteConnection,
userId: string,
muted: boolean,
) => Promise<QueryResult | null> = async (db, userId, muted) => {
const userQuery = `UPDATE nostros_users SET muted_groups = ? WHERE id = ?`
await addUser(userId, db)
return db.execute(userQuery, [muted ? 1 : 0, userId])
}
export const getUser: (pubkey: string, db: QuickSQLiteConnection) => Promise<User | null> = async (
pubkey,
db,

View File

@ -370,7 +370,10 @@
"share": "Teilen",
"unblock": "Erlauben",
"unfollow": "Abo entfernen",
"relaysTitle": "Relays"
"relaysTitle": "Relays",
"blocked": "Blocked",
"mute": "Mute",
"muted": "Muted"
},
"conversationsFeed": {
"openMessage": "Unterhaltung beginnen",

View File

@ -313,7 +313,8 @@
},
"groupPage": {
"typeMessage": "Type message",
"replyText": "Message"
"replyText": "Message",
"admin": "ADMIN"
},
"groupHeaderIcon": {
"delete": "Leave group",
@ -368,7 +369,15 @@
"block": "Block",
"unblock": "Unblock",
"share": "Share",
"relaysTitle": "Relays"
"relaysTitle": "Relays",
"blocked": "Blocked",
"mute": "Mute",
"muted": "Muted",
"muteUser": "Mute {{username}} on chats",
"muteWarningTitle": "Important",
"muteWarning": "This action will hide the messages of this user on all chats and cannot be undone.",
"muteForever": "Mute {{username}} forever",
"cancel": "Cancel"
},
"conversationsFeed": {
"openMessage": "Start conversation",

View File

@ -352,7 +352,10 @@
"share": "Share",
"unblock": "Desbloquear",
"unfollow": "Siguiendo",
"relaysTitle": "Relays"
"relaysTitle": "Relays",
"blocked": "Bloqueado",
"mute": "Silenciar",
"muted": "Silenciado"
},
"conversationsFeed": {
"openMessage": "Comenzar conversación",

View File

@ -336,7 +336,10 @@
"block": "Bloquer",
"unblock": "Débloquer",
"unfollow": "Abonné",
"relaysTitle": "Relays"
"relaysTitle": "Relays",
"blocked": "Blocked",
"mute": "Mute",
"muted": "Muted"
},
"conversationsFeed": {
"openMessage": "Commencer la conversation",

View File

@ -344,7 +344,10 @@
"unblock": "Desbloquear",
"unfollow": "Following",
"share": "Share",
"relaysTitle": "Relays"
"relaysTitle": "Relays",
"blocked": "Blocked",
"mute": "Mute",
"muted": "Muted"
},
"conversationsFeed": {
"openMessage": "Start conversation",

View File

@ -350,7 +350,10 @@
"share": "分享",
"copyNip05": "复制 NIP-05",
"copyNPub": "复制公钥",
"relaysTitle": "中继"
"relaysTitle": "中继",
"blocked": "Blocked",
"mute": "Mute",
"muted": "Muted"
},
"conversationsFeed": {
"openMessage": "发送私信",

View File

@ -18,7 +18,7 @@ import ConfigPage from '../ConfigPage'
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
import { AppContext } from '../../Contexts/AppContext'
import RelayCard from '../../Components/RelayCard'
import { updateAllRead } from '../../Functions/DatabaseFunctions/DirectMessages'
import { updateAllDirectMessagesRead } from '../../Functions/DatabaseFunctions/DirectMessages'
import { getUnixTime } from 'date-fns'
import ContactsPage from '../ContactsPage'
import GroupPage from '../GroupPage'
@ -60,8 +60,13 @@ export const HomeNavigator: React.FC = () => {
bottomSheetRef.current?.open()
}
const onPressCheckAll: () => void = () => {
if (database) updateAllRead(database)
const onMesssagesPressCheckAll: () => void = () => {
if (database) updateAllDirectMessagesRead(database)
setRefreshBottomBarAt(getUnixTime(new Date()))
}
const onGroupsPressCheckAll: () => void = () => {
if (database) updateAllDirectMessagesRead(database)
setRefreshBottomBarAt(getUnixTime(new Date()))
}
@ -119,7 +124,18 @@ export const HomeNavigator: React.FC = () => {
/>
)}
{['Landing'].includes(route.name) && historyKey?.includes('messages-') && (
<Appbar.Action icon='check-all' isLeading onPress={() => onPressCheckAll()} />
<Appbar.Action
icon='check-all'
isLeading
onPress={() => onMesssagesPressCheckAll()}
/>
)}
{['Landing'].includes(route.name) && historyKey?.includes('groups-') && (
<Appbar.Action
icon='check-all'
isLeading
onPress={() => onGroupsPressCheckAll()}
/>
)}
{['Group'].includes(route.name) && (
<GroupHeaderIcon groupId={route.params?.groupId} />

View File

@ -32,7 +32,9 @@ import { handleInfinityScroll } from '../../Functions/NativeFunctions'
import NostrosAvatar from '../../Components/NostrosAvatar'
import UploadImage from '../../Components/UploadImage'
import {
getGroup,
getGroupMessages,
Group,
GroupMessage,
updateGroupRead,
} from '../../Functions/DatabaseFunctions/Groups'
@ -53,6 +55,7 @@ export const GroupPage: React.FC<GroupPageProps> = ({ route }) => {
const { relayPool, lastEventId } = useContext(RelayPoolContext)
const { publicKey, privateKey, name, picture, validNip05 } = useContext(UserContext)
const [pageSize, setPageSize] = useState<number>(initialPageSize)
const [group, setGroup] = useState<Group>()
const [groupMessages, setGroupMessages] = useState<GroupMessage[]>([])
const [sendingMessages, setSendingMessages] = useState<GroupMessage[]>([])
const [reply, setReply] = useState<GroupMessage>()
@ -82,6 +85,7 @@ export const GroupPage: React.FC<GroupPageProps> = ({ route }) => {
const loadGroupMessages: (subscribe: boolean) => void = (subscribe) => {
if (database && publicKey && route.params.groupId) {
getGroup(database, route.params.groupId).then(setGroup)
updateGroupRead(database, route.params.groupId)
getGroupMessages(database, route.params.groupId, {
order: 'DESC',
@ -294,6 +298,11 @@ export const GroupPage: React.FC<GroupPageProps> = ({ route }) => {
)}
</View>
<View style={styles.cardContentDate}>
{item.pubkey === group?.pubkey && (
<View style={[styles.warning, { backgroundColor: '#683D00' }]}>
<Text style={{ color: '#FFDCBB' }}>{t('groupPage.admin')}</Text>
</View>
)}
{message?.pending && (
<View style={styles.cardContentPending}>
<MaterialCommunityIcons
@ -589,6 +598,12 @@ const styles = StyleSheet.create({
flex: 1,
paddingLeft: 16,
},
warning: {
borderRadius: 4,
paddingLeft: 5,
paddingRight: 5,
marginRight: 5,
},
input: {
flexDirection: 'column-reverse',
marginTop: 16,

View File

@ -96,11 +96,10 @@ export const GroupsFeed: React.FC = () => {
results.forEach((group) => {
if (group.id) {
getGroupMessagesMentionsCount(database, group.id).then((count) => {
if (count > 0)
setNewMentions((prev) => {
if (group.id) prev[group.id] = count
return prev
})
setNewMentions((prev) => {
if (group.id) prev[group.id] = count
return prev
})
})
getGroupMessagesCount(database, group.id).then((count) => {
setNewMessage((prev) => {

View File

@ -58,7 +58,7 @@ export const ProfileLoadPage: React.FC = () => {
if (publicKey && relayPoolReady) {
relayPool?.subscribe('profile-load-meta', [
{
kinds: [Kind.Contacts, Kind.Metadata],
kinds: [Kind.Contacts, Kind.Metadata, Kind.ChannelCreation, Kind.ChannelMetadata, 1002],
authors: [publicKey],
},
])

View File

@ -2,7 +2,7 @@ import React, { useContext, useState } from 'react'
import { FlatList, ListRenderItem, ScrollView, StyleSheet, View } from 'react-native'
import { useTranslation } from 'react-i18next'
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
import { getRelays, Relay } from '../../Functions/DatabaseFunctions/Relays'
import { Relay } from '../../Functions/DatabaseFunctions/Relays'
import { REGEX_SOCKET_LINK } from '../../Constants/Relay'
import {
List,
@ -20,48 +20,38 @@ import RBSheet from 'react-native-raw-bottom-sheet'
import { relayToColor } from '../../Functions/NativeFunctions'
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
import { useFocusEffect } from '@react-navigation/native'
import { AppContext } from '../../Contexts/AppContext'
export const defaultRelays = [
'wss://brb.io',
'wss://damus.io',
'wss://nostr-pub.wellorder.net',
'wss://nostr.swiss-enigma.ch',
'wss://nostr.onsats.org',
'wss://nostr-pub.semisol.dev',
'wss://nostr.openchain.fr',
'wss://relay.nostr.info',
'wss://nostr.oxtr.dev',
'wss://nostr.ono.re',
'wss://relay.grunch.dev',
'wss://nostr.developer.li',
]
import { UserContext } from '../../Contexts/UserContext'
export const RelaysPage: React.FC = () => {
const defaultRelayInput = React.useMemo(() => 'wss://', [])
const { updateRelayItem, addRelayItem, relayPool, setDisplayrelayDrawer } =
const { updateRelayItem, addRelayItem, relayPool, setDisplayrelayDrawer, relays } =
useContext(RelayPoolContext)
const { database } = useContext(AppContext)
const { publicKey } = useContext(UserContext)
const { t } = useTranslation('common')
const theme = useTheme()
const bottomSheetAddRef = React.useRef<RBSheet>(null)
const bottomSheetResilenseRef = React.useRef<RBSheet>(null)
const [relays, setRelays] = React.useState<Relay[]>([])
const [addRelayInput, setAddRelayInput] = useState<string>(defaultRelayInput)
const [showNotification, setShowNotification] = useState<string>()
useFocusEffect(
React.useCallback(() => {
relayPool?.unsubscribeAll()
updateRelays()
if (publicKey) {
relayPool?.subscribe('relays', [
{
kinds: [1002],
authors: [publicKey],
limit: 1,
},
])
}
return () => {}
return () => relayPool?.unsubscribe(['relays'])
}, []),
)
const updateRelays: () => void = () => {
if (database) getRelays(database).then(setRelays)
}
React.useEffect(() => {}, [relays])
const addRelay: (url: string) => void = (url) => {
if (!relayList.find((relay) => relay.url === url)) {
@ -70,7 +60,6 @@ export const RelaysPage: React.FC = () => {
active: 1,
global_feed: 1,
}).then(() => {
updateRelays()
setShowNotification('add')
})
}
@ -79,7 +68,6 @@ export const RelaysPage: React.FC = () => {
const activeRelay: (relay: Relay) => void = (relay) => {
relay.active = 1
updateRelayItem(relay).then(() => {
updateRelays()
setShowNotification('active')
})
}
@ -88,7 +76,6 @@ export const RelaysPage: React.FC = () => {
relay.active = 0
relay.global_feed = 0
updateRelayItem(relay).then(() => {
updateRelays()
setShowNotification('desactive')
})
}
@ -97,7 +84,6 @@ export const RelaysPage: React.FC = () => {
relay.active = 1
relay.global_feed = 1
updateRelayItem(relay).then(() => {
updateRelays()
setShowNotification('globalFeedActive')
})
}
@ -105,7 +91,6 @@ export const RelaysPage: React.FC = () => {
const desactiveGlobalFeedRelay: (relay: Relay) => void = (relay) => {
relay.global_feed = 0
updateRelayItem(relay).then(() => {
updateRelays()
setShowNotification('globalFeedActiveUnactive')
})
}
@ -145,8 +130,6 @@ export const RelaysPage: React.FC = () => {
return 0
})
const myRelays = relayList.filter((relay) => !defaultRelays.includes(relay.url))
const renderItem: ListRenderItem<Relay> = ({ item, index }) => {
return (
<List.Item
@ -200,7 +183,7 @@ export const RelaysPage: React.FC = () => {
right={() => (
<>
{type === 'centralized' && (
<Text style={[styles.smallRelay, { color: theme.colors.errorContainer }]}>
<Text style={[styles.smallRelay, { color: theme.colors.error }]}>
{relayPool?.resilientAssignation.centralizedRelays[item] &&
t('relaysPage.centralized')}
</Text>
@ -258,33 +241,9 @@ export const RelaysPage: React.FC = () => {
data={Object.keys(relayPool?.resilientAssignation.smallRelays ?? {})}
renderItem={(data) => renderResilienceItem(data.item, data.index, 'small')}
/>
{myRelays.length > 0 && (
<>
<View style={styles.titleWrapper}>
<Text style={styles.title} variant='titleMedium'>
{t('relaysPage.myList')}
</Text>
<Divider />
</View>
<List.Item
title={t('relaysPage.relayName')}
right={() => (
<>
<Text style={styles.listHeader}>{t('relaysPage.globalFeed')}</Text>
<Text style={styles.listHeader}>{t('relaysPage.active')}</Text>
</>
)}
/>
<FlatList
showsVerticalScrollIndicator={false}
data={myRelays}
renderItem={renderItem}
/>
</>
)}
<View style={styles.titleWrapper}>
<Text style={styles.title} variant='titleMedium'>
{t('relaysPage.recommended')}
{t('relaysPage.myList')}
</Text>
<Divider />
</View>
@ -297,17 +256,7 @@ export const RelaysPage: React.FC = () => {
</>
)}
/>
<FlatList
showsVerticalScrollIndicator={false}
data={defaultRelays.map(
(url) =>
relays.find((relay) => relay.url === url && relay.active && relay.active > 0) ?? {
url,
},
)}
renderItem={renderItem}
style={styles.list}
/>
<FlatList showsVerticalScrollIndicator={false} data={relays} renderItem={renderItem} />
</ScrollView>
<AnimatedFAB
style={styles.fab}