mirror of
https://github.com/KoalaSat/nostros.git
synced 2024-09-29 06:30:47 +00:00
Hashtags (#431)
This commit is contained in:
commit
d207e307a2
@ -1,6 +1,6 @@
|
||||
import { t } from 'i18next'
|
||||
import * as React from 'react'
|
||||
import { StyleSheet, View, type ListRenderItem, Switch, FlatList } from 'react-native'
|
||||
import { StyleSheet, View, type ListRenderItem, FlatList } from 'react-native'
|
||||
import { Button, IconButton, List, Snackbar, Text, useTheme } from 'react-native-paper'
|
||||
import { AppContext } from '../../Contexts/AppContext'
|
||||
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
||||
@ -11,15 +11,15 @@ import LnPayment from '../LnPayment'
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
|
||||
import { navigate } from '../../lib/Navigation'
|
||||
import RBSheet from 'react-native-raw-bottom-sheet'
|
||||
import { getUserRelays, type NoteRelay } from '../../Functions/DatabaseFunctions/NotesRelays'
|
||||
import { relayToColor } from '../../Functions/NativeFunctions'
|
||||
import { type 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'
|
||||
import DatabaseModule from '../../lib/Native/DatabaseModule'
|
||||
import { addMutedUsersList, removeMutedUsersList } from '../../Functions/RelayFunctions/Lists'
|
||||
import { getRelayMetadata } from '../../Functions/DatabaseFunctions/RelayMetadatas'
|
||||
import { getUserRelays } from '../../Functions/DatabaseFunctions/NotesRelays'
|
||||
|
||||
interface ProfileActionsProps {
|
||||
user: User
|
||||
@ -35,7 +35,8 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({
|
||||
const theme = useTheme()
|
||||
const { database } = React.useContext(AppContext)
|
||||
const { publicKey, privateKey, mutedUsers, reloadLists } = React.useContext(UserContext)
|
||||
const { relayPool, updateRelayItem, lastEventId, sendEvent } = React.useContext(RelayPoolContext)
|
||||
const { relayPool, addRelayItem, lastEventId, sendEvent, relays } =
|
||||
React.useContext(RelayPoolContext)
|
||||
const [isContact, setIsContact] = React.useState<boolean>()
|
||||
const [isMuted, setIsMuted] = React.useState<boolean>()
|
||||
const [isGroupHidden, setIsGroupHidden] = React.useState<boolean>()
|
||||
@ -44,13 +45,13 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({
|
||||
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 [userRelays, setUserRelays] = React.useState<string[]>()
|
||||
const [openLn, setOpenLn] = React.useState<boolean>(false)
|
||||
|
||||
React.useEffect(() => {
|
||||
loadUser()
|
||||
loadRelays()
|
||||
if (publicKey) {
|
||||
if (publicKey && user.id) {
|
||||
relayPool?.subscribe('lists-muted-users', [
|
||||
{
|
||||
kinds: [10000],
|
||||
@ -58,12 +59,20 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({
|
||||
limit: 1,
|
||||
},
|
||||
])
|
||||
relayPool?.subscribe(`card-user-${user.id.substring(0, 6)}`, [
|
||||
{
|
||||
kinds: [10002],
|
||||
authors: [user.id],
|
||||
limit: 1,
|
||||
},
|
||||
])
|
||||
}
|
||||
}, [])
|
||||
|
||||
React.useEffect(() => {
|
||||
reloadLists()
|
||||
loadUser()
|
||||
loadRelays()
|
||||
}, [lastEventId, isMuted])
|
||||
|
||||
const hideGroupsUser: () => void = () => {
|
||||
@ -87,9 +96,13 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({
|
||||
|
||||
const loadRelays: () => void = () => {
|
||||
if (database) {
|
||||
getUserRelays(database, user.id).then((results) => {
|
||||
if (results) {
|
||||
setUserRelays(results)
|
||||
getRelayMetadata(database, user.id).then((resultMeta) => {
|
||||
if (resultMeta) {
|
||||
setUserRelays(resultMeta.tags.map((relayMeta) => relayMeta[1]))
|
||||
} else {
|
||||
getUserRelays(database, user.id).then((resultRelays) => {
|
||||
setUserRelays(resultRelays.map((relay) => relay.url))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -149,21 +162,6 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({
|
||||
}
|
||||
}
|
||||
|
||||
const activeRelay: (relay: Relay) => void = (relay) => {
|
||||
relay.active = 1
|
||||
updateRelayItem(relay).then(() => {
|
||||
setShowNotificationRelay('active')
|
||||
})
|
||||
}
|
||||
|
||||
const desactiveRelay: (relay: Relay) => void = (relay) => {
|
||||
relay.active = 0
|
||||
relay.global_feed = 0
|
||||
updateRelayItem(relay).then(() => {
|
||||
setShowNotificationRelay('desactive')
|
||||
})
|
||||
}
|
||||
|
||||
const bottomSheetStyles = React.useMemo(() => {
|
||||
return {
|
||||
container: {
|
||||
@ -178,25 +176,34 @@ export const ProfileActions: React.FC<ProfileActionsProps> = ({
|
||||
}
|
||||
}, [])
|
||||
|
||||
const renderRelayItem: ListRenderItem<NoteRelay> = ({ index, item }) => {
|
||||
const onPressAddRelay: (url: string) => void = (url) => {
|
||||
addRelayItem({ url })
|
||||
}
|
||||
|
||||
const renderRelayItem: ListRenderItem<string> = ({ index, item }) => {
|
||||
const userRelayUrls = relays.map((relay) => relay.url)
|
||||
return (
|
||||
<List.Item
|
||||
key={index}
|
||||
title={item.url}
|
||||
title={item}
|
||||
left={() => (
|
||||
<MaterialCommunityIcons
|
||||
style={styles.relayColor}
|
||||
name='circle'
|
||||
color={relayToColor(item.url)}
|
||||
/>
|
||||
)}
|
||||
right={() => (
|
||||
<Switch
|
||||
style={styles.switch}
|
||||
value={item.active !== undefined && item.active > 0}
|
||||
onValueChange={() => (item.active ? desactiveRelay(item) : activeRelay(item))}
|
||||
color={relayToColor(item)}
|
||||
/>
|
||||
)}
|
||||
right={() => {
|
||||
if (userRelayUrls.includes(item)) {
|
||||
return <></>
|
||||
} else {
|
||||
return (
|
||||
<Button mode='text' onPress={() => onPressAddRelay(item)}>
|
||||
{t('profileCard.addRelay')}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -50,17 +50,19 @@ export const LinksPreview: React.FC<TextContentProps> = ({ urls, lnUrl }) => {
|
||||
|
||||
const getDefaultCover: () => number = () => {
|
||||
if (!firstLink || !urls[firstLink]) return require(DEFAULT_COVER)
|
||||
if (urls[firstLink] === 'magnet') return require(MAGNET_COVER)
|
||||
if (urls[firstLink] === 'blueBird') return require(BLUEBIRD_COVER)
|
||||
if (urls[firstLink] === 'audio') return require(MEDIA_COVER)
|
||||
if (urls[firstLink] === 'video') return require(MEDIA_COVER)
|
||||
if (urls[firstLink] === 'audio') return require(MEDIA_COVER)
|
||||
if (urls[firstLink] === 'blueBird') return require(BLUEBIRD_COVER)
|
||||
if (urls[firstLink] === 'tube') return require(MEDIA_COVER)
|
||||
if (urls[firstLink] === 'magnet') return require(MAGNET_COVER)
|
||||
return require(DEFAULT_COVER)
|
||||
}
|
||||
|
||||
const videoPreview = (
|
||||
<VideoPlayer
|
||||
source={{uri: firstLink}}
|
||||
source={{ uri: firstLink ?? '' }}
|
||||
style={styles.videPlayer}
|
||||
paused={true}
|
||||
disableBack
|
||||
disableVolume
|
||||
disableFullscreen
|
||||
@ -200,6 +202,6 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
videPlayer: {
|
||||
height: 195,
|
||||
borderRadius: 16
|
||||
}
|
||||
borderRadius: 16,
|
||||
},
|
||||
})
|
||||
|
@ -9,7 +9,12 @@ import getUnixTime from 'date-fns/getUnixTime'
|
||||
import { useTheme } from 'react-native-paper'
|
||||
import { getNip19Key, getNpub } from '../../lib/nostr/Nip19'
|
||||
import { navigate } from '../../lib/Navigation'
|
||||
import { validBlueBirdUrl, validImageUrl, validMediaUrl } from '../../Functions/NativeFunctions'
|
||||
import {
|
||||
validBlueBirdUrl,
|
||||
validImageUrl,
|
||||
validMediaUrl,
|
||||
validTubeUrl,
|
||||
} from '../../Functions/NativeFunctions'
|
||||
import { LinksPreview } from './LinksPreview'
|
||||
|
||||
interface TextContentProps {
|
||||
@ -56,6 +61,12 @@ export const TextContent: React.FC<TextContentProps> = ({
|
||||
}
|
||||
}
|
||||
|
||||
const handleHashtagPress: (hashtag: string) => void = (hashtag) => {
|
||||
if (hashtag) {
|
||||
navigate('Search', { search: hashtag })
|
||||
}
|
||||
}
|
||||
|
||||
const handleNip05ProfilePress: (nip19: string) => void = (nip19) => {
|
||||
const pubKey = getNip19Key(nip19)
|
||||
|
||||
@ -126,6 +137,8 @@ export const TextContent: React.FC<TextContentProps> = ({
|
||||
return 'image'
|
||||
} else if (validBlueBirdUrl(url)) {
|
||||
return 'blueBird'
|
||||
} else if (validTubeUrl(url)) {
|
||||
return 'tube'
|
||||
} else if (MAGNET_LINK.test(url)) {
|
||||
return 'magnet'
|
||||
}
|
||||
@ -174,7 +187,7 @@ export const TextContent: React.FC<TextContentProps> = ({
|
||||
pattern: /#\[(\d+)\]/,
|
||||
style: styles.mention,
|
||||
},
|
||||
{ pattern: /#(\w+)/, style: styles.hashTag },
|
||||
{ pattern: /#(\w+)/, style: styles.hashTag, onPress: handleHashtagPress },
|
||||
{ pattern: /(lnbc)\S+/, style: styles.nip19, renderText: renderLnurl },
|
||||
{ pattern: /(nevent1)\S+/, style: styles.nip19, onPress: handleNip05NotePress },
|
||||
{
|
||||
|
@ -48,7 +48,7 @@ export const pickRandomItems = <T extends unknown>(arr: T[], n: number): T[] =>
|
||||
|
||||
export const validImageUrl: (url: string | undefined) => boolean = (url) => {
|
||||
if (url) {
|
||||
const regexp = /^(https?:\/\/.*\.?(png|jpg|jpeg|gif|webp)(\?.*)?)$/
|
||||
const regexp = /^(https?:\/\/.*\.?(png|jpg|jpeg|gif|webp){1}(\?.*)?)$/
|
||||
return regexp.test(url)
|
||||
} else {
|
||||
return false
|
||||
@ -57,9 +57,15 @@ export const validImageUrl: (url: string | undefined) => boolean = (url) => {
|
||||
|
||||
export const validMediaUrl: (url: string | undefined) => boolean = (url) => {
|
||||
if (url) {
|
||||
const fileRegexp = /^(https?:\/\/.*\.?(mp4|mp3))$/
|
||||
const serviceRegexp = /^(https?:\/\/?(youtube|youtu.be).*)$/
|
||||
return fileRegexp.test(url) || serviceRegexp.test(url)
|
||||
return /^(https?:\/\/.*\.(mp4|mp3){1})$/.test(url)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export const validTubeUrl: (url: string | undefined) => boolean = (url) => {
|
||||
if (url) {
|
||||
return /^(https?:\/\/.*\.?(youtube|youtu.be){1}.*)$/.test(url)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
@ -67,7 +73,7 @@ export const validMediaUrl: (url: string | undefined) => boolean = (url) => {
|
||||
|
||||
export const validBlueBirdUrl: (url: string | undefined) => boolean = (url) => {
|
||||
if (url) {
|
||||
const serviceRegexp = /^(https?:\/\/?(twitter.com|t.co).*)$/
|
||||
const serviceRegexp = /^(https?:\/\/.*\.?(twitter.com|t.co){1}.*)$/
|
||||
return serviceRegexp.test(url)
|
||||
} else {
|
||||
return false
|
||||
@ -76,7 +82,7 @@ export const validBlueBirdUrl: (url: string | undefined) => boolean = (url) => {
|
||||
|
||||
export const validNip21: (string: string | undefined) => boolean = (string) => {
|
||||
if (string) {
|
||||
const regexp = /^(nostr:)?(npub1|nprofile1|nevent1|nrelay1|note1)\S*$/
|
||||
const regexp = /^(nostr:)?(npub1|nprofile1|nevent1|nrelay1|note1){1}\S*$/
|
||||
return regexp.test(string)
|
||||
} else {
|
||||
return false
|
||||
|
@ -15,7 +15,7 @@
|
||||
"searchPage": {
|
||||
"placeholder": "Look for public keys, notes...",
|
||||
"emptyTitle": "Tip",
|
||||
"emptyDescription": "Start typing @ to find someone"
|
||||
"emptyDescription": "Start typing @ to find someone\n\nStart typing # to search topics"
|
||||
},
|
||||
"qrReaderPage": {
|
||||
"emptyTitle": "Berechtigung nicht gewährt",
|
||||
@ -443,6 +443,7 @@
|
||||
"userUnblocked": "Profil entblockt",
|
||||
"userBlocked": "Profile geblockt"
|
||||
},
|
||||
"addRelay": "Connect relay",
|
||||
"invoice": "Tip",
|
||||
"message": "Nachricht",
|
||||
"follow": "Folgen",
|
||||
|
@ -35,9 +35,9 @@
|
||||
"markAllRead": "Mark all as read"
|
||||
},
|
||||
"searchPage": {
|
||||
"placeholder": "Look for public keys, notes...",
|
||||
"placeholder": "Look for public keys, notes, hashtags...",
|
||||
"emptyTitle": "Tip",
|
||||
"emptyDescription": "Start typing @ to find someone"
|
||||
"emptyDescription": "Start typing @ to find someone\n\nStart typing # to search topics"
|
||||
},
|
||||
"conversationPage": {
|
||||
"unableDecypt": "{{username}} is talking with others about you",
|
||||
@ -450,6 +450,7 @@
|
||||
"userUnblocked": "Profile unblocked",
|
||||
"userBlocked": "Profile unblocked"
|
||||
},
|
||||
"addRelay": "Connect relay",
|
||||
"invoice": "Tip",
|
||||
"message": "Message",
|
||||
"follow": "Follow",
|
||||
|
@ -15,7 +15,7 @@
|
||||
"searchPage": {
|
||||
"placeholder": "Busca for claves públicas, notas, ...",
|
||||
"emptyTitle": "Consejo",
|
||||
"emptyDescription": "Empieza escribiendo con @ para encontrar a alguien"
|
||||
"emptyDescription": "Empieza escribiendo con @ para encontrar a alguien.\n\nEmpieza escribiendo # para buscar temas."
|
||||
},
|
||||
"qrReaderPage": {
|
||||
"emptyTitle": "Permisos no concedidos",
|
||||
@ -430,6 +430,7 @@
|
||||
"userUnblocked": "Perfil desbloqueado",
|
||||
"userBlocked": "Perfil bloqueado"
|
||||
},
|
||||
"addRelay": "Connectar a relay",
|
||||
"invoice": "Propina",
|
||||
"message": "Mensaje",
|
||||
"follow": "Seguir",
|
||||
|
@ -13,9 +13,9 @@
|
||||
"privateKeysSnackbarDescription": "Conservez votre clé privée dans un endroit sûr. Si vous la perdez, vous ne pourrez plus avoir accès ni récupérer votre compte."
|
||||
},
|
||||
"searchPage": {
|
||||
"placeholder": "Look for public keys, notes...",
|
||||
"placeholder": "Look for public keys, notes, hashtags...",
|
||||
"emptyTitle": "Tip",
|
||||
"emptyDescription": "Start typing @ to find someone"
|
||||
"emptyDescription": "Start typing @ to find someone\n\nStart typing # to search topics"
|
||||
},
|
||||
"qrReaderPage": {
|
||||
"emptyTitle": "Permissions not granted",
|
||||
@ -414,6 +414,7 @@
|
||||
"userUnblocked": "Profile unblocked",
|
||||
"userBlocked": "Profile unblocked"
|
||||
},
|
||||
"addRelay": "Connect relay",
|
||||
"invoice": "Tip",
|
||||
"message": "Message",
|
||||
"follow": "Abonné",
|
||||
|
@ -13,9 +13,9 @@
|
||||
"privateKeysSnackbarDescription": "Keep your private key in a safe place, if you lose it you will not be able to access it again or recover your account."
|
||||
},
|
||||
"searchPage": {
|
||||
"placeholder": "Look for public keys, notes...",
|
||||
"placeholder": "Look for public keys, notes, hashtags...",
|
||||
"emptyTitle": "Tip",
|
||||
"emptyDescription": "Start typing @ to find someone"
|
||||
"emptyDescription": "Start typing @ to find someone\n\nStart typing # to search topics"
|
||||
},
|
||||
"qrReaderPage": {
|
||||
"emptyTitle": "Permissions not granted",
|
||||
@ -422,6 +422,7 @@
|
||||
"userUnblocked": "Profile unblocked",
|
||||
"userBlocked": "Profile unblocked"
|
||||
},
|
||||
"addRelay": "Connect relay",
|
||||
"invoice": "Tip",
|
||||
"message": "Message",
|
||||
"follow": "Follow",
|
||||
|
@ -13,9 +13,9 @@
|
||||
"privateKeysSnackbarDescription": "请妥善保管您的私钥。如果遗失,您将无法访问或恢复您的账号。"
|
||||
},
|
||||
"searchPage": {
|
||||
"placeholder": "Look for public keys, notes...",
|
||||
"placeholder": "Look for public keys, notes, hashtags...",
|
||||
"emptyTitle": "Tip",
|
||||
"emptyDescription": "Start typing @ to find someone"
|
||||
"emptyDescription": "Start typing @ to find someone\n\nStart typing # to search topics"
|
||||
},
|
||||
"qrReaderPage": {
|
||||
"emptyTitle": "未授予权限",
|
||||
@ -423,6 +423,7 @@
|
||||
"userUnblocked": "已屏蔽",
|
||||
"userBlocked": "已取消屏蔽"
|
||||
},
|
||||
"addRelay": "Connect relay",
|
||||
"invoice": "赞赏",
|
||||
"message": "私信",
|
||||
"follow": "关注",
|
||||
|
@ -74,7 +74,9 @@ export const FirstStep: React.FC<FirstStepProps> = ({ nextStep }) => {
|
||||
relays.forEach((relay) => {
|
||||
removeRelayItem(relay)
|
||||
})
|
||||
metadata.tags.forEach(async (tag) => await addRelayItem({ url: tag[1] }))
|
||||
metadata.tags.forEach(async (tag) => {
|
||||
if (tag[0] === 'r') await addRelayItem({ url: tag[1] })
|
||||
})
|
||||
nextStep()
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { useFocusEffect } from '@react-navigation/native'
|
||||
import { FlashList, ListRenderItem } from '@shopify/flash-list'
|
||||
import { t } from 'i18next'
|
||||
import debounce from 'lodash.debounce'
|
||||
import { Kind } from 'nostr-tools'
|
||||
import { decode } from 'nostr-tools/nip19'
|
||||
import * as React from 'react'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
@ -9,6 +11,7 @@ import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityI
|
||||
import NoteCard from '../../Components/NoteCard'
|
||||
import ProfileData from '../../Components/ProfileData'
|
||||
import { AppContext } from '../../Contexts/AppContext'
|
||||
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
||||
import { getNotes, Note } from '../../Functions/DatabaseFunctions/Notes'
|
||||
import { getUsers, User } from '../../Functions/DatabaseFunctions/Users'
|
||||
import { validNip21 } from '../../Functions/NativeFunctions'
|
||||
@ -16,17 +19,19 @@ import { navigate } from '../../lib/Navigation'
|
||||
import { getNpub } from '../../lib/nostr/Nip19'
|
||||
|
||||
interface SearchPageProps {
|
||||
route: { params: { urls: string[]; index?: number } }
|
||||
route: { params: { search: string } }
|
||||
}
|
||||
|
||||
export const SearchPage: React.FC<SearchPageProps> = ({ route }) => {
|
||||
const pageSize = 30
|
||||
const theme = useTheme()
|
||||
const { database } = React.useContext(AppContext)
|
||||
const { relayPool, lastEventId } = React.useContext(RelayPoolContext)
|
||||
const [users, setUsers] = React.useState<User[]>([])
|
||||
const [resultsUsers, setResultsUsers] = React.useState<User[]>([])
|
||||
const [notes, setNotes] = React.useState<Note[]>([])
|
||||
const [resultsNotes, setResultsNotes] = React.useState<Note[]>([])
|
||||
const [searchInput, setSearchInput] = React.useState<string>('')
|
||||
const [searchInput, setSearchInput] = React.useState<string>(route?.params?.search ?? '')
|
||||
const inputRef = React.useRef<TextInput>(null)
|
||||
|
||||
useFocusEffect(
|
||||
@ -46,10 +51,42 @@ export const SearchPage: React.FC<SearchPageProps> = ({ route }) => {
|
||||
)
|
||||
|
||||
React.useEffect(() => {
|
||||
if (searchInput !== '') {
|
||||
if (/^#.*/.test(searchInput)) {
|
||||
const search = searchInput.toLocaleLowerCase()
|
||||
if (/^@.*/.test(search)) {
|
||||
const searchUser = search.replace(/^@/, '')
|
||||
setResultsNotes(
|
||||
notes.filter((note) => note.content.toLocaleLowerCase().includes(search.trim())),
|
||||
)
|
||||
}
|
||||
}, [lastEventId])
|
||||
|
||||
const subscribeHandler = React.useMemo(
|
||||
() =>
|
||||
debounce((hastags) => {
|
||||
relayPool?.subscribe('search-hastags', [
|
||||
{
|
||||
kinds: [Kind.Text],
|
||||
'#t': hastags,
|
||||
limit: pageSize,
|
||||
},
|
||||
])
|
||||
}, 600),
|
||||
[pageSize],
|
||||
)
|
||||
|
||||
React.useEffect(() => {
|
||||
if (/^#.*/.test(searchInput)) {
|
||||
const hastags = [...searchInput.matchAll(/#([^#]\S+)/gi)].map((match) => {
|
||||
return match[1]
|
||||
})
|
||||
if (hastags.length > 0) {
|
||||
subscribeHandler(hastags)
|
||||
}
|
||||
}
|
||||
}, [searchInput])
|
||||
|
||||
React.useEffect(() => {
|
||||
if (/^@.*/.test(searchInput)) {
|
||||
const searchUser = searchInput.replace(/^@/, '')
|
||||
setResultsUsers(
|
||||
users.filter(
|
||||
(user) =>
|
||||
@ -58,9 +95,17 @@ export const SearchPage: React.FC<SearchPageProps> = ({ route }) => {
|
||||
),
|
||||
)
|
||||
} else {
|
||||
if (validNip21(search)) {
|
||||
const search = searchInput.toLocaleLowerCase()
|
||||
setResultsNotes(
|
||||
notes.filter((note) => note.content.toLocaleLowerCase().includes(search.trim())),
|
||||
)
|
||||
}
|
||||
}, [searchInput, notes])
|
||||
|
||||
React.useEffect(() => {
|
||||
if (searchInput !== '' && validNip21(searchInput)) {
|
||||
try {
|
||||
const key = decode(search.replace('nostr:', ''))
|
||||
const key = decode(searchInput.replace('nostr:', ''))
|
||||
if (key?.data) {
|
||||
if (key.type === 'nevent') {
|
||||
setSearchInput('')
|
||||
@ -75,9 +120,6 @@ export const SearchPage: React.FC<SearchPageProps> = ({ route }) => {
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
setResultsNotes(notes.filter((note) => note.content.toLocaleLowerCase().includes(search)))
|
||||
}
|
||||
}
|
||||
}, [searchInput])
|
||||
|
||||
const renderItemNote: ListRenderItem<Note> = ({ item, index }) => {
|
||||
@ -173,7 +215,8 @@ const styles = StyleSheet.create({
|
||||
paddingTop: 16,
|
||||
},
|
||||
container: {
|
||||
padding: 16,
|
||||
paddingLeft: 16,
|
||||
paddingRight: 16,
|
||||
flex: 1,
|
||||
},
|
||||
inputContainer: {
|
||||
|
@ -97,6 +97,10 @@ export const SendPage: React.FC<SendPageProps> = ({ route }) => {
|
||||
})
|
||||
}
|
||||
|
||||
;[...rawContent.matchAll(/#([^#]\S+)/gi)].forEach((match) => {
|
||||
if (match[1]) tags.push(['t', match[1]])
|
||||
})
|
||||
|
||||
const event: Event = {
|
||||
content: rawContent,
|
||||
created_at: getUnixTime(new Date()),
|
||||
@ -104,6 +108,7 @@ export const SendPage: React.FC<SendPageProps> = ({ route }) => {
|
||||
pubkey: publicKey,
|
||||
tags,
|
||||
}
|
||||
|
||||
sendEvent(event).catch(() => {})
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ export interface RelayFilters {
|
||||
kinds?: number[]
|
||||
'#e'?: string[]
|
||||
'#p'?: string[]
|
||||
'#t'?: string[]
|
||||
since?: number
|
||||
limit?: number
|
||||
until?: number
|
||||
|
Loading…
Reference in New Issue
Block a user