UI improvement and relay deletion (#364)

This commit is contained in:
KoalaSat 2023-02-21 14:42:12 +00:00 committed by GitHub
commit 68cfd0452e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 545 additions and 127 deletions

View File

@ -18,15 +18,47 @@ jobs:
go install github.com/fiatjaf/noscl@latest
~/go/bin/noscl setprivate '${{ secrets.NOSTROS_PRIVATE_KEY }}'
~/go/bin/noscl relay add "wss://brb.io"
~/go/bin/noscl relay add "wss://damus.io"
~/go/bin/noscl relay add "wss://nostr-pub.wellorder.net"
~/go/bin/noscl relay add "wss://nostr.swiss-enigma.ch"
~/go/bin/noscl relay add "wss://nostr.onsats.org"
~/go/bin/noscl relay add "wss://nostr-pub.semisol.dev"
~/go/bin/noscl relay add "wss://nostr.openchain.fr"
~/go/bin/noscl relay add "wss://relay.nostr.info"
~/go/bin/noscl relay add "wss://nostr.oxtr.dev"
~/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 relay add "wss://nostr.oxtr.dev"
~/go/bin/noscl relay add "wss://nostr.swiss-enigma.ch"
~/go/bin/noscl relay add "wss://relay.nostr.snblago.com"
~/go/bin/noscl relay add "wss://nos.lol"
~/go/bin/noscl relay add "wss://relay.austrich.net"
~/go/bin/noscl relay add "wss://nostr.cro.social"
~/go/bin/noscl relay add "wss://relay.koreus.social"
~/go/bin/noscl relay add "wss://spore.ws"
~/go/bin/noscl relay add "wss://nostr.web3infra.xyz"
~/go/bin/noscl relay add "wss://nostr.snblago.com"
~/go/bin/noscl relay add "wss://relay.nostrified.org"
~/go/bin/noscl relay add "wss://relay.ryzizub.com"
~/go/bin/noscl relay add "wss://relay.wellorder.net"
~/go/bin/noscl relay add "wss://nostr.btcmp.com"
~/go/bin/noscl relay add "wss://relay.nostromo.social"
~/go/bin/noscl relay add "wss://relay.stoner.com"
~/go/bin/noscl relay add "wss://nostr.massmux.com"
~/go/bin/noscl relay add "wss://nostr.robotesc.ro"
~/go/bin/noscl relay add "wss://relay.humanumest.social"
~/go/bin/noscl relay add "wss://relay-local.cowdle.gg"
~/go/bin/noscl relay add "wss://nostr-2.afarazit.eu"
~/go/bin/noscl relay add "wss://nostr.data.haus"
~/go/bin/noscl relay add "wss://nostr-pub.wellorder.net"
~/go/bin/noscl relay add "wss://nostr.thank.eu"
~/go/bin/noscl relay add "wss://relay-dev.cowdle.gg"
~/go/bin/noscl relay add "wss://nostrsxz4lbwe-nostr.functions.fnc.fr-par.scw.cloud"
~/go/bin/noscl relay add "wss://relay.nostrcheck.me"
~/go/bin/noscl relay add "wss://relay.nostrich.de"
~/go/bin/noscl relay add "wss://nostr.com.de"
~/go/bin/noscl relay add "wss://relay.nostr.scot"
~/go/bin/noscl relay add "wss://nostr.8e23.net"
~/go/bin/noscl relay add "wss://nostr.mouton.dev"
~/go/bin/noscl relay add "wss://nostr.l00p.org"
~/go/bin/noscl relay add "wss://nostr.island.network"
~/go/bin/noscl relay add "wss://nostr.handyjunky.com"
~/go/bin/noscl relay add "wss://relay.valera.co"
~/go/bin/noscl relay add "wss://relay.nostr.vet"
~/go/bin/noscl relay add "wss://tmp-relay.cesc.trade"
~/go/bin/noscl relay add "wss://relay.dwadziesciajeden.pl"
~/go/bin/noscl relay add "wss://nostr-1.afarazit.eu"
~/go/bin/noscl relay add "wss://lbrygen.xyz"
~/go/bin/noscl publish "${{ github.event.release.body }}"

View File

@ -183,7 +183,7 @@ public class Event {
String name = parts[0];
String domain = parts[1];
if (!name.matches("^[a-z0-9-_]+$")) return false;
if (!name.matches("^[a-zA-Z0-9-_]+$")) return false;
try {
String url = "https://" + domain + "/.well-known/nostr.json?name=" + name;
@ -575,6 +575,7 @@ public class Event {
values.put("active", 0);
values.put("global_feed", 0);
values.put("manual", 1);
values.put("deleted_at", 0);
database.insert("nostros_relays", null, values);
} else if (cursor.moveToFirst() && created_at > cursor.getInt(0)) {
values.put("updated_at", created_at);

View File

@ -52,14 +52,17 @@ public class Relay {
values.put("url", url);
values.put("active", active);
values.put("global_feed", globalFeed);
values.put("deleted_at", 0);
database.replace("nostros_relays", null, values);
}
public void destroy(SQLiteDatabase database) {
public void delete(SQLiteDatabase database) {
String whereClause = "url = ?";
String[] whereArgs = new String[] {
url
};
database.delete ("nostros_relays", whereClause, whereArgs);
ContentValues values = new ContentValues();
values.put("deleted_at", System.currentTimeMillis() / 1000L);
database.update ("nostros_relays", values, whereClause, whereArgs);
}
}

View File

@ -196,6 +196,9 @@ public class DatabaseModule {
" );");
database.execSQL("CREATE INDEX nostros_nostros_zaps_zapped_event_id_index ON nostros_zaps(zapped_event_id);");
} catch (SQLException e) { }
try {
database.execSQL("ALTER TABLE nostros_relays ADD COLUMN deleted_at INT DEFAULT 0;");
} catch (SQLException e) { }
}
public void saveEvent(JSONObject data, String userPubKey, String relayUrl) throws JSONException {
@ -207,13 +210,13 @@ public class DatabaseModule {
relay.save(database);
}
public void destroyRelay(Relay relay) {
relay.destroy(database);
public void deleteRelay(Relay relay) {
relay.delete(database);
}
public List<Relay> getRelays(ReactApplicationContext reactContext) {
List<Relay> relayList = new ArrayList<>();
String query = "SELECT url, active, global_feed FROM nostros_relays;";
String query = "SELECT url, active, global_feed FROM nostros_relays WHERE deleted_at = 0 AND active = 1;";
@SuppressLint("Recycle") Cursor cursor = database.rawQuery(query, new String[] {});
if (cursor.getCount() > 0) {
cursor.moveToFirst();

View File

@ -55,7 +55,7 @@ public class RelayPoolModule extends ReactContextBaseJavaModule {
if(url.equals(relay.url)){
relay.disconnect();
iterator.remove();
database.destroyRelay(relay);
database.deleteRelay(relay);
}
}

View File

@ -8,16 +8,28 @@ import RBSheet from 'react-native-raw-bottom-sheet'
import { getNevent } from '../../lib/nostr/Nip19'
import QRCode from 'react-native-qrcode-svg'
import { Group } from '../../Functions/DatabaseFunctions/Groups'
import { getNoteRelays } from '../../Functions/DatabaseFunctions/Notes'
import { AppContext } from '../../Contexts/AppContext'
interface GroupShareProps {
group: Group
}
export const GroupShare: React.FC<GroupShareProps> = ({ group }) => {
const { database } = React.useContext(AppContext)
const bottomSheetShareRef = React.useRef<RBSheet>(null)
const [qrCode, setQrCode] = React.useState<any>()
const [showNotification, setShowNotification] = React.useState<undefined | string>()
const nEvent = React.useMemo(() => getNevent(group.id), [group])
const [nEvent, setNevent] = React.useState<undefined | string>()
React.useEffect(() => {
if (database && group.id) {
getNoteRelays(database, group.id).then((results) => {
const urls = results.map((item) => item.relay_url)
setNevent(getNevent(group.id, [...new Set(urls)]))
})
}
}, [group, database])
return (
<View style={styles.mainLayout}>

View File

@ -0,0 +1,182 @@
import { t } from 'i18next'
import * as React from 'react'
import { StyleSheet, TouchableNativeFeedback, View } from 'react-native'
import { IconButton, Text, useTheme } from 'react-native-paper'
import { AppContext } from '../../Contexts/AppContext'
import RBSheet from 'react-native-raw-bottom-sheet'
import { getNoteRelays, getNotes, Note, NoteRelay } from '../../Functions/DatabaseFunctions/Notes'
import Clipboard from '@react-native-clipboard/clipboard'
import NoteShare from '../NoteShare'
import { navigate } from '../../lib/Navigation'
import { relayToColor } from '../../Functions/NativeFunctions'
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
import { formatId } from '../../Functions/RelayFunctions/Users'
interface NoteActionsProps {
bottomSheetRef: React.RefObject<RBSheet>
}
export const NoteActions: React.FC<NoteActionsProps> = ({ bottomSheetRef }) => {
const theme = useTheme()
const { database, displayNoteDrawer, relayColouring } = React.useContext(AppContext)
const { setDisplayrelayDrawer } = React.useContext(RelayPoolContext)
const [note, setNote] = React.useState<Note>()
const [relays, setRelays] = React.useState<NoteRelay[]>([])
const bottomSheetShareRef = React.useRef<RBSheet>(null)
React.useEffect(() => {
loadNote()
}, [displayNoteDrawer])
const loadNote: () => void = () => {
if (database && displayNoteDrawer) {
getNotes(database, { filters: { id: displayNoteDrawer } }).then((results) => {
if (results.length > 0) {
setNote(results[0])
}
})
getNoteRelays(database, displayNoteDrawer).then(setRelays)
}
}
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}>
<Text variant='titleMedium'>{formatId(note?.id)}</Text>
<View style={styles.mainLayout}>
<View style={styles.actionButton}>
<IconButton
icon='eye'
size={28}
onPress={() => {
bottomSheetRef.current?.close()
navigate('Note', { noteId: note?.id })
}}
/>
<Text>{t('noteActions.view')}</Text>
</View>
<View style={styles.actionButton}>
<IconButton
icon='content-copy'
size={28}
onPress={() => {
note?.content && Clipboard.setString(note?.content)
bottomSheetRef.current?.close()
}}
/>
<Text>{t('noteActions.copy')}</Text>
</View>
<View style={styles.actionButton}>
<IconButton
icon='share-variant-outline'
size={28}
onPress={() => bottomSheetShareRef.current?.open()}
/>
<Text>{t('noteActions.share')}</Text>
</View>
</View>
<View style={styles.relayList}>
{relayColouring &&
relays.map((relay, index) => (
<TouchableNativeFeedback onPress={() => setDisplayrelayDrawer(relay.relay_url)} key={relay.relay_url}>
<View
style={[
styles.relay,
{ backgroundColor: relayToColor(relay.relay_url) },
index === 0 ? { borderBottomLeftRadius: 50, borderTopLeftRadius: 50 } : {},
index === relays.length - 1
? { borderBottomRightRadius: 50, borderTopRightRadius: 50 }
: {},
]}
/>
</TouchableNativeFeedback>
))}
</View>
{note && (
<RBSheet
ref={bottomSheetShareRef}
closeOnDragDown={true}
customStyles={bottomSheetStyles}
onClose={() => bottomSheetRef.current?.close()}
>
<NoteShare note={note} />
</RBSheet>
)}
</View>
)
}
const styles = StyleSheet.create({
relayList: {
flexDirection: 'row',
marginTop: 16,
},
container: {
width: '100%',
paddingRight: 16,
paddingLeft: 16,
},
relayColor: {
paddingTop: 9,
},
mainLayout: {
flexDirection: 'row',
justifyContent: 'space-between',
marginTop: 16,
marginBottom: 16
},
actionButton: {
alignItems: 'center',
},
snackbar: {
marginLeft: 16,
bottom: 16,
},
switch: {
marginLeft: 32,
},
listHeader: {
paddingRight: 5,
paddingLeft: 16,
textAlign: 'center',
},
warning: {
borderRadius: 4,
padding: 16,
marginTop: 16,
marginBottom: 16,
},
warningTitle: {
marginBottom: 8,
},
buttonSpacer: {
marginTop: 16,
marginBottom: 16,
},
muteContainer: {
paddingRight: 16,
},
relaysList: {
maxHeight: '90%',
},
relay: {
flex: 1,
height: 10,
},
})
export default NoteActions

View File

@ -15,8 +15,7 @@ import { t } from 'i18next'
import { isContentWarning } from '../../Functions/RelayFunctions/Events'
import { Event } from '../../lib/nostr/Events'
import { getUnixTime } from 'date-fns'
import { populateRelay } from '../../Functions/RelayFunctions'
import { searchRelays } from '../../Functions/DatabaseFunctions/Relays'
import { Relay, searchRelays } from '../../Functions/DatabaseFunctions/Relays'
import TextContent from '../../Components/TextContent'
import { formatPubKey } from '../../Functions/RelayFunctions/Users'
import { getReactions } from '../../Functions/DatabaseFunctions/Reactions'
@ -30,6 +29,7 @@ import {
TouchableRipple,
Chip,
Surface,
IconButton,
} from 'react-native-paper'
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
import { REGEX_SOCKET_LINK } from '../../Constants/Relay'
@ -74,9 +74,16 @@ export const NoteCard: React.FC<NoteCardProps> = ({
}) => {
const theme = useTheme()
const { publicKey, privateKey } = React.useContext(UserContext)
const { relayPool, lastEventId, setDisplayrelayDrawer } = useContext(RelayPoolContext)
const { database, showSensitive, setDisplayUserDrawer, relayColouring, longPressZap } =
useContext(AppContext)
const { relayPool, lastEventId, addRelayItem } =
useContext(RelayPoolContext)
const {
database,
showSensitive,
setDisplayUserDrawer,
setDisplayNoteDrawer,
relayColouring,
longPressZap,
} = useContext(AppContext)
const [relayAdded, setRelayAdded] = useState<boolean>(false)
const [positiveReactions, setPositiveReactions] = useState<number>(0)
const [negativeReactions, setNegativeReactions] = useState<number>(0)
@ -228,15 +235,8 @@ export const NoteCard: React.FC<NoteCardProps> = ({
}
const recommendServer: () => JSX.Element = () => {
const relayName = note?.content
const addRelayItem: () => void = () => {
if (relayPool && database && publicKey && note) {
relayPool.add(note.content, () => {
populateRelay(relayPool, database, publicKey)
setRelayAdded(true)
})
}
const relay: Relay = {
url: note?.content ?? '',
}
return (
@ -244,7 +244,7 @@ export const NoteCard: React.FC<NoteCardProps> = ({
<Card>
<Card.Title
title={t('noteCard.recommendation')}
subtitle={relayName}
subtitle={relay.url}
left={(props) => (
<Avatar.Icon
{...props}
@ -257,7 +257,7 @@ export const NoteCard: React.FC<NoteCardProps> = ({
/>
{!relayAdded && note && REGEX_SOCKET_LINK.test(note.content) && (
<Card.Content style={[styles.bottomActions, { borderColor: theme.colors.onSecondary }]}>
<Button mode='contained' onPress={addRelayItem}>
<Button mode='contained' onPress={async () => await addRelayItem(relay)}>
{t('noteCard.addRelay')}
</Button>
</Card.Content>
@ -404,18 +404,27 @@ export const NoteCard: React.FC<NoteCardProps> = ({
return note ? (
<Card mode={mode}>
<Card.Content style={styles.title}>
<TouchableRipple onPress={() => setDisplayUserDrawer(note.pubkey)}>
<ProfileData
username={note?.name}
publicKey={note.pubkey}
validNip05={note?.valid_nip05}
nip05={note?.nip05}
lnurl={note?.lnurl}
lnAddress={note?.ln_address}
picture={showAvatarImage ? note?.picture : undefined}
timestamp={note?.created_at}
<View>
<TouchableRipple onPress={() => setDisplayUserDrawer(note.pubkey)}>
<ProfileData
username={note?.name}
publicKey={note.pubkey}
validNip05={note?.valid_nip05}
nip05={note?.nip05}
lnurl={note?.lnurl}
lnAddress={note?.ln_address}
picture={showAvatarImage ? note?.picture : undefined}
timestamp={note?.created_at}
/>
</TouchableRipple>
</View>
<View style={styles.noteOptionsIcon}>
<IconButton
icon='dots-vertical'
size={28}
onPress={() => setDisplayNoteDrawer(note.id)}
/>
</TouchableRipple>
</View>
</Card.Content>
{getNoteContent()}
{showAction && (
@ -478,14 +487,11 @@ export const NoteCard: React.FC<NoteCardProps> = ({
{relayColouring &&
showRelayColors &&
relays.map((relay, index) => (
<TouchableNativeFeedback
onPress={() => setDisplayrelayDrawer(relay.relay_url)}
key={relay.relay_url}
>
<TouchableNativeFeedback key={relay.relay_url}>
<View
style={[
styles.relay,
{ backgroundColor: relayToColor(relay.relay_url) },
{ borderBottomColor: relayToColor(relay.relay_url) },
index === 0 ? { borderBottomLeftRadius: 50 } : {},
index === relays.length - 1 ? { borderBottomRightRadius: 50 } : {},
]}
@ -502,7 +508,7 @@ export const NoteCard: React.FC<NoteCardProps> = ({
const styles = StyleSheet.create({
relayList: {
flexDirection: 'row',
marginTop: 8,
bottom: 2,
marginBottom: -16,
marginLeft: -16,
marginRight: -16,
@ -510,6 +516,7 @@ const styles = StyleSheet.create({
relay: {
flex: 1,
height: 10,
borderBottomWidth: 2,
},
titleUsername: {
fontWeight: 'bold',
@ -529,6 +536,7 @@ const styles = StyleSheet.create({
},
title: {
flexDirection: 'row',
justifyContent: 'space-between',
paddingBottom: 16,
},
userBlockedWrapper: {
@ -580,6 +588,16 @@ const styles = StyleSheet.create({
paddingTop: 4,
paddingLeft: 5,
},
snackbar: {
marginBottom: 50,
marginLeft: 0,
width: '100%',
},
noteOptionsIcon: {
marginBottom: -16,
marginRight: -16,
marginTop: -8,
},
})
export default NoteCard

View File

@ -0,0 +1,111 @@
import { t } from 'i18next'
import * as React from 'react'
import { Dimensions, StyleSheet, View } from 'react-native'
import Clipboard from '@react-native-clipboard/clipboard'
import { IconButton, Snackbar, Text, TouchableRipple } from 'react-native-paper'
import Share from 'react-native-share'
import RBSheet from 'react-native-raw-bottom-sheet'
import QRCode from 'react-native-qrcode-svg'
import { useContext } from 'react'
import { AppContext } from '../../Contexts/AppContext'
import { getNoteRelays, Note } from '../../Functions/DatabaseFunctions/Notes'
import { getNevent } from '../../lib/nostr/Nip19'
interface NoteShareProps {
note: Note
}
export const NoteShare: React.FC<NoteShareProps> = ({ note }) => {
const { database } = useContext(AppContext)
const bottomSheetShareRef = React.useRef<RBSheet>(null)
const [qrCode, setQrCode] = React.useState<any>()
const [showNotification, setShowNotification] = React.useState<undefined | string>()
const [nEvent, setNevent] = React.useState<undefined | string>()
React.useEffect(() => {
if (database && note.id) {
getNoteRelays(database, note.id).then((results) => {
const urls = results.map((item) => item.relay_url)
setNevent(getNevent(note.id, [...new Set(urls)]))
})
}
}, [note, database])
return (
<View style={styles.mainLayout}>
<View style={styles.qr}>
<TouchableRipple
onPress={() => {
if (qrCode) {
qrCode.toDataURL((base64: string) => {
Share.open({
url: `data:image/png;base64,${base64}`,
filename: note?.id ?? 'nostrosshare',
})
})
}
}}
>
<QRCode
quietZone={8}
value={`nostr:${nEvent}`}
size={Dimensions.get('window').width - 64}
logoBorderRadius={50}
logoSize={100}
logo={{ uri: note?.picture }}
getRef={setQrCode}
/>
</TouchableRipple>
</View>
<View style={styles.shareActionButton}>
<IconButton
icon='key-outline'
size={28}
onPress={() => {
setShowNotification('npubCopied')
Clipboard.setString(nEvent ?? '')
bottomSheetShareRef.current?.close()
}}
/>
<Text>{t('profileShare.copyNPub')}</Text>
</View>
{showNotification && (
<Snackbar
style={styles.snackbar}
visible={showNotification !== undefined}
duration={Snackbar.DURATION_SHORT}
onIconPress={() => setShowNotification(undefined)}
onDismiss={() => setShowNotification(undefined)}
>
{t(`profileShare.notifications.${showNotification}`)}
</Snackbar>
)}
</View>
)
}
const styles = StyleSheet.create({
snackbar: {
marginBottom: 85,
width: '100%',
},
mainLayout: {
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'center',
justifyContent: 'flex-start',
},
qr: {
justifyContent: 'center',
alignItems: 'center',
padding: 16,
},
shareActionButton: {
justifyContent: 'center',
alignItems: 'center',
flexBasis: '100%',
marginBottom: 4,
},
})
export default NoteShare

View File

@ -277,6 +277,7 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({
closeOnDragDown={true}
customStyles={bottomSheetStyles}
dragFromTopOnly={true}
onClose={() => onActionDone()}
>
<View>
<Text variant='titleLarge'>{t('profileCard.relaysTitle')}</Text>
@ -309,10 +310,20 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({
</Snackbar>
)}
</RBSheet>
<RBSheet ref={bottomSheetShareRef} closeOnDragDown={true} customStyles={bottomSheetStyles}>
<RBSheet
ref={bottomSheetShareRef}
closeOnDragDown={true}
customStyles={bottomSheetStyles}
onClose={() => onActionDone()}
>
<ProfileShare user={user} />
</RBSheet>
<RBSheet ref={bottomSheetMuteRef} closeOnDragDown={true} customStyles={bottomSheetStyles}>
<RBSheet
ref={bottomSheetMuteRef}
closeOnDragDown={true}
customStyles={bottomSheetStyles}
onClose={() => onActionDone()}
>
<View style={styles.muteContainer}>
<Text variant='titleLarge'>
{t('profileCard.muteUser', { username: username(user) })}

View File

@ -60,12 +60,11 @@ export const ProfileData: React.FC<ProfileCardProps> = ({
<></>
)}
</View>
<Text numberOfLines={1}>{validNip05 ? getNip05Domain(nip05) : ''}</Text>
</View>
</View>
<View style={styles.right}>
<View style={styles.date}>
<Text numberOfLines={1}>{date ?? ''}</Text>
<Text numberOfLines={1}>
{timestamp ?
date
: validNip05 ? getNip05Domain(nip05) : ''}
</Text>
</View>
</View>
</View>
@ -73,14 +72,8 @@ export const ProfileData: React.FC<ProfileCardProps> = ({
}
const styles = StyleSheet.create({
right: {
flexDirection: 'row',
width: '50%',
justifyContent: 'flex-end',
},
left: {
flexDirection: 'row',
width: '50%',
},
container: {
flexDirection: 'row',

View File

@ -57,7 +57,7 @@ export const RelayCard: React.FC<RelayCardProps> = ({ url, bottomSheetRef }) =>
React.useEffect(() => {
loadRelay()
}, [])
}, [url])
React.useEffect(() => {
if (pushUserHistoric && url && database && publicKey && relayPool) {
@ -103,7 +103,7 @@ export const RelayCard: React.FC<RelayCardProps> = ({ url, bottomSheetRef }) =>
relayPool.sendEvent(group, url)
})
})
sendRelays(relays, url)
sendRelays(url)
}
}, [pushUserHistoric])
@ -133,9 +133,8 @@ export const RelayCard: React.FC<RelayCardProps> = ({ url, bottomSheetRef }) =>
const removeRelay: () => void = () => {
if (relay) {
removeRelayItem(relay).then(() => {
bottomSheetRef.current?.close()
})
removeRelayItem(relay)
bottomSheetRef.current?.close()
}
}

View File

@ -35,6 +35,8 @@ export interface AppContextProps {
checkClipboard: () => void
displayUserDrawer?: string
setDisplayUserDrawer: (displayUserDrawer: string | undefined) => void
displayNoteDrawer?: string
setDisplayNoteDrawer: (displayNoteDrawer: string | undefined) => void
refreshBottomBarAt?: number
setRefreshBottomBarAt: (refreshBottomBarAt: number) => void
longPressZap?: number | undefined
@ -78,6 +80,7 @@ export const initialAppContext: AppContextProps = {
getSatoshiSymbol: () => <></>,
setClipboardNip21: () => {},
setDisplayUserDrawer: () => {},
setDisplayNoteDrawer: () => {},
longPressZap: undefined,
setLongPressZap: () => {},
}
@ -105,6 +108,7 @@ export const AppContextProvider = ({ children }: AppContextProviderProps): JSX.E
const [clipboardLoads, setClipboardLoads] = React.useState<string[]>([])
const [clipboardNip21, setClipboardNip21] = React.useState<string>()
const [displayUserDrawer, setDisplayUserDrawer] = React.useState<string>()
const [displayNoteDrawer, setDisplayNoteDrawer] = React.useState<string>()
const [pushedTab, setPushedTab] = useState<string>()
useEffect(() => {
@ -238,6 +242,8 @@ export const AppContextProvider = ({ children }: AppContextProviderProps): JSX.E
setPushedTab,
longPressZap,
setLongPressZap,
displayNoteDrawer,
setDisplayNoteDrawer
}}
>
{children}

View File

@ -7,7 +7,7 @@ import { getActiveRelays, getRelays, Relay } from '../Functions/DatabaseFunction
import { UserContext } from './UserContext'
import { randomInt } from '../Functions/NativeFunctions'
import { getUnixTime } from 'date-fns'
import { Event } from '../../lib/nostr/Events'
import { Event } from '../lib/nostr/Events'
export interface RelayPoolContextProps {
relayPoolReady: boolean
@ -21,7 +21,7 @@ export interface RelayPoolContextProps {
addRelayItem: (relay: Relay) => Promise<void>
removeRelayItem: (relay: Relay) => Promise<void>
updateRelayItem: (relay: Relay) => Promise<void>
sendRelays: (relays: Relay[], url?: string) => Promise<void>
sendRelays: (url?: string) => Promise<void>
}
export interface WebsocketEvent {
@ -36,12 +36,12 @@ export interface RelayPoolContextProviderProps {
export const initialRelayPoolContext: RelayPoolContextProps = {
relayPoolReady: true,
setRelayPool: () => {},
addRelayItem: async () => await new Promise(() => {}),
removeRelayItem: async () => await new Promise(() => {}),
updateRelayItem: async () => await new Promise(() => {}),
addRelayItem: async () => {},
removeRelayItem: async () => {},
updateRelayItem: async () => {},
relays: [],
setDisplayrelayDrawer: () => {},
sendRelays: () => {},
sendRelays: async () => {},
}
export const RelayPoolContextProvider = ({
@ -58,16 +58,20 @@ export const RelayPoolContextProvider = ({
const [relays, setRelays] = React.useState<Relay[]>([])
const [displayRelayDrawer, setDisplayrelayDrawer] = React.useState<string>()
const sendRelays: (relayList: Relay[], url?: string) => void = (relayList, url) => {
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 ?? '']),
}
url ? relayPool?.sendEvent(event, url) : relayPool?.sendEvent(event)
const sendRelays: (url?: string) => Promise<void> = async (url) => {
if (publicKey && database) {
getActiveRelays(database).then((results) => {
if (publicKey && results.length > 0) {
const event: Event = {
content: '',
created_at: getUnixTime(new Date()),
kind: 1002,
pubkey: publicKey,
tags: results.map((relay) => ['r', relay.url, relay.mode ?? '']),
}
url ? relayPool?.sendEvent(event, url) : relayPool?.sendEvent(event)
}
})
}
}
@ -146,8 +150,8 @@ export const RelayPoolContextProvider = ({
return await new Promise((resolve, _reject) => {
if (relayPool && database && publicKey) {
relayPool.add(relay.url, () => {
loadRelays().then((results) => {
sendRelays(results)
loadRelays().then(() => {
sendRelays()
resolve()
})
})
@ -160,8 +164,8 @@ export const RelayPoolContextProvider = ({
return await new Promise((resolve, _reject) => {
if (relayPool && database && publicKey) {
relayPool.remove(relay.url, () => {
loadRelays().then((results) => {
sendRelays(results)
loadRelays().then(() => {
sendRelays()
resolve()
})
})

View File

@ -31,7 +31,7 @@ export const searchRelays: (
relayUrl: string,
db: QuickSQLiteConnection,
) => Promise<Relay[]> = async (relayUrl, db) => {
const searchQuery = `SELECT * FROM nostros_relays WHERE url = '${relayUrl}';`
const searchQuery = `SELECT * FROM nostros_relays WHERE url = '${relayUrl}' AND deleted_at = 0;`
const results = await db.execute(searchQuery)
const items: object[] = getItems(results)
const relays: Relay[] = items.map((object) => databaseToEntity(object))
@ -39,7 +39,7 @@ export const searchRelays: (
}
export const getRelays: (db: QuickSQLiteConnection) => Promise<Relay[]> = async (db) => {
const notesQuery = 'SELECT * FROM nostros_relays;'
const notesQuery = 'SELECT * FROM nostros_relays WHERE deleted_at = 0;'
const resultSet = await db.execute(notesQuery)
const items: object[] = getItems(resultSet)
const relays: Relay[] = items.map((object) => databaseToEntity(object))
@ -47,7 +47,7 @@ export const getRelays: (db: QuickSQLiteConnection) => Promise<Relay[]> = async
}
export const getActiveRelays: (db: QuickSQLiteConnection) => Promise<Relay[]> = async (db) => {
const notesQuery = 'SELECT * FROM nostros_relays WHERE active = 1;'
const notesQuery = 'SELECT * FROM nostros_relays WHERE active = 1 AND deleted_at = 0;'
const resultSet = await db.execute(notesQuery)
const items: object[] = getItems(resultSet)
const relays: Relay[] = items.map((object) => databaseToEntity(object))
@ -58,23 +58,13 @@ export const getRelay: (db: QuickSQLiteConnection, url: string) => Promise<Relay
db,
url,
) => {
const notesQuery = 'SELECT * FROM nostros_relays WHERE url = ?;'
const notesQuery = 'SELECT * FROM nostros_relays WHERE url = ? AND deleted_at = 0;'
const resultSet = await db.execute(notesQuery, [url])
const items: object[] = getItems(resultSet)
const relays: Relay[] = items.map((object) => databaseToEntity(object))
return relays[0]
}
export const createRelay: (db: QuickSQLiteConnection, url: string) => Promise<QueryResult> = async (
db,
url,
) => {
const query = `
INSERT OR IGNORE INTO nostros_relays (url) VALUES (?)
`
return db.execute(query, [url])
}
export const createResilientRelay: (
db: QuickSQLiteConnection,
url: string,

View File

@ -1,12 +0,0 @@
import RelayPool from '../../lib/nostr/RelayPool/intex'
import { QuickSQLiteConnection } from 'react-native-quick-sqlite'
import { populatePets, populateProfile } from './Users'
export const populateRelay: (
relayPool: RelayPool,
database: QuickSQLiteConnection,
publicKey: string,
) => void = (relayPool, database, publicKey) => {
populateProfile(relayPool, database, publicKey)
populatePets(relayPool, database, publicKey)
}

View File

@ -93,7 +93,15 @@
"update": "Update",
"disable": "Disable"
},
"noteActions": {
"copy": "Kopieren",
"share": "Teilen",
"view": "View"
},
"noteCard": {
"notifications": {
"zapServerError": "There was an error on the server while trying to request for the invoice."
},
"answering": "{{pubkey}} antworten",
"reposting": "{{pubkey}} reposten",
"seeParent": "Notiz ansehen",
@ -233,7 +241,6 @@
"alreadyExists": "Relay existiert bereits"
}
},
"relayCard": {
"pushDone": "Fertig",
"pushHistoricTitle": "Alle meine Daten hochladen",
@ -269,7 +276,6 @@
"pushCompleted": "All your data has been pushed."
}
},
"profileConfigPage": {
"notifications": {
"nsecCopied": "Privater Schlüssel kopiert.",
@ -368,7 +374,6 @@
"copyNip05": "NIP-05 kopieren",
"copyNPub": "Schlüssel kopieren"
},
"profileCard": {
"notifications": {
"contactAdded": "Aboniert",
@ -400,4 +405,4 @@
"emptyButton": "Unterhaltung beginnen"
}
}
}
}

View File

@ -93,7 +93,15 @@
"update": "Update",
"disable": "Disable"
},
"noteActions": {
"copy": "Copy",
"share": "Share",
"view": "View"
},
"noteCard": {
"notifications": {
"zapServerError": "There was an error on the server while trying to request for the invoice."
},
"answering": "Answer to {{pubkey}}",
"reposting": "Reposted {{pubkey}}",
"userBlocked": "User blocked",
@ -403,4 +411,4 @@
"emptyButton": "Open a conversation"
}
}
}
}

View File

@ -114,7 +114,15 @@
"update": "Actualizar",
"disable": "Desabilitar"
},
"noteActions": {
"copy": "Copiar",
"share": "Compartir",
"view": "Ver"
},
"noteCard": {
"notifications": {
"zapServerError": "Ha ocurrido un error en el servidor mientras se intentaba obtener la factura."
},
"answering": "Responder a {{pubkey}}",
"reposting": "Reposted {{pubkey}}",
"seeParent": "Ver nota",
@ -382,4 +390,4 @@
"emptyButton": "Abrir una conversación"
}
}
}
}

View File

@ -121,7 +121,15 @@
"update": "Update",
"disable": "Disable"
},
"noteActions": {
"copy": "Copier",
"share": "Partager",
"view": "View"
},
"noteCard": {
"notifications": {
"zapServerError": "There was an error on the server while trying to request for the invoice."
},
"answering": "Répondre à {{pubkey}}",
"reposting": "Republié {{pubkey}}",
"seeParent": "Voir la note",

View File

@ -114,7 +114,15 @@
"update": "Update",
"disable": "Disable"
},
"noteActions": {
"copy": "Скопировать",
"share": "Поделиться",
"view": "View"
},
"noteCard": {
"notifications": {
"zapServerError": "There was an error on the server while trying to request for the invoice."
},
"answering": "Ответить {{pubkey}}",
"reposting": "Reposted {{pubkey}}",
"seeParent": "See note",
@ -374,4 +382,4 @@
"emptyButton": "Открыть чат"
}
}
}
}

View File

@ -113,7 +113,15 @@
"update": "Update",
"disable": "Disable"
},
"noteActions": {
"copy": "复制",
"share": "分享",
"view": "View"
},
"noteCard": {
"notifications": {
"zapServerError": "There was an error on the server while trying to request for the invoice."
},
"answering": "回复 {{pubkey}}",
"reposting": "已转发 {{pubkey}}",
"userBlocked": "用户已屏蔽",
@ -380,4 +388,4 @@
"emptyButton": "发送私信"
}
}
}
}

View File

@ -23,15 +23,23 @@ import { getUnixTime } from 'date-fns'
import ContactsPage from '../ContactsPage'
import GroupPage from '../GroupPage'
import GroupHeaderIcon from '../../Components/GroupHeaderIcon'
import NoteActions from '../../Components/NoteActions'
export const HomeNavigator: React.FC = () => {
const theme = useTheme()
const { t } = useTranslation('common')
const { displayRelayDrawer, setDisplayrelayDrawer } = React.useContext(RelayPoolContext)
const { displayUserDrawer, setDisplayUserDrawer, setRefreshBottomBarAt, database } =
React.useContext(AppContext)
const {
displayUserDrawer,
setDisplayNoteDrawer,
displayNoteDrawer,
setDisplayUserDrawer,
setRefreshBottomBarAt,
database,
} = React.useContext(AppContext)
const bottomSheetRef = React.useRef<RBSheet>(null)
const bottomSheetProfileRef = React.useRef<RBSheet>(null)
const bottomSheetNoteRef = React.useRef<RBSheet>(null)
const bottomSheetRelayRef = React.useRef<RBSheet>(null)
const Stack = React.useMemo(() => createStackNavigator(), [])
const cardStyleInterpolator = React.useMemo(
@ -74,6 +82,10 @@ export const HomeNavigator: React.FC = () => {
if (displayRelayDrawer) bottomSheetRelayRef.current?.open()
}, [displayRelayDrawer])
React.useEffect(() => {
if (displayNoteDrawer) bottomSheetNoteRef.current?.open()
}, [displayNoteDrawer])
React.useEffect(() => {
if (displayUserDrawer) bottomSheetProfileRef.current?.open()
}, [displayUserDrawer])
@ -172,6 +184,14 @@ export const HomeNavigator: React.FC = () => {
>
<ProfileCard bottomSheetRef={bottomSheetProfileRef} />
</RBSheet>
<RBSheet
ref={bottomSheetNoteRef}
closeOnDragDown={true}
customStyles={bottomSheetStyles}
onClose={() => setDisplayNoteDrawer(undefined)}
>
<NoteActions bottomSheetRef={bottomSheetNoteRef} />
</RBSheet>
<RBSheet
ref={bottomSheetRelayRef}
closeOnDragDown={true}

View File

@ -35,12 +35,12 @@ export function getNprofile(key: string, relays: string[]): string {
return key
}
export function getNevent(key: string | undefined): string {
export function getNevent(key: string | undefined, relays: string[]): string {
if (!key) return ''
if (isPublicKey(key)) return key
try {
return neventEncode({ id: key, relays: [] })
return neventEncode({ id: key, relays })
} catch {
console.log('Error encoding')
}