mirror of
https://github.com/KoalaSat/nostros.git
synced 2024-09-29 14:40:43 +00:00
Global feed relay filter (#238)
This commit is contained in:
commit
951fda5737
@ -298,6 +298,7 @@ public class Event {
|
||||
values.put("name", name);
|
||||
values.put("contact", true);
|
||||
values.put("blocked", 0);
|
||||
values.put("pet_at", created_at);
|
||||
database.insert("nostros_users", null, values);
|
||||
}
|
||||
}
|
||||
@ -315,6 +316,7 @@ public class Event {
|
||||
if (cursor.getCount() == 0) {
|
||||
values.put("id", pubkey);
|
||||
values.put("follower", true);
|
||||
values.put("follower_at", created_at);
|
||||
database.insert("nostros_users", null, values);
|
||||
} else {
|
||||
String whereClause = "id = ?";
|
||||
@ -322,6 +324,7 @@ public class Event {
|
||||
this.pubkey
|
||||
};
|
||||
values.put("follower", true);
|
||||
values.put("follower_at", created_at);
|
||||
database.update("nostros_users", values, whereClause, whereArgs);
|
||||
}
|
||||
}
|
||||
|
@ -13,22 +13,28 @@ import java.io.IOException;
|
||||
public class Relay {
|
||||
private Websocket webSocket;
|
||||
public String url;
|
||||
public boolean active;
|
||||
public int active;
|
||||
public int globalFeed;
|
||||
|
||||
public Relay(String serverUrl, boolean isActive,DatabaseModule database, ReactApplicationContext reactContext) throws IOException {
|
||||
public Relay(String serverUrl, int isActive, int showGlobalFeed, DatabaseModule database, ReactApplicationContext reactContext) throws IOException {
|
||||
webSocket = new Websocket(serverUrl, database, reactContext);
|
||||
url = serverUrl;
|
||||
active = isActive;
|
||||
globalFeed = showGlobalFeed;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
public int active() {
|
||||
return active;
|
||||
}
|
||||
|
||||
public void setActive(boolean active) {
|
||||
public void setActive(int active) {
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
public void setGlobalFeed(int globalFeed) {
|
||||
this.globalFeed = globalFeed;
|
||||
}
|
||||
|
||||
public void send(String message) {
|
||||
webSocket.send(message);
|
||||
}
|
||||
@ -44,7 +50,8 @@ public class Relay {
|
||||
public void save(SQLiteDatabase database) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("url", url);
|
||||
values.put("active", active ? 1 : 0);
|
||||
values.put("active", active);
|
||||
values.put("global_feed", globalFeed);
|
||||
database.replace("nostros_relays", null, values);
|
||||
}
|
||||
|
||||
|
@ -40,8 +40,8 @@ public class DatabaseModule {
|
||||
" picture TEXT,\n" +
|
||||
" about TEXT,\n" +
|
||||
" main_relay TEXT,\n" +
|
||||
" contact BOOLEAN DEFAULT FALSE,\n" +
|
||||
" follower BOOLEAN DEFAULT FALSE\n" +
|
||||
" contact BOOLEAN DEFAULT 0,\n" +
|
||||
" follower BOOLEAN DEFAULT 0\n" +
|
||||
" );");
|
||||
database.execSQL("CREATE TABLE IF NOT EXISTS nostros_relays(\n" +
|
||||
" url TEXT PRIMARY KEY NOT NULL,\n" +
|
||||
@ -56,7 +56,7 @@ public class DatabaseModule {
|
||||
" sig TEXT NOT NULL,\n" +
|
||||
" tags TEXT NOT NULL,\n" +
|
||||
" conversation_id TEXT NOT NULL,\n" +
|
||||
" read BOOLEAN DEFAULT FALSE\n" +
|
||||
" read BOOLEAN DEFAULT 0\n" +
|
||||
" );");
|
||||
try {
|
||||
database.execSQL("ALTER TABLE nostros_notes ADD COLUMN user_mentioned BOOLEAN DEFAULT 0;");
|
||||
@ -139,6 +139,11 @@ public class DatabaseModule {
|
||||
database.execSQL("CREATE INDEX nostros_notes_relays_note_id_index ON nostros_notes_relays(note_id);");
|
||||
database.execSQL("CREATE INDEX nostros_notes_relays_pubkey_index ON nostros_notes_relays(pubkey);");
|
||||
} catch (SQLException e) { }
|
||||
try {
|
||||
database.execSQL("ALTER TABLE nostros_relays ADD COLUMN global_feed BOOLEAN DEFAULT 1;");
|
||||
database.execSQL("ALTER TABLE nostros_users ADD COLUMN pet_at INT;");
|
||||
database.execSQL("ALTER TABLE nostros_users ADD COLUMN follower_at INT;");
|
||||
} catch (SQLException e) { }
|
||||
}
|
||||
|
||||
public void saveEvent(JSONObject data, String userPubKey, String relayUrl) throws JSONException {
|
||||
@ -156,7 +161,7 @@ public class DatabaseModule {
|
||||
|
||||
public List<Relay> getRelays(ReactApplicationContext reactContext) {
|
||||
List<Relay> relayList = new ArrayList<>();
|
||||
String query = "SELECT url, active FROM nostros_relays;";
|
||||
String query = "SELECT url, active, global_feed FROM nostros_relays;";
|
||||
@SuppressLint("Recycle") Cursor cursor = database.rawQuery(query, new String[] {});
|
||||
if (cursor.getCount() > 0) {
|
||||
cursor.moveToFirst();
|
||||
@ -164,7 +169,8 @@ public class DatabaseModule {
|
||||
try {
|
||||
String relayUrl = cursor.getString(0);
|
||||
int active = cursor.getInt(1);
|
||||
Relay relay = new Relay(relayUrl, active > 0,this, reactContext);
|
||||
int globalFeed = cursor.getInt(2);
|
||||
Relay relay = new Relay(relayUrl, active, globalFeed,this, reactContext);
|
||||
relayList.add(relay);
|
||||
} catch (IOException e) {
|
||||
Log.d("WebSocket", e.toString());
|
||||
|
@ -38,7 +38,7 @@ public class RelayPoolModule extends ReactContextBaseJavaModule {
|
||||
@ReactMethod
|
||||
public void add(String url) {
|
||||
try {
|
||||
Relay relay = new Relay(url, true, database, context);
|
||||
Relay relay = new Relay(url, 1, 1, database, context);
|
||||
relay.connect(userPubKey);
|
||||
relays.add(relay);
|
||||
database.saveRelay(relay);
|
||||
@ -63,15 +63,16 @@ public class RelayPoolModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void active(String url, Callback callback) throws IOException {
|
||||
public void update(String url, int active, int globalFeed, Callback callback) throws IOException {
|
||||
ListIterator<Relay> iterator = relays.listIterator();
|
||||
boolean relayExists = false;
|
||||
while(iterator.hasNext()){
|
||||
Relay relay = iterator.next();
|
||||
if(url.equals(relay.url) && !relay.isActive()){
|
||||
if(url.equals(relay.url)){
|
||||
int index = relays.indexOf(relay);
|
||||
relay.connect(userPubKey);
|
||||
relay.setActive(true);
|
||||
relay.setActive(active);
|
||||
relay.setGlobalFeed(globalFeed);
|
||||
relay.save(database.database);
|
||||
this.relays.set(index, relay);
|
||||
relayExists = true;
|
||||
@ -85,30 +86,13 @@ public class RelayPoolModule extends ReactContextBaseJavaModule {
|
||||
callback.invoke();
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void desactive(String url, Callback callback) {
|
||||
ListIterator<Relay> iterator = relays.listIterator();
|
||||
while(iterator.hasNext()){
|
||||
Relay relay = iterator.next();
|
||||
if(url.equals(relay.url) && relay.isActive()){
|
||||
int index = relays.indexOf(relay);
|
||||
relay.disconnect();
|
||||
relay.setActive(false);
|
||||
relay.save(database.database);
|
||||
this.relays.set(index, relay);
|
||||
}
|
||||
}
|
||||
|
||||
callback.invoke();
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void connect(String pubKey, Callback callback) {
|
||||
userPubKey = pubKey;
|
||||
relays = database.getRelays(context);
|
||||
for (Relay relay : relays) {
|
||||
try {
|
||||
if (relay.isActive()) {
|
||||
if (relay.active() > 0) {
|
||||
relay.connect(pubKey);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
@ -119,9 +103,9 @@ public class RelayPoolModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void send(String message) {
|
||||
public void send(String message, boolean globalFeed) {
|
||||
for (Relay relay : relays) {
|
||||
if (relay.isActive()) {
|
||||
if (relay.active() > 0 && (!globalFeed || relay.globalFeed > 0)) {
|
||||
relay.send(message);
|
||||
}
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ export const NoteCard: React.FC<NoteCardProps> = ({
|
||||
}
|
||||
|
||||
const getNoteContent: () => JSX.Element | undefined = () => {
|
||||
if (note?.blocked !== undefined && note.blocked) {
|
||||
if (note?.blocked !== undefined && note.blocked > 0) {
|
||||
return blockedContent()
|
||||
} else if (note?.kind === Kind.Text) {
|
||||
return textNote()
|
||||
@ -289,7 +289,7 @@ export const NoteCard: React.FC<NoteCardProps> = ({
|
||||
)}
|
||||
</Card.Content>
|
||||
{getNoteContent()}
|
||||
{showAction && !note?.blocked && (
|
||||
{showAction && !note?.blocked > 0 && (
|
||||
<Card.Content style={[styles.bottomActions, { borderColor: theme.colors.onSecondary }]}>
|
||||
<Button
|
||||
icon={() => (
|
||||
|
@ -39,7 +39,7 @@ export const ProfileCard: React.FC<ProfileCardProps> = ({
|
||||
const { publicKey } = React.useContext(UserContext)
|
||||
const { relayPool } = React.useContext(RelayPoolContext)
|
||||
const [user, setUser] = React.useState<User>()
|
||||
const [blocked, setBlocked] = React.useState<boolean>()
|
||||
const [blocked, setBlocked] = React.useState<number>()
|
||||
const [openLn, setOpenLn] = React.useState<boolean>(false)
|
||||
const [isContact, setIsContact] = React.useState<boolean>()
|
||||
const [showNotification, setShowNotification] = React.useState<undefined | string>()
|
||||
@ -54,7 +54,7 @@ export const ProfileCard: React.FC<ProfileCardProps> = ({
|
||||
const onChangeBlockUser: () => void = () => {
|
||||
if (database && blocked !== undefined) {
|
||||
updateUserBlock(userPubKey, database, !blocked).then(() => {
|
||||
setBlocked(!blocked)
|
||||
setBlocked(blocked === 0 ? 1 : 0)
|
||||
loadUser()
|
||||
})
|
||||
}
|
||||
@ -85,11 +85,11 @@ export const ProfileCard: React.FC<ProfileCardProps> = ({
|
||||
getUser(userPubKey, database).then((result) => {
|
||||
if (result) {
|
||||
setUser(result)
|
||||
setBlocked(result.blocked !== undefined && result.blocked)
|
||||
setBlocked(result.blocked)
|
||||
setIsContact(result?.contact)
|
||||
} else {
|
||||
setUser({ id: userPubKey })
|
||||
setBlocked(false)
|
||||
setBlocked(0)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -199,11 +199,11 @@ export const ProfileCard: React.FC<ProfileCardProps> = ({
|
||||
)}
|
||||
<View style={styles.actionButton}>
|
||||
<IconButton
|
||||
icon={blocked ? 'account-cancel' : 'account-cancel-outline'}
|
||||
icon={blocked && blocked > 0 ? 'account-cancel' : 'account-cancel-outline'}
|
||||
size={28}
|
||||
onPress={onChangeBlockUser}
|
||||
/>
|
||||
<Text>{t(blocked ? 'profileCard.unblock' : 'profileCard.block')}</Text>
|
||||
<Text>{t(blocked && blocked > 0 ? 'profileCard.unblock' : 'profileCard.block')}</Text>
|
||||
</View>
|
||||
</View>
|
||||
{showNotification && (
|
||||
|
@ -15,8 +15,7 @@ export interface RelayPoolContextProps {
|
||||
relays: Relay[]
|
||||
addRelayItem: (relay: Relay) => Promise<void>
|
||||
removeRelayItem: (relay: Relay) => Promise<void>
|
||||
activeRelayItem: (relay: Relay) => Promise<void>
|
||||
desactiveRelayItem: (relay: Relay) => Promise<void>
|
||||
updateRelayItem: (relay: Relay) => Promise<void>
|
||||
}
|
||||
|
||||
export interface WebsocketEvent {
|
||||
@ -33,8 +32,7 @@ export const initialRelayPoolContext: RelayPoolContextProps = {
|
||||
setRelayPool: () => {},
|
||||
addRelayItem: async () => await new Promise(() => {}),
|
||||
removeRelayItem: async () => await new Promise(() => {}),
|
||||
activeRelayItem: async () => await new Promise(() => {}),
|
||||
desactiveRelayItem: async () => await new Promise(() => {}),
|
||||
updateRelayItem: async () => await new Promise(() => {}),
|
||||
relays: [],
|
||||
}
|
||||
|
||||
@ -91,32 +89,19 @@ export const RelayPoolContextProvider = ({
|
||||
})
|
||||
}
|
||||
|
||||
const activeRelayItem: (relay: Relay) => Promise<void> = async (relay) => {
|
||||
const updateRelayItem: (relay: Relay) => Promise<void> = async (relay) => {
|
||||
setRelays((prev) => {
|
||||
return prev.map((item) => {
|
||||
if (item.url === relay.url) item.active = true
|
||||
if (item.url === relay.url) {
|
||||
return relay
|
||||
} else {
|
||||
return item
|
||||
}
|
||||
})
|
||||
})
|
||||
return await new Promise((resolve, _reject) => {
|
||||
if (relayPool && database && publicKey) {
|
||||
relayPool.active(relay.url, () => {
|
||||
loadRelays().then(resolve)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const desactiveRelayItem: (relay: Relay) => Promise<void> = async (relay) => {
|
||||
setRelays((prev) => {
|
||||
return prev.map((item) => {
|
||||
if (item.url === relay.url) item.active = false
|
||||
return item
|
||||
})
|
||||
})
|
||||
return await new Promise((resolve, _reject) => {
|
||||
if (relayPool && database && publicKey) {
|
||||
relayPool.desactive(relay.url, () => {
|
||||
relayPool.update(relay.url, relay.active ?? 1, relay.global_feed ?? 1, () => {
|
||||
loadRelays().then(resolve)
|
||||
})
|
||||
}
|
||||
@ -174,8 +159,7 @@ export const RelayPoolContextProvider = ({
|
||||
relays,
|
||||
addRelayItem,
|
||||
removeRelayItem,
|
||||
activeRelayItem,
|
||||
desactiveRelayItem,
|
||||
updateRelayItem,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
@ -11,7 +11,7 @@ export interface Note extends Event {
|
||||
nip05: string
|
||||
valid_nip05: boolean
|
||||
repost_id: string
|
||||
blocked: boolean
|
||||
blocked: number
|
||||
}
|
||||
|
||||
export interface NoteRelay {
|
||||
@ -74,7 +74,12 @@ export const getMainNotesCount: (
|
||||
SELECT
|
||||
COUNT(*)
|
||||
FROM nostros_notes
|
||||
WHERE created_at > "${from}"
|
||||
LEFT JOIN
|
||||
nostros_users ON nostros_users.id = nostros_notes.pubkey
|
||||
WHERE
|
||||
nostros_users.blocked != 1 AND
|
||||
nostros_notes.main_event_id IS NULL AND
|
||||
nostros_notes.created_at > "${from}"
|
||||
`
|
||||
const resultSet = db.execute(repliesQuery)
|
||||
const item: { 'COUNT(*)': number } = resultSet?.rows?.item(0)
|
||||
|
@ -5,6 +5,7 @@ export interface Relay {
|
||||
url: string
|
||||
name?: string
|
||||
active?: number
|
||||
global_feed?: number
|
||||
}
|
||||
|
||||
const databaseToEntity: (object: any) => Relay = (object) => {
|
||||
|
@ -13,7 +13,7 @@ export interface User {
|
||||
nip05?: string
|
||||
created_at?: number
|
||||
valid_nip05?: boolean
|
||||
blocked?: boolean
|
||||
blocked?: number
|
||||
}
|
||||
|
||||
const databaseToEntity: (object: object) => User = (object) => {
|
||||
|
@ -153,6 +153,9 @@
|
||||
"myFeed": "Mein Feed"
|
||||
},
|
||||
"relaysPage": {
|
||||
"relayName": "Address",
|
||||
"globalFeed": "Global feed",
|
||||
"active": "Active",
|
||||
"labelAdd": "Beschreibung des Relay",
|
||||
"cancel": "Abbrechen",
|
||||
"add": "Hinzufügen",
|
||||
@ -163,7 +166,8 @@
|
||||
"remove": "Relay entfernen",
|
||||
"active": "Relay aktivieren.",
|
||||
"desactive": "Relay deaktivieren.",
|
||||
"badFormat": "Die URL des Relays hat kein gültiges Format."
|
||||
"badFormat": "Die URL des Relays hat kein gültiges Format.",
|
||||
"alreadyExists": "Relay already exists."
|
||||
}
|
||||
},
|
||||
"profileConfigPage": {
|
||||
|
@ -163,6 +163,9 @@
|
||||
"newMessages": "{{newNotesCount}} new notes. Pull to refresh."
|
||||
},
|
||||
"relaysPage": {
|
||||
"relayName": "Address",
|
||||
"globalFeed": "Global feed",
|
||||
"active": "Active",
|
||||
"labelAdd": "Relay address",
|
||||
"cancel": "Cancel",
|
||||
"add": "Add",
|
||||
@ -171,11 +174,14 @@
|
||||
"recommended": "Recommended",
|
||||
"myList": "My relays",
|
||||
"notifications": {
|
||||
"globalFeedActive": "Global feed enabled.",
|
||||
"globalFeedActiveUnactive": "Global feed disabled.",
|
||||
"add": "Relay added.",
|
||||
"remove": "Relay removed.",
|
||||
"active": "Relay activated.",
|
||||
"desactive": "Relay desactivated.",
|
||||
"badFormat": "Relay URL has a bad format."
|
||||
"badFormat": "Relay URL has a bad format.",
|
||||
"alreadyExists": "Relay already exists."
|
||||
}
|
||||
},
|
||||
"profileConfigPage": {
|
||||
|
@ -2,7 +2,7 @@
|
||||
"common": {
|
||||
"drawers": {
|
||||
"relaysTitle": "Relés",
|
||||
"relaysDescription": "Los relés son nodos en la red que actúan como intermediarios para la transmisión demensajes entre aplicaciones.\n\n\nLos relés 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 relés 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 relés 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 relés y considerar medidas de seguridad adecuadas para protegerla privacidad y la seguridad de la red.",
|
||||
"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.",
|
||||
"keysTitle": "¿Qué son las claves?",
|
||||
"keysDescription": "En nostr tienes dos claves: tu clave pública y tu clave privada.",
|
||||
"publicKeys": "Clave pública",
|
||||
@ -153,6 +153,9 @@
|
||||
"myFeed": "Mi feed"
|
||||
},
|
||||
"relaysPage": {
|
||||
"relayName": "Dirección",
|
||||
"globalFeed": "Feed global",
|
||||
"active": "Activo",
|
||||
"labelAdd": "Dirección de relay",
|
||||
"cancel": "Cancelar",
|
||||
"add": "Añadir",
|
||||
@ -163,7 +166,8 @@
|
||||
"remove": "Relay borrado",
|
||||
"active": "Relay activado.",
|
||||
"desactive": "Relay desactivado.",
|
||||
"badFormat": "La URL del relay no tiene el formato adecuado."
|
||||
"badFormat": "La URL del relay no tiene el formato adecuado.",
|
||||
"alreadyExists": "El relay ya existe."
|
||||
}
|
||||
},
|
||||
"profileConfigPage": {
|
||||
|
@ -152,6 +152,9 @@
|
||||
"myFeed": "Mon flux"
|
||||
},
|
||||
"relaysPage": {
|
||||
"relayName": "Address",
|
||||
"globalFeed": "Global feed",
|
||||
"active": "Active",
|
||||
"labelAdd": "Adresse du relai",
|
||||
"cancel": "Annuler",
|
||||
"add": "Ajouter",
|
||||
@ -162,7 +165,8 @@
|
||||
"remove": "Relai supprimé",
|
||||
"active": "Relais activé.",
|
||||
"desactive": "Relais desactivé.",
|
||||
"badFormat": "L'URL du relai n'est pas correctement formatée."
|
||||
"badFormat": "L'URL du relai n'est pas correctement formatée.",
|
||||
"alreadyExists": "Relay already exists."
|
||||
}
|
||||
},
|
||||
"profileConfigPage": {
|
||||
|
@ -152,6 +152,9 @@
|
||||
"myFeed": "My feed"
|
||||
},
|
||||
"relaysPage": {
|
||||
"relayName": "Address",
|
||||
"globalFeed": "Global feed",
|
||||
"active": "Active",
|
||||
"labelAdd": "Relay address",
|
||||
"cancel": "Отменить",
|
||||
"add": "Добавить",
|
||||
@ -162,7 +165,8 @@
|
||||
"remove": "Relay removed.",
|
||||
"active": "Relay acivado.",
|
||||
"desactive": "Relay desactivado.",
|
||||
"badFormat": "Relay URL has a bad format."
|
||||
"badFormat": "Relay URL has a bad format.",
|
||||
"alreadyExists": "Relay already exists."
|
||||
}
|
||||
},
|
||||
"profileConfigPage": {
|
||||
|
@ -235,6 +235,7 @@ export const ContactsFeed: React.FC = () => {
|
||||
const Following: JSX.Element = (
|
||||
<View style={styles.container}>
|
||||
<FlashList
|
||||
estimatedItemSize={71}
|
||||
showsVerticalScrollIndicator={false}
|
||||
data={following.slice(0, pageSize)}
|
||||
renderItem={renderContactItem}
|
||||
@ -276,6 +277,7 @@ export const ContactsFeed: React.FC = () => {
|
||||
const Followers: JSX.Element = (
|
||||
<View style={styles.container}>
|
||||
<FlashList
|
||||
estimatedItemSize={71}
|
||||
style={styles.list}
|
||||
data={followers.slice(0, pageSize)}
|
||||
renderItem={renderContactItem}
|
||||
|
@ -97,7 +97,7 @@ export const GlobalFeed: React.FC<GlobalFeedProps> = ({ navigation, setProfileCa
|
||||
setRefreshing(false)
|
||||
if (results.length > 0) {
|
||||
setNotes(results)
|
||||
relayPool?.subscribe('homepage-contacts-meta', [
|
||||
relayPool?.subscribe('homepage-global-meta', [
|
||||
{
|
||||
kinds: [Kind.Metadata],
|
||||
authors: results.map((note) => note.pubkey ?? ''),
|
||||
@ -169,6 +169,7 @@ export const GlobalFeed: React.FC<GlobalFeedProps> = ({ navigation, setProfileCa
|
||||
)}
|
||||
<View style={styles.list}>
|
||||
<FlashList
|
||||
estimatedItemSize={200}
|
||||
showsVerticalScrollIndicator={false}
|
||||
data={notes}
|
||||
renderItem={renderItem}
|
||||
|
@ -164,6 +164,7 @@ export const MyFeed: React.FC<MyFeedProps> = ({ navigation, setProfileCardPubKey
|
||||
return (
|
||||
<View style={styles.list}>
|
||||
<FlashList
|
||||
estimatedItemSize={200}
|
||||
showsVerticalScrollIndicator={false}
|
||||
data={notes}
|
||||
renderItem={renderItem}
|
||||
|
@ -136,6 +136,7 @@ export const NotePage: React.FC<NotePageProps> = ({ route }) => {
|
||||
<NoteCard note={note} onPressUser={openProfileDrawer} />
|
||||
<View style={[styles.list, { borderColor: theme.colors.onSecondary }]}>
|
||||
<FlashList
|
||||
estimatedItemSize={200}
|
||||
showsVerticalScrollIndicator={false}
|
||||
data={replies}
|
||||
renderItem={renderItem}
|
||||
|
@ -3,7 +3,6 @@ import {
|
||||
NativeScrollEvent,
|
||||
NativeSyntheticEvent,
|
||||
RefreshControl,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
View,
|
||||
} from 'react-native'
|
||||
@ -25,6 +24,7 @@ import { useFocusEffect } from '@react-navigation/native'
|
||||
import { getLastReaction } from '../../Functions/DatabaseFunctions/Reactions'
|
||||
import { getUnixTime } from 'date-fns'
|
||||
import { Config } from '../../Functions/DatabaseFunctions/Config'
|
||||
import { FlashList, ListRenderItem } from '@shopify/flash-list'
|
||||
|
||||
export const NotificationsFeed: React.FC = () => {
|
||||
const theme = useTheme()
|
||||
@ -140,11 +140,11 @@ export const NotificationsFeed: React.FC = () => {
|
||||
}
|
||||
}, [])
|
||||
|
||||
const renderItem: (note: Note) => JSX.Element = (note) => {
|
||||
const renderItem: ListRenderItem<Note> = ({ item }) => {
|
||||
return (
|
||||
<View style={styles.noteCard} key={note.id}>
|
||||
<View style={styles.noteCard} key={item.id}>
|
||||
<NoteCard
|
||||
note={note}
|
||||
note={item}
|
||||
onPressUser={(user) => {
|
||||
setProfileCardPubKey(user.id)
|
||||
bottomSheetProfileRef.current?.open()
|
||||
@ -175,19 +175,8 @@ export const NotificationsFeed: React.FC = () => {
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{notes && notes.length > 0 ? (
|
||||
<ScrollView
|
||||
onScroll={onScroll}
|
||||
horizontal={false}
|
||||
showsVerticalScrollIndicator={false}
|
||||
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />}
|
||||
>
|
||||
{notes.map((note) => renderItem(note))}
|
||||
{notes.length >= 10 && <ActivityIndicator animating={true} />}
|
||||
</ScrollView>
|
||||
) : (
|
||||
const ListEmptyComponent = React.useMemo(
|
||||
() => (
|
||||
<View style={styles.blank}>
|
||||
<MaterialCommunityIcons
|
||||
name='bell-outline'
|
||||
@ -205,7 +194,24 @@ export const NotificationsFeed: React.FC = () => {
|
||||
{t('notificationsFeed.emptyButton')}
|
||||
</Button>
|
||||
</View>
|
||||
)}
|
||||
),
|
||||
[],
|
||||
)
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<FlashList
|
||||
estimatedItemSize={200}
|
||||
showsVerticalScrollIndicator={false}
|
||||
data={notes}
|
||||
renderItem={renderItem}
|
||||
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />}
|
||||
onScroll={onScroll}
|
||||
refreshing={refreshing}
|
||||
ListEmptyComponent={ListEmptyComponent}
|
||||
horizontal={false}
|
||||
ListFooterComponent={<ActivityIndicator animating={true} />}
|
||||
/>
|
||||
<RBSheet ref={bottomSheetProfileRef} closeOnDragDown={true} customStyles={bottomSheetStyles}>
|
||||
<ProfileCard userPubKey={profileCardPubkey ?? ''} bottomSheetRef={bottomSheetProfileRef} />
|
||||
</RBSheet>
|
||||
|
@ -273,6 +273,7 @@ export const ProfilePage: React.FC<ProfilePageProps> = ({ route }) => {
|
||||
</Surface>
|
||||
<View style={styles.list}>
|
||||
<FlashList
|
||||
estimatedItemSize={200}
|
||||
showsVerticalScrollIndicator={false}
|
||||
data={notes}
|
||||
renderItem={renderItem}
|
||||
|
@ -167,6 +167,7 @@ export const ReactionsFeed: React.FC<ReactionsFeedProps> = ({
|
||||
return (
|
||||
<View style={styles.list}>
|
||||
<FlashList
|
||||
estimatedItemSize={200}
|
||||
showsVerticalScrollIndicator={false}
|
||||
data={notes}
|
||||
renderItem={renderItem}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useContext, useState } from 'react'
|
||||
import { ScrollView, StyleSheet, View } from 'react-native'
|
||||
import { FlatList, ListRenderItem, ScrollView, StyleSheet, View } from 'react-native'
|
||||
import Clipboard from '@react-native-clipboard/clipboard'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
||||
@ -23,8 +23,7 @@ import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityI
|
||||
|
||||
export const RelaysPage: React.FC = () => {
|
||||
const defaultRelayInput = React.useMemo(() => 'wss://', [])
|
||||
const { activeRelayItem, desactiveRelayItem, addRelayItem, removeRelayItem, relays } =
|
||||
useContext(RelayPoolContext)
|
||||
const { updateRelayItem, addRelayItem, removeRelayItem, relays } = useContext(RelayPoolContext)
|
||||
const { t } = useTranslation('common')
|
||||
const theme = useTheme()
|
||||
const bottomSheetAddRef = React.useRef<RBSheet>(null)
|
||||
@ -36,7 +35,8 @@ export const RelaysPage: React.FC = () => {
|
||||
const addRelay: (url: string) => void = (url) => {
|
||||
addRelayItem({
|
||||
url,
|
||||
active: true,
|
||||
active: 1,
|
||||
global_feed: 1,
|
||||
}).then(() => {
|
||||
setShowNotification('add')
|
||||
})
|
||||
@ -51,29 +51,45 @@ export const RelaysPage: React.FC = () => {
|
||||
}
|
||||
|
||||
const activeRelay: (relay: Relay) => void = (relay) => {
|
||||
activeRelayItem(relay).then(() => {
|
||||
relay.active = 1
|
||||
updateRelayItem(relay).then(() => {
|
||||
setShowNotification('active')
|
||||
})
|
||||
}
|
||||
|
||||
const desactiveRelay: (relay: Relay) => void = (relay) => {
|
||||
desactiveRelayItem(relay).then(() => {
|
||||
relay.active = 0
|
||||
updateRelayItem(relay).then(() => {
|
||||
setShowNotification('desactive')
|
||||
})
|
||||
}
|
||||
|
||||
const activeGlobalFeedRelay: (relay: Relay) => void = (relay) => {
|
||||
relay.global_feed = 1
|
||||
updateRelayItem(relay).then(() => {
|
||||
setShowNotification('globalFeedActive')
|
||||
})
|
||||
}
|
||||
|
||||
const desactiveGlobalFeedRelay: (relay: Relay) => void = (relay) => {
|
||||
relay.global_feed = 0
|
||||
updateRelayItem(relay).then(() => {
|
||||
setShowNotification('globalFeedActiveUnactive')
|
||||
})
|
||||
}
|
||||
|
||||
const onPressAddRelay: () => void = () => {
|
||||
if (
|
||||
REGEX_SOCKET_LINK.test(addRelayInput) &&
|
||||
!relays.find((relay) => relay.url === addRelayInput)
|
||||
) {
|
||||
bottomSheetAddRef.current?.close()
|
||||
if (REGEX_SOCKET_LINK.test(addRelayInput)) {
|
||||
if (relays.find((relay) => relay.url === addRelayInput)) {
|
||||
setShowNotification('alreadyExists')
|
||||
} else {
|
||||
addRelay(addRelayInput)
|
||||
setAddRelayInput(defaultRelayInput)
|
||||
}
|
||||
} else {
|
||||
bottomSheetAddRef.current?.close()
|
||||
setShowNotification('badFormat')
|
||||
}
|
||||
bottomSheetAddRef.current?.close()
|
||||
}
|
||||
|
||||
const rbSheetCustomStyles = React.useMemo(() => {
|
||||
@ -91,78 +107,87 @@ export const RelaysPage: React.FC = () => {
|
||||
}
|
||||
}, [])
|
||||
|
||||
const myRelays = relays.filter((relay) => !defaultRelays.includes(relay.url))
|
||||
const myRelays = relays
|
||||
.filter((relay) => !defaultRelays.includes(relay.url))
|
||||
.sort((a, b) => {
|
||||
if (a.url > b.url) return 1
|
||||
if (a.url < b.url) return -1
|
||||
return 0
|
||||
})
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<ScrollView horizontal={false}>
|
||||
{myRelays.length > 0 && (
|
||||
<>
|
||||
<Text style={styles.title} variant='titleMedium'>
|
||||
{t('relaysPage.myList')}
|
||||
</Text>
|
||||
{myRelays.length > 0 &&
|
||||
myRelays.map((relay, index) => {
|
||||
const renderItem: ListRenderItem<Relay> = ({ item, index }) => {
|
||||
return (
|
||||
<List.Item
|
||||
key={index}
|
||||
title={relay.url.split('wss://')[1]?.split('/')[0]}
|
||||
title={item.url.split('wss://')[1]?.split('/')[0]}
|
||||
right={() => (
|
||||
<>
|
||||
<Switch
|
||||
value={relay.active !== undefined && relay.active > 0}
|
||||
value={item.global_feed !== undefined && item.global_feed > 0}
|
||||
onValueChange={() =>
|
||||
relay.active ? desactiveRelay(relay) : activeRelay(relay)
|
||||
item.active ? desactiveGlobalFeedRelay(item) : activeGlobalFeedRelay(item)
|
||||
}
|
||||
/>
|
||||
<Switch
|
||||
style={styles.switch}
|
||||
value={item.active !== undefined && item.active > 0}
|
||||
onValueChange={() => (item.active ? desactiveRelay(item) : activeRelay(item))}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
left={() => (
|
||||
<MaterialCommunityIcons
|
||||
style={styles.relayColor}
|
||||
name='circle'
|
||||
color={relayToColor(relay.url)}
|
||||
color={relayToColor(item.url)}
|
||||
/>
|
||||
)}
|
||||
onPress={() => {
|
||||
setSelectedRelay(relay)
|
||||
setSelectedRelay(item)
|
||||
bottomSheetEditRef.current?.open()
|
||||
}}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<List.Item
|
||||
title={t('relaysPage.relayName')}
|
||||
right={() => (
|
||||
<>
|
||||
<Text style={styles.listHeader}>{t('relaysPage.globalFeed')}</Text>
|
||||
<Text style={styles.listHeader}>{t('relaysPage.active')}</Text>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
<ScrollView horizontal={false}>
|
||||
<Text style={styles.title} variant='titleMedium'>
|
||||
{t('relaysPage.myList')}
|
||||
</Text>
|
||||
{myRelays.length > 0 && (
|
||||
<>
|
||||
<FlatList
|
||||
showsVerticalScrollIndicator={false}
|
||||
data={myRelays}
|
||||
renderItem={renderItem}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<Text style={styles.title} variant='titleMedium'>
|
||||
{t('relaysPage.recommended')}
|
||||
</Text>
|
||||
{defaultRelays.map((url, index) => {
|
||||
const relay = {
|
||||
<FlatList
|
||||
showsVerticalScrollIndicator={false}
|
||||
data={defaultRelays.map(
|
||||
(url) =>
|
||||
relays.find((relay) => relay.url === url && relay.active && relay.active > 0) ?? {
|
||||
url,
|
||||
active: relays.find((relay) => relay.url === url && relay.active) !== undefined,
|
||||
}
|
||||
return (
|
||||
<List.Item
|
||||
key={index}
|
||||
title={url.split('wss://')[1]?.split('/')[0]}
|
||||
right={() => (
|
||||
<Switch
|
||||
value={relay.active}
|
||||
onValueChange={() => (relay.active ? desactiveRelay(relay) : activeRelay(relay))}
|
||||
/>
|
||||
},
|
||||
)}
|
||||
left={() => (
|
||||
<MaterialCommunityIcons
|
||||
style={styles.relayColor}
|
||||
name='circle'
|
||||
color={relayToColor(relay.url)}
|
||||
renderItem={renderItem}
|
||||
style={styles.list}
|
||||
/>
|
||||
)}
|
||||
onPress={() => {
|
||||
setSelectedRelay(relay)
|
||||
bottomSheetEditRef.current?.open()
|
||||
}}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</ScrollView>
|
||||
<AnimatedFAB
|
||||
style={styles.fab}
|
||||
@ -252,12 +277,10 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
container: {
|
||||
padding: 0,
|
||||
paddingBottom: 32,
|
||||
paddingLeft: 16,
|
||||
},
|
||||
list: {
|
||||
padding: 0,
|
||||
paddingBottom: 45,
|
||||
paddingBottom: 80,
|
||||
},
|
||||
snackbar: {
|
||||
margin: 16,
|
||||
@ -266,6 +289,14 @@ const styles = StyleSheet.create({
|
||||
relayColor: {
|
||||
paddingTop: 9,
|
||||
},
|
||||
switch: {
|
||||
marginLeft: 32,
|
||||
},
|
||||
listHeader: {
|
||||
paddingRight: 5,
|
||||
paddingLeft: 16,
|
||||
textAlign: 'center',
|
||||
},
|
||||
fab: {
|
||||
bottom: 16,
|
||||
right: 16,
|
||||
|
@ -156,6 +156,7 @@ export const RepostsFeed: React.FC<RepostsFeedProps> = ({ navigation, setProfile
|
||||
return (
|
||||
<View style={styles.list}>
|
||||
<FlashList
|
||||
estimatedItemSize={200}
|
||||
showsVerticalScrollIndicator={false}
|
||||
data={notes}
|
||||
renderItem={renderItem}
|
||||
|
@ -2,12 +2,11 @@ import { NativeModules } from 'react-native'
|
||||
const { RelayPoolModule } = NativeModules
|
||||
|
||||
interface RelayPoolInterface {
|
||||
send: (message: string) => void
|
||||
send: (message: string, globalFeed: boolean) => void
|
||||
connect: (pubKey: string, callback: (eventId: string) => void) => void
|
||||
add: (url: string, callback: () => void) => void
|
||||
remove: (url: string, callback: () => void) => void
|
||||
active: (url: string, callback: () => void) => void
|
||||
desactive: (url: string, callback: () => void) => void
|
||||
update: (relayUrl: string, active: number, globalfeed: number, callback?: () => void) => void
|
||||
onEventId: (callback: (eventId: string) => void) => void
|
||||
}
|
||||
|
||||
|
@ -26,9 +26,12 @@ class RelayPool {
|
||||
private readonly privateKey?: string
|
||||
private subscriptions: Record<string, string[]>
|
||||
|
||||
private readonly send: (message: object) => void = async (message) => {
|
||||
private readonly send: (message: object, globalFeed?: boolean) => void = async (
|
||||
message,
|
||||
globalFeed,
|
||||
) => {
|
||||
const tosend = JSON.stringify(message)
|
||||
RelayPoolModule.send(tosend)
|
||||
RelayPoolModule.send(tosend, globalFeed ?? false)
|
||||
}
|
||||
|
||||
public readonly connect: (publicKey: string, onEventId: (eventId: string) => void) => void =
|
||||
@ -50,18 +53,13 @@ class RelayPool {
|
||||
RelayPoolModule.remove(relayUrl, callback)
|
||||
}
|
||||
|
||||
public readonly active: (relayUrl: string, callback?: () => void) => void = async (
|
||||
relayUrl,
|
||||
callback = () => {},
|
||||
) => {
|
||||
RelayPoolModule.active(relayUrl, callback)
|
||||
}
|
||||
|
||||
public readonly desactive: (relayUrl: string, callback?: () => void) => void = async (
|
||||
relayUrl,
|
||||
callback = () => {},
|
||||
) => {
|
||||
RelayPoolModule.desactive(relayUrl, callback)
|
||||
public readonly update: (
|
||||
relayUrl: string,
|
||||
active: number,
|
||||
globalfeed: number,
|
||||
callback?: () => void,
|
||||
) => void = async (relayUrl, active, globalfeed, callback = () => {}) => {
|
||||
RelayPoolModule.update(relayUrl, active, globalfeed, callback)
|
||||
}
|
||||
|
||||
public readonly sendEvent: (event: Event) => Promise<Event | null> = async (event) => {
|
||||
@ -89,7 +87,7 @@ class RelayPool {
|
||||
if (this.subscriptions[subId]?.includes(id)) {
|
||||
console.log('Subscription already done!', subId)
|
||||
} else {
|
||||
this.send([...['REQ', subId], ...(filters ?? [])])
|
||||
this.send([...['REQ', subId], ...(filters ?? [])], subId.includes('-global-'))
|
||||
const newSubscriptions = [...(this.subscriptions[subId] ?? []), id]
|
||||
this.subscriptions[subId] = newSubscriptions
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user