Smooth event navigation and profile load

This commit is contained in:
KoalaSat 2022-10-29 19:56:49 +02:00
parent 02a9150423
commit 76f1295a23
No known key found for this signature in database
GPG Key ID: 2F7F61C6146AB157
8 changed files with 75 additions and 27 deletions

View File

@ -25,6 +25,7 @@ export const ConfigPage: React.FC = () => {
}, []);
const onPressBack: () => void = () => {
relayPool?.unsubscribeAll();
goBack();
};

View File

@ -46,6 +46,7 @@ export const ContactsPage: React.FC = () => {
console.log('RELAYPOOL EVENT =======>', relay.url, event);
if (database && event?.id && event.kind === EventKind.petNames) {
insertUserContact(event, database).finally(() => setLastEventId(event?.id ?? ''));
relayPool?.removeOn('event', 'contacts');
}
});
}, []);

View File

@ -56,7 +56,7 @@ export const Logger: React.FC = () => {
const initEvents: () => void = () => {
relayPool?.on('event', 'landing', (_relay: Relay, _subId?: string, event?: Event) => {
console.log('LandingPage EVENT =======>', event);
console.log('LANDING EVENT =======>', event);
if (event && database) {
if (event.kind === EventKind.petNames) {
loadPets(event);

View File

@ -24,23 +24,23 @@ export const NotePage: React.FC = () => {
const { page, goBack, goToPage, database } = useContext(AppContext);
const { lastEventId, relayPool } = useContext(RelayPoolContext);
const [note, setNote] = useState<Note>();
const [replies, setReplies] = useState<Note[]>([]);
const [replies, setReplies] = useState<Note[]>();
const theme = useTheme();
const { t } = useTranslation('common');
const breadcrump = page.split('%');
const eventId = breadcrump[breadcrump.length - 1].split('#')[1];
useEffect(() => {
const reload: () => void = () => {
setNote(undefined);
setReplies(undefined);
relayPool?.unsubscribeAll();
relayPool?.subscribe('main-channel', {
kinds: [EventKind.textNote, EventKind.recommendServer],
kinds: [EventKind.textNote],
ids: [eventId],
});
relayPool?.subscribe('main-channel', {
kinds: [EventKind.textNote, EventKind.recommendServer],
'#e': [eventId],
});
}, []);
};
useEffect(reload, []);
useEffect(() => {
if (database) {
@ -48,13 +48,19 @@ export const NotePage: React.FC = () => {
if (events.length > 0) {
const event = events[0];
setNote(event);
if (!replies) {
relayPool?.subscribe('main-channel', {
kinds: [EventKind.textNote],
'#e': [eventId],
});
}
getNotes(database, { filters: { reply_event_id: eventId } }).then((notes) => {
const rootReplies = getDirectReplies(notes, event);
const rootReplies = getDirectReplies(event, notes);
if (rootReplies.length > 0) {
setReplies(rootReplies as Note[]);
const message: RelayFilters = {
kinds: [EventKind.meta],
authors: rootReplies.map((note) => note.pubkey),
authors: [...rootReplies.map((note) => note.pubkey), event.pubkey],
};
relayPool?.subscribe('main-channel', message);
} else {
@ -67,9 +73,20 @@ export const NotePage: React.FC = () => {
}, [lastEventId, page]);
const onPressBack: () => void = () => {
relayPool?.unsubscribeAll();
goBack();
};
const onPressGoParent: () => void = () => {
if (note) {
const replyId = getReplyEventId(note);
if (replyId) {
goToPage(`note#${replyId}`);
reload();
}
}
};
const renderBackAction = (): JSX.Element => {
return (
<TopNavigationAction
@ -79,6 +96,17 @@ export const NotePage: React.FC = () => {
);
};
const renderNoteActions = (): JSX.Element => {
return note && getReplyEventId(note) ? (
<TopNavigationAction
icon={<Icon name='arrow-up' size={16} color={theme['text-basic-color']} />}
onPress={onPressGoParent}
/>
) : (
<></>
);
};
const onPressNote: (note: Note) => void = (note) => {
if (note.kind !== EventKind.recommendServer) {
const replyEventId = getReplyEventId(note);
@ -87,7 +115,7 @@ export const NotePage: React.FC = () => {
} else if (note.id) {
goToPage(`note#${note.id}`);
}
setReplies([]);
reload();
}
};
@ -127,10 +155,11 @@ export const NotePage: React.FC = () => {
alignment='center'
title={`${eventId.slice(0, 12)}...${eventId.slice(-12)}`}
accessoryLeft={renderBackAction}
accessoryRight={renderNoteActions}
/>
<Layout level='4'>
{note ? (
<List data={[note, ...replies]} renderItem={(item) => ItemCard(item?.item)} />
<List data={[note, ...(replies ?? [])]} renderItem={(item) => ItemCard(item?.item)} />
) : (
<Loading style={styles.loading} />
)}

View File

@ -48,7 +48,6 @@ export const ProfilePage: React.FC = () => {
useEffect(() => {
setNotes(undefined);
setUser(undefined);
relayPool?.unsubscribeAll();
relayPool?.subscribe('main-channel', {
kinds: [EventKind.meta, EventKind.petNames],
authors: [userId],
@ -121,7 +120,7 @@ export const ProfilePage: React.FC = () => {
if (publicKey === userId) {
return (
<TopNavigationAction
icon={<Icon name='dna' size={16} color={theme['text-basic-color']} solid />}
icon={<Icon name='cog' size={16} color={theme['text-basic-color']} solid />}
onPress={() => goToPage('config')}
/>
);
@ -149,6 +148,8 @@ export const ProfilePage: React.FC = () => {
};
const onPressBack: () => void = () => {
relayPool?.removeOn('event', 'profile');
relayPool?.unsubscribeAll();
goBack();
};

View File

@ -11,7 +11,7 @@ import React, { useContext, useEffect, useState } from 'react';
import { StyleSheet } from 'react-native';
import { AppContext } from '../../Contexts/AppContext';
import Icon from 'react-native-vector-icons/FontAwesome5';
import { Event } from '../../lib/nostr/Events';
import { Event, EventKind } from '../../lib/nostr/Events';
import { useTranslation } from 'react-i18next';
import { RelayPoolContext } from '../../Contexts/RelayPoolContext';
import moment from 'moment';
@ -75,12 +75,19 @@ export const SendPage: React.FC = () => {
const event: Event = {
content,
created_at: moment().unix(),
kind: 1,
kind: EventKind.textNote,
pubkey: publicKey,
tags,
};
relayPool?.sendEvent(event);
setNoteId(note.id);
relayPool?.sendEvent(event).then((sentNote) => {
if (sentNote?.id) {
relayPool?.subscribe('main-channel', {
kinds: [EventKind.textNote],
ids: [sentNote.id],
});
setNoteId(sentNote.id);
}
});
setSending(true);
});
}

View File

@ -74,7 +74,9 @@ export const RelayPoolContextProvider = ({
(relay: Relay, _subId?: string, event?: Event) => {
console.log('RELAYPOOL EVENT =======>', relay.url, event);
if (database && event?.id && event.kind !== EventKind.petNames) {
storeEvent(event, database).finally(() => setLastEventId(event.id));
storeEvent(event, database)
.then(() => setLastEventId(event.id))
.catch(() => setLastEventId(event.id));
}
},
);

View File

@ -26,14 +26,21 @@ export const getReplyEventId: (event: Event) => string | null = (event) => {
return mainTag ? mainTag[1] : null;
};
export const getDirectReplies: (replies: Event[], event: Event) => Event[] = (replies, event) => {
const expectedTags: number = getETags(event).length + 1;
const filter = replies.filter((event) => {
const eventETags = getETags(event);
return eventETags.length === expectedTags;
});
export const getDirectReplies: (event: Event, replies: Event[]) => Event[] = (event, replies) => {
return replies.filter((item) => isDirectReply(event, item));
};
return filter;
export const isDirectReply: (mainEvent: Event, reply: Event) => boolean = (mainEvent, reply) => {
const taggedMainEventsIds: string[] = getTaggedEventIds(mainEvent);
const taggedReplyEventsIds: string[] = getTaggedEventIds(reply);
const difference = taggedReplyEventsIds.filter((item) => !taggedMainEventsIds.includes(item));
return difference.length === 1 && difference[0] === mainEvent.id;
};
export const getTaggedEventIds: (event: Event) => string[] = (event) => {
const mainEventETags: string[][] = getETags(event);
return mainEventETags.map((item) => item[1] ?? '');
};
export const getETags: (event: Event) => string[][] = (event) => {