Image preview and JS files restructred (#76)

This commit is contained in:
KoalaSat 2022-12-30 18:13:14 +00:00 committed by GitHub
commit df877f7882
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 105 additions and 71 deletions

View File

@ -18,7 +18,7 @@ import { populateRelay } from '../../Functions/RelayFunctions'
import Avatar from '../Avatar'
import { searchRelays } from '../../Functions/DatabaseFunctions/Relays'
import { RelayFilters } from '../../lib/nostr/RelayPool/intex'
import TextBox from '../TextBox'
import TextContent from '../../Components/TextContent'
import { formatPubKey } from '../../Functions/RelayFunctions/Users'
interface NoteCardProps {
@ -94,7 +94,7 @@ export const NoteCard: React.FC<NoteCardProps> = ({
{t('note.contentWarning')}
</Button>
) : (
<TextBox note={note} />
<TextContent event={note} />
)}
</Layout>
<Layout style={styles.footer}>

View File

@ -7,19 +7,28 @@ import { AppContext } from '../../Contexts/AppContext'
import { getUser } from '../../Functions/DatabaseFunctions/Users'
import { formatPubKey } from '../../Functions/RelayFunctions/Users'
import moment from 'moment'
import { LinkPreview, REGEX_LINK } from '@flyerhq/react-native-link-preview'
interface TextBoxProps {
note: Event
interface TextContentProps {
event?: Event
content?: string
preview?: boolean
}
export const TextBox: React.FC<TextBoxProps> = ({ note }) => {
export const TextContent: React.FC<TextContentProps> = ({ event, content, preview = true }) => {
const theme = useTheme()
const { database, goToPage } = useContext(AppContext)
const [userNames, setUserNames] = useState<Record<number, string>>({})
const [loadedUsers, setLoadedUsers] = useState<number>(0)
const text = event?.content ?? content ?? ''
useEffect(() => {}, [loadedUsers])
const containsUrl: () => boolean = () => {
const matches = text.match(REGEX_LINK) ?? []
return matches.length > 0
}
const handleUrlPress: (url: string) => void = (url) => {
Linking.openURL(url)
}
@ -29,8 +38,10 @@ export const TextBox: React.FC<TextBoxProps> = ({ note }) => {
}
const handleMentionPress: (text: string) => void = (text) => {
if (!event) return
const mentionIndex: number = parseInt(text.substring(2, text.length - 1))
goToPage(`profile#${note.tags[mentionIndex][1]}`)
goToPage(`profile#${event.tags[mentionIndex][1]}`)
}
const renderMentionText: (matchingString: string, matches: string[]) => string = (
@ -41,8 +52,8 @@ export const TextBox: React.FC<TextBoxProps> = ({ note }) => {
if (userNames[mentionIndex]) {
return userNames[mentionIndex]
} else {
const pudKey = note.tags[mentionIndex][1]
} else if (event) {
const pudKey = event.tags[mentionIndex][1]
if (database) {
getUser(pudKey, database).then((user) => {
setLoadedUsers(moment().unix())
@ -53,6 +64,8 @@ export const TextBox: React.FC<TextBoxProps> = ({ note }) => {
})
}
return `@${formatPubKey(pudKey)}`
} else {
return matchingString
}
}
@ -76,26 +89,33 @@ export const TextBox: React.FC<TextBoxProps> = ({ note }) => {
})
return (
note && (
<>
<ParsedText
style={styles.text}
parse={[
{ type: 'url', style: styles.url, onPress: handleUrlPress },
{ type: 'email', style: styles.email, onPress: handleEmailPress },
{
pattern: /#\[(\d+)\]/,
style: styles.mention,
onPress: handleMentionPress,
renderText: renderMentionText,
},
event
? {
pattern: /#\[(\d+)\]/,
style: styles.mention,
onPress: handleMentionPress,
renderText: renderMentionText,
}
: {
pattern: /#\[(\d+)\]/,
},
{ pattern: /#(\w+)/, style: styles.hashTag },
]}
childrenProps={{ allowFontScaling: false }}
>
{note.content}
{text}
</ParsedText>
)
{preview && containsUrl() && (
<LinkPreview text={text} renderText={() => ''} textContainerStyle={{ height: 0 }} />
)}
</>
)
}
export default TextBox
export default TextContent

View File

@ -16,7 +16,7 @@ import Icon from 'react-native-vector-icons/FontAwesome5'
import { EventKind } from '../../lib/nostr/Events'
import { useTranslation } from 'react-i18next'
import { getUsers, updateUserContact, User } from '../../Functions/DatabaseFunctions/Users'
import UserCard from '../UserCard'
import UserCard from '../../Components/UserCard'
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
import { populatePets } from '../../Functions/RelayFunctions/Users'

View File

@ -10,13 +10,13 @@ import {
updateConversationRead,
} from '../../Functions/DatabaseFunctions/DirectMessages'
import { getUser, User } from '../../Functions/DatabaseFunctions/Users'
import Avatar from '../Avatar'
import Avatar from '../../Components/Avatar'
import { decrypt } from 'nostr-tools/nip04'
import Icon from 'react-native-vector-icons/FontAwesome5'
import { username, usersToTags } from '../../Functions/RelayFunctions/Users'
import moment from 'moment'
import { encrypt } from '../../lib/nostr/Crypto'
import TextBox from '../TextBox'
import TextContent from '../../Components/TextContent'
export const ConversationPage: React.FC = () => {
const theme = useTheme()
@ -123,7 +123,7 @@ export const ConversationPage: React.FC = () => {
{moment.unix(message.created_at).format('HH:mm DD-MM-YY')}
</Text>
</Layout>
<TextBox note={message} />
<TextContent event={message} />
</Layout>
</Layout>
</Layout>
@ -143,7 +143,7 @@ export const ConversationPage: React.FC = () => {
)}
</Layout>
</Layout>
<TextBox note={message} />
<TextContent event={message} />
</Layout>
</Layout>
)

View File

@ -23,7 +23,7 @@ import {
generateConversationId,
getOtherPubKey,
} from '../../Functions/RelayFunctions/DirectMessages'
import Avatar from '../Avatar'
import Avatar from '../../Components/Avatar'
import Icon from 'react-native-vector-icons/FontAwesome5'
import { useTranslation } from 'react-i18next'
import { username } from '../../Functions/RelayFunctions/Users'

View File

@ -1,4 +1,4 @@
import { Button, Card, Layout, Text, useTheme } from '@ui-kitten/components'
import { Button, Card, Layout, Spinner, Text, useTheme } from '@ui-kitten/components'
import React, { useCallback, useContext, useEffect, useState } from 'react'
import { t } from 'i18next'
import {
@ -11,7 +11,7 @@ import {
} from 'react-native'
import { AppContext } from '../../Contexts/AppContext'
import { getMainNotes, Note } from '../../Functions/DatabaseFunctions/Notes'
import NoteCard from '../NoteCard'
import NoteCard from '../../Components/NoteCard'
import Icon from 'react-native-vector-icons/FontAwesome5'
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
import { EventKind } from '../../lib/nostr/Events'
@ -141,6 +141,11 @@ export const HomePage: React.FC = () => {
justifyContent: 'center',
alignItems: 'center',
},
spinner: {
justifyContent: 'center',
alignItems: 'center',
height: 64,
},
})
return (
@ -153,6 +158,9 @@ export const HomePage: React.FC = () => {
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />}
>
{notes.map((note) => itemCard(note))}
<Layout style={styles.spinner}>
<Spinner size='small' />
</Layout>
</ScrollView>
) : (
<Layout style={styles.empty} level='3'>
@ -160,7 +168,7 @@ export const HomePage: React.FC = () => {
<Text>{t('homePage.noContacts')}</Text>
</Layout>
<Button
onPress={() => goToPage('config')}
onPress={() => goToPage('contacts')}
status='warning'
accessoryLeft={
<Icon name='address-book' size={16} color={theme['text-basic-color']} solid />

View File

@ -34,10 +34,10 @@ export const Loader: React.FC = () => {
if (database) {
getUsers(database, { contacts: true }).then((results) => {
setContactsCount(results.length)
if (results && results.length > 0) {
if (publicKey && results && results.length > 0) {
relayPool?.subscribe('main-channel', {
kinds: [EventKind.meta],
authors: results.map((user: User) => user.id),
kinds: [EventKind.meta, EventKind.textNote, EventKind.recommendServer],
authors: [...results.map((user: User) => user.id), publicKey],
})
}
})

View File

@ -1,7 +1,7 @@
import React, { useContext } from 'react'
import { Layout, Text, useTheme } from '@ui-kitten/components'
import { Linking, StyleSheet, TouchableOpacity } from 'react-native'
import Loading from '../Loading'
import Loading from '../../Components/Loading'
import Logger from './Logger'
import Loader from './Loader'
import Icon from 'react-native-vector-icons/FontAwesome5'

View File

@ -4,7 +4,7 @@ import { StyleSheet } from 'react-native'
import { AppContext } from '../../Contexts/AppContext'
import HomePage from '../HomePage'
import ProfilePage from '../ProfilePage'
import NavigationBar from '../NavigationBar'
import NavigationBar from '../../Components/NavigationBar'
import SendPage from '../SendPage'
import ContactsPage from '../ContactsPage'
import NotePage from '../NotePage'
@ -13,7 +13,7 @@ import ConfigPage from '../ConfigPage'
import RelaysPage from '../RelaysPage'
import DirectMessagesPage from '../DirectMessagesPage'
import ConversationPage from '../ConversationPage'
import Loading from '../Loading'
import Loading from '../../Components/Loading'
import MentionsPage from '../MentionsPage'
export const MainLayout: React.FC = () => {

View File

@ -1,10 +1,10 @@
import { Card, Layout, Text } from '@ui-kitten/components'
import { Card, Layout, Spinner, Text } from '@ui-kitten/components'
import React, { useContext, useEffect, useState } from 'react'
import { t } from 'i18next'
import { NativeScrollEvent, NativeSyntheticEvent, ScrollView, StyleSheet } from 'react-native'
import { AppContext } from '../../Contexts/AppContext'
import { getMentionNotes, Note } from '../../Functions/DatabaseFunctions/Notes'
import NoteCard from '../NoteCard'
import NoteCard from '../../Components/NoteCard'
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
import { EventKind } from '../../lib/nostr/Events'
import { getReplyEventId } from '../../Functions/RelayFunctions/Events'
@ -112,6 +112,11 @@ export const MentionsPage: React.FC = () => {
justifyContent: 'center',
alignItems: 'center',
},
spinner: {
justifyContent: 'center',
alignItems: 'center',
height: 64,
},
})
return (
@ -119,6 +124,9 @@ export const MentionsPage: React.FC = () => {
{notes && notes.length > 0 ? (
<ScrollView onScroll={onScroll} horizontal={false}>
{notes.map((note) => itemCard(note))}
<Layout style={styles.spinner}>
<Spinner size='small' />
</Layout>
</ScrollView>
) : (
<Layout style={styles.empty} level='3'>

View File

@ -4,10 +4,10 @@ import { AppContext } from '../../Contexts/AppContext'
import { getNotes, Note } from '../../Functions/DatabaseFunctions/Notes'
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
import Icon from 'react-native-vector-icons/FontAwesome5'
import NoteCard from '../NoteCard'
import NoteCard from '../../Components/NoteCard'
import { EventKind } from '../../lib/nostr/Events'
import { Clipboard, ScrollView, StyleSheet, Text, TouchableOpacity } from 'react-native'
import Loading from '../Loading'
import Loading from '../../Components/Loading'
import { getDirectReplies, getReplyEventId } from '../../Functions/RelayFunctions/Events'
import { RelayFilters } from '../../lib/nostr/RelayPool/intex'
@ -146,6 +146,9 @@ export const NotePage: React.FC = () => {
}
const styles = StyleSheet.create({
container: {
marginBottom: 32,
},
main: {
paddingBottom: 32,
paddingTop: 26,
@ -169,7 +172,7 @@ export const NotePage: React.FC = () => {
accessoryLeft={renderBackAction}
accessoryRight={renderNoteActions}
/>
<Layout level='4'>
<Layout level='4' style={styles.container}>
{note ? (
<ScrollView horizontal={false}>
{[note, ...(replies ?? [])].map((note) => itemCard(note))}

View File

@ -11,18 +11,19 @@ import {
} from 'react-native'
import { AppContext } from '../../Contexts/AppContext'
import { getNotes, Note } from '../../Functions/DatabaseFunctions/Notes'
import NoteCard from '../NoteCard'
import NoteCard from '../../Components/NoteCard'
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
import { getUser, User, updateUserContact } from '../../Functions/DatabaseFunctions/Users'
import { EventKind } from '../../lib/nostr/Events'
import Icon from 'react-native-vector-icons/FontAwesome5'
import { formatPubKey, populatePets } from '../../Functions/RelayFunctions/Users'
import { getReplyEventId } from '../../Functions/RelayFunctions/Events'
import Loading from '../Loading'
import Loading from '../../Components/Loading'
import { handleInfinityScroll } from '../../Functions/NativeFunctions'
import Avatar from '../Avatar'
import Avatar from '../../Components/Avatar'
import { RelayFilters } from '../../lib/nostr/RelayPool/intex'
import { t } from 'i18next'
import TextContent from '../../Components/TextContent'
export const ProfilePage: React.FC = () => {
const { database, page, goToPage, goBack } = useContext(AppContext)
@ -236,6 +237,11 @@ export const ProfilePage: React.FC = () => {
justifyContent: 'center',
alignItems: 'center',
},
spinner: {
justifyContent: 'center',
alignItems: 'center',
height: 64,
},
})
const itemCard: (note: Note) => JSX.Element = (note) => {
@ -285,9 +291,7 @@ export const ProfilePage: React.FC = () => {
{user && (
<>
<Layout style={styles.about} level='3'>
<Text numberOfLines={5} ellipsizeMode='tail'>
{user?.about}
</Text>
<TextContent content={user?.about} preview={false} />
</Layout>
</>
)}
@ -327,6 +331,9 @@ export const ProfilePage: React.FC = () => {
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />}
>
{notes.map((note) => itemCard(note))}
<Layout style={styles.spinner}>
<Spinner size='small' />
</Layout>
</ScrollView>
) : (
<Loading />

View File

@ -20,7 +20,7 @@ import { getNotes } from '../../Functions/DatabaseFunctions/Notes'
import { getETags } from '../../Functions/RelayFunctions/Events'
import { getUsers, User } from '../../Functions/DatabaseFunctions/Users'
import { formatPubKey } from '../../Functions/RelayFunctions/Users'
import Avatar from '../Avatar'
import Avatar from '../../Components/Avatar'
export const SendPage: React.FC = () => {
const theme = useTheme()

View File

@ -4,7 +4,7 @@ import theme from './theme.json'
import { EvaIconsPack } from '@ui-kitten/eva-icons'
import * as eva from '@eva-design/eva'
import { AppContextProvider } from './Contexts/AppContext'
import MainLayout from './Components/MainLayout'
import MainLayout from './Pages/MainLayout'
import { RelayPoolContextProvider } from './Contexts/RelayPoolContext'
import { I18nextProvider } from 'react-i18next'
import i18n from './i18n.config'

View File

@ -12,6 +12,7 @@
},
"dependencies": {
"@eva-design/eva": "^2.1.0",
"@flyerhq/react-native-link-preview": "^1.6.0",
"@ui-kitten/components": "5.1.2",
"@ui-kitten/eva-icons": "5.1.2",
"@ui-kitten/metro-config": "5.1.2",

View File

@ -900,6 +900,13 @@
resolved "https://registry.yarnpkg.com/@eva-design/processor/-/processor-2.1.1.tgz#33a59efa52ee2d206ac4d912dae801d12f9275a8"
integrity sha512-lbxZLm5ARhuk/wxWkaiWhw5XeZ+Xcp1JGCjcZl+S5rUbLppfp4U47jfq861EY27BP1dpQ5PyTVFCbl5eHlRFdg==
"@flyerhq/react-native-link-preview@^1.6.0":
version "1.6.0"
resolved "https://registry.yarnpkg.com/@flyerhq/react-native-link-preview/-/react-native-link-preview-1.6.0.tgz#c7285ab93a133328edc5d69b011822581bb4414b"
integrity sha512-MY2Kxlf3SzLVUAuGU2LXhDU0a2icNBWL7MDCA8BNpmKqsWI+tHjX3mHm5nGpsLweYG5wsajzBd5XS0KCXNPkJA==
dependencies:
html-entities "^2.3.2"
"@hapi/hoek@^9.0.0":
version "9.3.0"
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb"
@ -4371,6 +4378,11 @@ hoist-non-react-statics@^3.2.1:
dependencies:
react-is "^16.7.0"
html-entities@^2.3.2:
version "2.3.3"
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46"
integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==
html-escaper@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
@ -5512,13 +5524,6 @@ lines-and-columns@^1.1.6:
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
linkify-it@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-4.0.1.tgz#01f1d5e508190d06669982ba31a7d9f56a5751ec"
integrity sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==
dependencies:
uc.micro "^1.0.1"
locate-path@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
@ -5645,11 +5650,6 @@ mdn-data@2.0.14:
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==
mdurl@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
integrity sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==
memoize-one@^5.0.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
@ -6840,14 +6840,6 @@ react-native-gradle-plugin@^0.70.3:
resolved "https://registry.yarnpkg.com/react-native-gradle-plugin/-/react-native-gradle-plugin-0.70.3.tgz#cbcf0619cbfbddaa9128701aa2d7b4145f9c4fc8"
integrity sha512-oOanj84fJEXUg9FoEAQomA8ISG+DVIrTZ3qF7m69VQUJyOGYyDZmPqKcjvRku4KXlEH6hWO9i4ACLzNBh8gC0A==
react-native-hyperlink@^0.0.22:
version "0.0.22"
resolved "https://registry.yarnpkg.com/react-native-hyperlink/-/react-native-hyperlink-0.0.22.tgz#9f553390b5f96ae473d942639c40bce6579abc89"
integrity sha512-IVhG+aP2bAnllUEr08/+rGA3cbpzyl83PtOfe94higfWUR8E7rUGThj21tdhx8SWAyl+4XO1K864tA6ybVbMFA==
dependencies:
linkify-it "^4.0.1"
mdurl "^1.0.1"
react-native-iphone-x-helper@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz#20c603e9a0e765fd6f97396638bdeb0e5a60b010"
@ -7937,11 +7929,6 @@ typescript@^4.9.3:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.3.tgz#3aea307c1746b8c384435d8ac36b8a2e580d85db"
integrity sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==
uc.micro@^1.0.1:
version "1.0.6"
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==
uglify-es@^3.1.9:
version "3.3.9"
resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677"