mirror of
https://github.com/KoalaSat/nostros.git
synced 2024-09-28 22:30:41 +00:00
Mentions
This commit is contained in:
parent
f6093f1f22
commit
2ecb4261db
@ -38,7 +38,7 @@ public class Event {
|
||||
if (kind.equals("0")) {
|
||||
saveUserMeta(database);
|
||||
} else if (kind.equals("1") || kind.equals("2")) {
|
||||
saveNote(database);
|
||||
saveNote(database, userPubKey);
|
||||
} else if (kind.equals("3")) {
|
||||
if (pubkey.equals(userPubKey)) {
|
||||
savePets(database);
|
||||
@ -98,6 +98,23 @@ public class Event {
|
||||
return replyEventId;
|
||||
}
|
||||
|
||||
protected Boolean getUserMentioned(String userPubKey) {
|
||||
JSONArray eTags = filterTags("p");
|
||||
Boolean userMentioned = false;
|
||||
try {
|
||||
for (int i = 0; i < eTags.length(); ++i) {
|
||||
JSONArray tag = eTags.getJSONArray(i);
|
||||
if (tag.getString(1).equals(userPubKey)) {
|
||||
userMentioned = true;
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return userMentioned;
|
||||
}
|
||||
|
||||
protected String saveFollower(String pubKey) {
|
||||
JSONArray eTags = filterTags("p");
|
||||
String mainEventId = null;
|
||||
@ -136,7 +153,7 @@ public class Event {
|
||||
return filtered;
|
||||
}
|
||||
|
||||
protected void saveNote(SQLiteDatabase database) {
|
||||
protected void saveNote(SQLiteDatabase database, String userPubKey) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("id", id);
|
||||
values.put("content", content.replace("'", "''"));
|
||||
@ -147,6 +164,7 @@ public class Event {
|
||||
values.put("tags", tags.toString());
|
||||
values.put("main_event_id", getMainEventId());
|
||||
values.put("reply_event_id", getReplyEventId());
|
||||
values.put("user_mentioned", getUserMentioned(userPubKey));
|
||||
database.replace("nostros_notes", null, values);
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,8 @@ public class DatabaseModule {
|
||||
" conversation_id TEXT NOT NULL,\n" +
|
||||
" read BOOLEAN DEFAULT FALSE\n" +
|
||||
" );");
|
||||
database.execSQL("ALTER TABLE nostros_notes ADD COLUMN user_mentioned BOOLEAN DEFAULT FALSE;");
|
||||
database.execSQL("ALTER TABLE nostros_notes ADD COLUMN seen BOOLEAN DEFAULT FALSE;");
|
||||
}
|
||||
|
||||
public void saveEvent(JSONObject data, String userPubKey) throws JSONException {
|
||||
|
@ -16,8 +16,7 @@ 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 Markdown from 'react-native-markdown-display'
|
||||
import { markdownIt, markdownStyle } from '../../Constants/AppConstants'
|
||||
import TextBox from '../TextBox'
|
||||
|
||||
export const ConversationPage: React.FC = () => {
|
||||
const theme = useTheme()
|
||||
@ -124,9 +123,9 @@ export const ConversationPage: React.FC = () => {
|
||||
{moment.unix(message.created_at).format('HH:mm DD-MM-YY')}
|
||||
</Text>
|
||||
</Layout>
|
||||
<Markdown style={markdownStyle(theme)} markdownit={markdownIt}>
|
||||
{message.content}
|
||||
</Markdown>
|
||||
<TextBox note={message}>
|
||||
<Text>{message.content}</Text>
|
||||
</TextBox>
|
||||
</Layout>
|
||||
</Layout>
|
||||
</Layout>
|
||||
@ -146,9 +145,9 @@ export const ConversationPage: React.FC = () => {
|
||||
)}
|
||||
</Layout>
|
||||
</Layout>
|
||||
<Markdown style={markdownStyle(theme)} markdownit={markdownIt}>
|
||||
{message.content}
|
||||
</Markdown>
|
||||
<TextBox note={message}>
|
||||
<Text>{message.content}</Text>
|
||||
</TextBox>
|
||||
</Layout>
|
||||
</Layout>
|
||||
)
|
||||
|
@ -142,7 +142,10 @@ export const Logger: React.FC = () => {
|
||||
<Layout style={styles.buttonssContainer}>
|
||||
<Layout style={styles.buttonLeft}>
|
||||
<Button
|
||||
onPress={() => setIsPrivate(!isPrivate)}
|
||||
onPress={() => {
|
||||
setIsPrivate(!isPrivate)
|
||||
setInputValue('')
|
||||
}}
|
||||
disabled={loading}
|
||||
accessoryLeft={keyButton}
|
||||
status={isPrivate ? 'warning' : 'default'}
|
||||
|
@ -2,7 +2,6 @@ import React, { useContext, useEffect, useState } from 'react'
|
||||
import { Button, Divider, Layout, Text, useTheme } from '@ui-kitten/components'
|
||||
import { getNotes, Note } from '../../Functions/DatabaseFunctions/Notes'
|
||||
import { StyleSheet, TouchableOpacity } from 'react-native'
|
||||
import Markdown from 'react-native-markdown-display'
|
||||
import { EventKind } from '../../lib/nostr/Events'
|
||||
import Icon from 'react-native-vector-icons/FontAwesome5'
|
||||
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
||||
@ -13,9 +12,10 @@ import { getDirectReplies, getReplyEventId } from '../../Functions/RelayFunction
|
||||
import moment from 'moment'
|
||||
import { populateRelay } from '../../Functions/RelayFunctions'
|
||||
import Avatar from '../Avatar'
|
||||
import { markdownIt, markdownStyle } from '../../Constants/AppConstants'
|
||||
import { searchRelays } from '../../Functions/DatabaseFunctions/Relays'
|
||||
import { RelayFilters } from '../../lib/nostr/RelayPool/intex'
|
||||
import TextBox from '../TextBox'
|
||||
import { formatPubKey } from '../../Functions/RelayFunctions/Users'
|
||||
|
||||
interface NoteCardProps {
|
||||
note: Note
|
||||
@ -75,7 +75,7 @@ export const NoteCard: React.FC<NoteCardProps> = ({
|
||||
<TouchableOpacity onPress={onPressUser}>
|
||||
<Layout style={styles.pubkey}>
|
||||
<Text appearance='hint'>
|
||||
{note.name ?? `${note.pubkey.slice(0, 6)}...${note.pubkey.slice(-6)}`}
|
||||
{note.name ?? formatPubKey(note.pubkey)}
|
||||
</Text>
|
||||
</Layout>
|
||||
</TouchableOpacity>
|
||||
@ -86,9 +86,9 @@ export const NoteCard: React.FC<NoteCardProps> = ({
|
||||
</Layout>
|
||||
</Layout>
|
||||
<Layout style={styles.text}>
|
||||
<Markdown style={markdownStyle(theme)} markdownit={markdownIt}>
|
||||
{note.content}
|
||||
</Markdown>
|
||||
<TextBox note={note}>
|
||||
<Text>{note.content}</Text>
|
||||
</TextBox>
|
||||
</Layout>
|
||||
<Layout style={styles.footer}>
|
||||
<Text appearance='hint'>{moment.unix(note.created_at).format('HH:mm DD-MM-YY')}</Text>
|
||||
@ -153,6 +153,7 @@ export const NoteCard: React.FC<NoteCardProps> = ({
|
||||
flexDirection: 'row',
|
||||
backgroundColor: 'transparent',
|
||||
paddingTop: 16,
|
||||
paddingLeft: 50
|
||||
},
|
||||
divider: {
|
||||
paddingTop: 16,
|
||||
|
@ -16,7 +16,7 @@ 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 { populatePets } from '../../Functions/RelayFunctions/Users'
|
||||
import { formatPubKey, populatePets } from '../../Functions/RelayFunctions/Users'
|
||||
import { getReplyEventId } from '../../Functions/RelayFunctions/Events'
|
||||
import Loading from '../Loading'
|
||||
import { handleInfinityScroll } from '../../Functions/NativeFunctions'
|
||||
@ -35,7 +35,7 @@ export const ProfilePage: React.FC = () => {
|
||||
const [refreshing, setRefreshing] = useState(false)
|
||||
const breadcrump = page.split('%')
|
||||
const userId = breadcrump[breadcrump.length - 1].split('#')[1] ?? publicKey
|
||||
const username = user?.name === '' ? user?.id : user?.name
|
||||
const username = user?.name === '' ? formatPubKey(user.id) : user?.name
|
||||
|
||||
useEffect(() => {
|
||||
setRefreshing(true)
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Button, Input, Layout, Spinner, TopNavigation, useTheme } from '@ui-kitten/components'
|
||||
import React, { useContext, useEffect, useState } from 'react'
|
||||
import { StyleSheet } from 'react-native'
|
||||
import { Button, Input, Layout, List, ListItem, Spinner, TopNavigation, useTheme } from '@ui-kitten/components'
|
||||
import React, { useContext, useEffect, useRef, useState } from 'react'
|
||||
import { ScrollView, StyleSheet } from 'react-native'
|
||||
import { AppContext } from '../../Contexts/AppContext'
|
||||
import Icon from 'react-native-vector-icons/FontAwesome5'
|
||||
import { Event, EventKind } from '../../lib/nostr/Events'
|
||||
@ -9,14 +9,20 @@ import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
||||
import moment from 'moment'
|
||||
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'
|
||||
|
||||
export const SendPage: React.FC = () => {
|
||||
const theme = useTheme()
|
||||
const { goBack, page, database } = useContext(AppContext)
|
||||
const { relayPool, publicKey } = useContext(RelayPoolContext)
|
||||
const { t } = useTranslation('common')
|
||||
const scrollViewRef = useRef<Input>()
|
||||
const [content, setContent] = useState<string>('')
|
||||
const [sending, setSending] = useState<boolean>(false)
|
||||
const [userSuggestions, setUserSuggestions] = useState<User[]>([])
|
||||
const [userMentions, setUserMentions] = useState<User[]>([])
|
||||
const breadcrump = page.split('%')
|
||||
const eventId = breadcrump[breadcrump.length - 1].split('#')[1]
|
||||
|
||||
@ -42,12 +48,30 @@ export const SendPage: React.FC = () => {
|
||||
goBack()
|
||||
}
|
||||
|
||||
const onChangeText: (text: string) => void = (text) => {
|
||||
const match = text.match(/@(\S*)$/)
|
||||
if (database && match && match[1].length > 0) {
|
||||
getUsers(database, { name: match[1] }).then((results) => {
|
||||
setUserSuggestions(results)
|
||||
})
|
||||
} else {
|
||||
setUserSuggestions([])
|
||||
}
|
||||
setContent(text)
|
||||
}
|
||||
|
||||
const mentionText: (user: User) => string = (user) => {
|
||||
return `@${user.name ?? formatPubKey(user.id)}`
|
||||
}
|
||||
|
||||
const onPressSend: () => void = () => {
|
||||
if (database && publicKey) {
|
||||
getNotes(database, { filters: { id: eventId } }).then((notes) => {
|
||||
let tags: string[][] = []
|
||||
const note = notes[0]
|
||||
|
||||
let rawContent = content
|
||||
|
||||
if (note) {
|
||||
tags = note.tags
|
||||
if (getETags(note).length === 0) {
|
||||
@ -56,28 +80,63 @@ export const SendPage: React.FC = () => {
|
||||
tags.push(['e', eventId, '', 'reply'])
|
||||
}
|
||||
}
|
||||
if (userMentions.length > 0) {
|
||||
userMentions.forEach((user) => {
|
||||
const userText = mentionText(user)
|
||||
if (rawContent.includes(userText)) {
|
||||
rawContent = rawContent.replace(userText, `#[${tags.length}]`)
|
||||
tags.push(['p', user.id])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const event: Event = {
|
||||
content,
|
||||
content: rawContent,
|
||||
created_at: moment().unix(),
|
||||
kind: EventKind.textNote,
|
||||
pubkey: publicKey,
|
||||
tags,
|
||||
}
|
||||
relayPool?.sendEvent(event).then((sentNote) => {
|
||||
if (sentNote?.id) {
|
||||
relayPool?.subscribe('main-channel', {
|
||||
kinds: [EventKind.textNote],
|
||||
ids: [sentNote.id],
|
||||
})
|
||||
goBack()
|
||||
}
|
||||
})
|
||||
relayPool?.sendEvent(event)
|
||||
setSending(true)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const addUserMention: (user: User) => void = (user) => {
|
||||
setUserMentions((prev) => {
|
||||
prev.push(user)
|
||||
return prev
|
||||
})
|
||||
setContent((prev) => {
|
||||
const splitText = prev.split("@")
|
||||
splitText.pop()
|
||||
return `${splitText.join("@")}${mentionText(user)}`
|
||||
})
|
||||
setUserSuggestions([])
|
||||
scrollViewRef.current?.focus()
|
||||
}
|
||||
|
||||
const suggestionsList: () => JSX.Element = () => {
|
||||
const renderItem: (item: { item: User }) => JSX.Element = ({item}) => {
|
||||
return <ListItem
|
||||
title={`${item.name ?? item.id}`}
|
||||
accessoryLeft={<Avatar name={item.name} src={item.picture} pubKey={item.id} size={25}/>}
|
||||
onPress={() => addUserMention(item)}
|
||||
/>
|
||||
};
|
||||
|
||||
return userSuggestions.length > 0 ?
|
||||
(
|
||||
<List
|
||||
data={userSuggestions}
|
||||
renderItem={renderItem}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
};
|
||||
|
||||
const renderBackAction = (): JSX.Element => (
|
||||
<Button
|
||||
accessoryRight={<Icon name='arrow-left' size={16} color={theme['text-basic-color']} />}
|
||||
@ -97,11 +156,12 @@ export const SendPage: React.FC = () => {
|
||||
<Layout style={styles.actionContainer} level='2'>
|
||||
<Layout>
|
||||
<Input
|
||||
ref={scrollViewRef}
|
||||
multiline={true}
|
||||
textStyle={{ minHeight: 64 }}
|
||||
placeholder={t('sendPage.placeholder')}
|
||||
value={content}
|
||||
onChangeText={setContent}
|
||||
onChangeText={onChangeText}
|
||||
size='large'
|
||||
autoFocus={true}
|
||||
keyboardType='twitter'
|
||||
@ -116,6 +176,7 @@ export const SendPage: React.FC = () => {
|
||||
{t('sendPage.send')}
|
||||
</Button>
|
||||
</Layout>
|
||||
{suggestionsList()}
|
||||
</Layout>
|
||||
</Layout>
|
||||
</>
|
||||
|
94
frontend/Components/TextBox/index.tsx
Normal file
94
frontend/Components/TextBox/index.tsx
Normal file
@ -0,0 +1,94 @@
|
||||
import React, { useContext, useState } from 'react'
|
||||
import ParsedText from 'react-native-parsed-text';
|
||||
import { useTheme } from '@ui-kitten/components'
|
||||
import { Event } from '../../lib/nostr/Events'
|
||||
import { Linking, StyleSheet } from 'react-native';
|
||||
import { AppContext } from '../../Contexts/AppContext';
|
||||
import { getUser } from '../../Functions/DatabaseFunctions/Users';
|
||||
import { formatPubKey } from '../../Functions/RelayFunctions/Users';
|
||||
|
||||
interface TextBoxProps {
|
||||
note: Event
|
||||
}
|
||||
|
||||
export const TextBox: React.FC<TextBoxProps> = ({
|
||||
note
|
||||
}) => {
|
||||
const theme = useTheme()
|
||||
const { database, goToPage } = useContext(AppContext)
|
||||
const [userNames, setUserNames] = useState<{[index: number]: string}>({})
|
||||
|
||||
const handleUrlPress: (url: string) => void = (url) => {
|
||||
Linking.openURL(url);
|
||||
}
|
||||
|
||||
const handleEmailPress: (email: string) => void = (email) => {
|
||||
Linking.openURL(email);
|
||||
}
|
||||
|
||||
const handleMentionPress: (text: string) => void = (text) => {
|
||||
const mentionIndex: number = parseInt(text.substring(2, text.length - 1))
|
||||
goToPage(`profile#${note.tags[mentionIndex][1]}`)
|
||||
}
|
||||
|
||||
const renderMentionText: (matchingString: string, matches: string[]) => string = (_matchingString, matches) => {
|
||||
const mentionIndex: number = parseInt(matches[1])
|
||||
const pudKey = note.tags[mentionIndex][1]
|
||||
|
||||
if (userNames[mentionIndex]) {
|
||||
return userNames[mentionIndex]
|
||||
} else {
|
||||
if (database) {
|
||||
getUser(pudKey, database).then((user) => {
|
||||
setUserNames((prev) => {
|
||||
if (user?.name) {
|
||||
prev[mentionIndex] = `@${user.name}`
|
||||
}
|
||||
return prev
|
||||
})
|
||||
})
|
||||
}
|
||||
return `@${formatPubKey(pudKey)}`
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
url: {
|
||||
textDecorationLine: 'underline',
|
||||
},
|
||||
email: {
|
||||
textDecorationLine: 'underline',
|
||||
},
|
||||
text: {
|
||||
color: theme['text-basic-color'],
|
||||
},
|
||||
mention: {
|
||||
fontWeight: 'bold',
|
||||
textDecorationLine: 'underline',
|
||||
},
|
||||
hashTag: {
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
})
|
||||
|
||||
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},
|
||||
{pattern: /#(\w+)/, style: styles.hashTag},
|
||||
]
|
||||
}
|
||||
childrenProps={{allowFontScaling: false}}
|
||||
>
|
||||
{note.content}
|
||||
</ParsedText>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export default TextBox
|
@ -1,48 +0,0 @@
|
||||
import { StyleSheet } from 'react-native'
|
||||
import { MarkdownIt } from 'react-native-markdown-display'
|
||||
|
||||
export const markdownStyle: (theme: Record<string, string>) => StyleSheet.NamedStyles<any> = (
|
||||
theme,
|
||||
) => {
|
||||
return {
|
||||
text: {
|
||||
color: theme['text-basic-color'],
|
||||
},
|
||||
tr: {
|
||||
borderColor: theme['border-primary-color-5'],
|
||||
},
|
||||
table: {
|
||||
borderColor: theme['border-primary-color-5'],
|
||||
},
|
||||
blocklink: {
|
||||
borderColor: theme['border-primary-color-5'],
|
||||
},
|
||||
hr: {
|
||||
backgroundColor: theme['background-basic-color-3'],
|
||||
},
|
||||
blockquote: {
|
||||
backgroundColor: theme['background-basic-color-3'],
|
||||
borderColor: theme['border-primary-color-5'],
|
||||
color: theme['text-basic-color'],
|
||||
},
|
||||
code_inline: {
|
||||
borderColor: theme['border-primary-color-5'],
|
||||
backgroundColor: theme['background-basic-color-3'],
|
||||
color: theme['text-basic-color'],
|
||||
},
|
||||
code_block: {
|
||||
borderColor: theme['border-primary-color-5'],
|
||||
backgroundColor: theme['background-basic-color-3'],
|
||||
color: theme['text-basic-color'],
|
||||
},
|
||||
fence: {
|
||||
borderColor: theme['border-primary-color-5'],
|
||||
backgroundColor: theme['background-basic-color-3'],
|
||||
color: theme['text-basic-color'],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const markdownIt = new MarkdownIt({
|
||||
linkify: true,
|
||||
})
|
@ -4,7 +4,6 @@ import { initDatabase } from '../Functions/DatabaseFunctions'
|
||||
import FlashMessage from 'react-native-flash-message'
|
||||
import SInfo from 'react-native-sensitive-info'
|
||||
import { BackHandler } from 'react-native'
|
||||
import { markdownIt } from '../Constants/AppConstants'
|
||||
|
||||
export interface AppContextProps {
|
||||
page: string
|
||||
@ -36,11 +35,6 @@ export const AppContextProvider = ({ children }: AppContextProviderProps): JSX.E
|
||||
const [loadingDb, setLoadingDb] = useState<boolean>(initialAppContext.loadingDb)
|
||||
|
||||
const init: () => void = () => {
|
||||
markdownIt.linkify
|
||||
.tlds('onion', true)
|
||||
.add('git:', 'http:')
|
||||
.add('ftp:', null)
|
||||
.set({ fuzzyIP: true })
|
||||
const db = initDatabase()
|
||||
setDatabase(db)
|
||||
SInfo.getItem('privateKey', {}).then(() => {
|
||||
|
@ -54,8 +54,8 @@ export const addUser: (pubKey: string, db: QuickSQLiteConnection) => Promise<Que
|
||||
|
||||
export const getUsers: (
|
||||
db: QuickSQLiteConnection,
|
||||
options: { exludeIds?: string[]; contacts?: boolean; followers?: boolean; includeIds?: string[] },
|
||||
) => Promise<User[]> = async (db, { exludeIds, contacts, followers, includeIds }) => {
|
||||
options: { name?: string, exludeIds?: string[]; contacts?: boolean; followers?: boolean; includeIds?: string[] },
|
||||
) => Promise<User[]> = async (db, { name, exludeIds, contacts, followers, includeIds }) => {
|
||||
let userQuery = 'SELECT * FROM nostros_users '
|
||||
|
||||
const filters = []
|
||||
@ -63,6 +63,10 @@ export const getUsers: (
|
||||
if (contacts) {
|
||||
filters.push('contact = 1')
|
||||
}
|
||||
|
||||
if (name) {
|
||||
filters.push(`name LIKE '%${name}%'`)
|
||||
}
|
||||
|
||||
if (includeIds && includeIds.length > 0) {
|
||||
filters.push(`id IN ('${includeIds.join("', '")}')`)
|
||||
|
@ -23,7 +23,7 @@ export const username: (user: User) => string = (user) => {
|
||||
}
|
||||
|
||||
export const formatPubKey: (pubKey: string) => string = (pubKey) => {
|
||||
return `${pubKey.slice(0, 8)}...${pubKey.slice(-8)}`
|
||||
return `${pubKey.slice(0, 4)}...${pubKey.slice(-4)}`
|
||||
}
|
||||
|
||||
export const populatePets: (
|
||||
|
@ -25,7 +25,6 @@
|
||||
"events": "^3.3.0",
|
||||
"i18next": "^22.0.6",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"markdown-it": "^13.0.1",
|
||||
"moment": "^2.29.4",
|
||||
"nostr-tools": "^0.24.1",
|
||||
"react": "18.1.0",
|
||||
@ -34,8 +33,8 @@
|
||||
"react-native-action-button": "^2.8.5",
|
||||
"react-native-bidirectional-infinite-scroll": "^0.3.3",
|
||||
"react-native-flash-message": "^0.3.1",
|
||||
"react-native-markdown-display": "^7.0.0-alpha.2",
|
||||
"react-native-multithreading": "^1.1.1",
|
||||
"react-native-parsed-text": "^0.0.22",
|
||||
"react-native-quick-sqlite": "^6.1.1",
|
||||
"react-native-reanimated": "^2.13.0",
|
||||
"react-native-securerandom": "^1.0.1",
|
||||
@ -55,6 +54,7 @@
|
||||
"@react-native-community/eslint-config": "^3.2.0",
|
||||
"@types/create-hash": "^1.2.2",
|
||||
"@types/jest": "^29.2.2",
|
||||
"@types/linkify-it": "^3.0.2",
|
||||
"@types/lodash.debounce": "^4.0.7",
|
||||
"@types/react-native": "^0.70.6",
|
||||
"@types/react-native-sqlite-storage": "^5.0.2",
|
||||
|
104
yarn.lock
104
yarn.lock
@ -1623,6 +1623,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
|
||||
|
||||
"@types/linkify-it@^3.0.2":
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.2.tgz#fd2cd2edbaa7eaac7e7f3c1748b52a19143846c9"
|
||||
integrity sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==
|
||||
|
||||
"@types/lodash.debounce@^4.0.7":
|
||||
version "4.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash.debounce/-/lodash.debounce-4.0.7.tgz#0285879defb7cdb156ae633cecd62d5680eded9f"
|
||||
@ -2637,11 +2642,6 @@ camelcase@^6.0.0, camelcase@^6.2.0:
|
||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
|
||||
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
|
||||
|
||||
camelize@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.1.tgz#89b7e16884056331a35d6b5ad064332c91daa6c3"
|
||||
integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==
|
||||
|
||||
caniuse-lite@^1.0.30001400:
|
||||
version "1.0.30001427"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001427.tgz#d3a749f74be7ae0671fbec3a4eea18576e8ad646"
|
||||
@ -2978,11 +2978,6 @@ cryptr@^6.0.3:
|
||||
resolved "https://registry.yarnpkg.com/cryptr/-/cryptr-6.0.3.tgz#669364e7993a1cd19d77e32e90ffef38455ecd74"
|
||||
integrity sha512-Nhaxn3CYl/OoWF3JSZlF8B6FQO600RRkU3g8213OGEIq4YvMlc3od8hL9chubhY1SmTq8ienvCRq1MSFjMTpOg==
|
||||
|
||||
css-color-keywords@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
|
||||
integrity sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==
|
||||
|
||||
css-select@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.1.0.tgz#b8ebd6554c3637ccc76688804ad3f6a6fdaea8a6"
|
||||
@ -2994,15 +2989,6 @@ css-select@^5.1.0:
|
||||
domutils "^3.0.1"
|
||||
nth-check "^2.0.1"
|
||||
|
||||
css-to-react-native@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.0.0.tgz#62dbe678072a824a689bcfee011fc96e02a7d756"
|
||||
integrity sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==
|
||||
dependencies:
|
||||
camelize "^1.0.0"
|
||||
css-color-keywords "^1.0.0"
|
||||
postcss-value-parser "^4.0.2"
|
||||
|
||||
css-tree@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d"
|
||||
@ -3296,16 +3282,6 @@ entities@^4.2.0:
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174"
|
||||
integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==
|
||||
|
||||
entities@~2.0.0:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f"
|
||||
integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==
|
||||
|
||||
entities@~3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4"
|
||||
integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==
|
||||
|
||||
envinfo@^7.7.2:
|
||||
version "7.8.1"
|
||||
resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475"
|
||||
@ -5536,13 +5512,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@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.2.0.tgz#e3b54697e78bf915c70a38acd78fd09e0058b1cf"
|
||||
integrity sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==
|
||||
dependencies:
|
||||
uc.micro "^1.0.1"
|
||||
|
||||
linkify-it@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-4.0.1.tgz#01f1d5e508190d06669982ba31a7d9f56a5751ec"
|
||||
@ -5662,28 +5631,6 @@ map-visit@^1.0.0:
|
||||
dependencies:
|
||||
object-visit "^1.0.0"
|
||||
|
||||
markdown-it@^10.0.0:
|
||||
version "10.0.0"
|
||||
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-10.0.0.tgz#abfc64f141b1722d663402044e43927f1f50a8dc"
|
||||
integrity sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==
|
||||
dependencies:
|
||||
argparse "^1.0.7"
|
||||
entities "~2.0.0"
|
||||
linkify-it "^2.0.0"
|
||||
mdurl "^1.0.1"
|
||||
uc.micro "^1.0.5"
|
||||
|
||||
markdown-it@^13.0.1:
|
||||
version "13.0.1"
|
||||
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-13.0.1.tgz#c6ecc431cacf1a5da531423fc6a42807814af430"
|
||||
integrity sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==
|
||||
dependencies:
|
||||
argparse "^2.0.1"
|
||||
entities "~3.0.1"
|
||||
linkify-it "^4.0.1"
|
||||
mdurl "^1.0.1"
|
||||
uc.micro "^1.0.5"
|
||||
|
||||
md5.js@^1.3.4:
|
||||
version "1.3.5"
|
||||
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
|
||||
@ -6693,11 +6640,6 @@ posix-character-classes@^0.1.0:
|
||||
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
|
||||
integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==
|
||||
|
||||
postcss-value-parser@^4.0.2:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
|
||||
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
|
||||
|
||||
prelude-ls@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
|
||||
@ -6768,7 +6710,7 @@ prompts@^2.0.1, prompts@^2.4.0:
|
||||
kleur "^3.0.3"
|
||||
sisteransi "^1.0.5"
|
||||
|
||||
prop-types@^15.5.10, prop-types@^15.7.2, prop-types@^15.8.1:
|
||||
prop-types@^15.5.10, prop-types@^15.7.2, prop-types@^15.7.x, prop-types@^15.8.1:
|
||||
version "15.8.1"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
||||
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||
@ -6885,13 +6827,6 @@ react-native-eva-icons@^1.3.1:
|
||||
resolved "https://registry.yarnpkg.com/react-native-eva-icons/-/react-native-eva-icons-1.3.1.tgz#1e6e019b0fd3cb1669db50bd6bbdaa6d89327593"
|
||||
integrity sha512-emd/aYXuOacuDVTx0SJoLi+xsOdCNdljQB3PTNCM9AQ3m/smG0X1TN0+ihelPO7MqoHzaH0h6lbANtwxGUy8Fw==
|
||||
|
||||
react-native-fit-image@^1.5.5:
|
||||
version "1.5.5"
|
||||
resolved "https://registry.yarnpkg.com/react-native-fit-image/-/react-native-fit-image-1.5.5.tgz#c660d1ad74b9dcaa1cba27a0d9c23837e000226c"
|
||||
integrity sha512-Wl3Vq2DQzxgsWKuW4USfck9zS7YzhvLNPpkwUUCF90bL32e1a0zOVQ3WsJILJOwzmPdHfzZmWasiiAUNBkhNkg==
|
||||
dependencies:
|
||||
prop-types "^15.5.10"
|
||||
|
||||
react-native-flash-message@^0.3.1:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react-native-flash-message/-/react-native-flash-message-0.3.1.tgz#e88073dffa826385c92aebf9244438940fbcffec"
|
||||
@ -6905,26 +6840,31 @@ 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"
|
||||
integrity sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg==
|
||||
|
||||
react-native-markdown-display@^7.0.0-alpha.2:
|
||||
version "7.0.0-alpha.2"
|
||||
resolved "https://registry.yarnpkg.com/react-native-markdown-display/-/react-native-markdown-display-7.0.0-alpha.2.tgz#a48a70d3cb5c510a52ecf7f1509a4a3d14d728aa"
|
||||
integrity sha512-Od1a4wJEcVGwO1bh02sHivsEkKKpu99+ew/OtmVTPRmfT8V3B0aTut7k7ICV0Vej9F4ZjylRHvm28/maYUBeGw==
|
||||
dependencies:
|
||||
css-to-react-native "^3.0.0"
|
||||
markdown-it "^10.0.0"
|
||||
prop-types "^15.7.2"
|
||||
react-native-fit-image "^1.5.5"
|
||||
|
||||
react-native-multithreading@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-native-multithreading/-/react-native-multithreading-1.1.1.tgz#e1522ecd56115993d444a69c21bca49ca123bf4e"
|
||||
integrity sha512-ceJQRZAPjH5LfrDjb5svF4F18Ne7QR7QLQUFO0huAe+9w0hd2C3PR12ATxljo+590GXCzWRt2ruR9pY3EstFAQ==
|
||||
|
||||
react-native-parsed-text@^0.0.22:
|
||||
version "0.0.22"
|
||||
resolved "https://registry.yarnpkg.com/react-native-parsed-text/-/react-native-parsed-text-0.0.22.tgz#a23c756eaa5d6724296814755085127f9072e5f5"
|
||||
integrity sha512-hfD83RDXZf9Fvth3DowR7j65fMnlqM9PpxZBGWkzVcUTFtqe6/yPcIoIAgrJbKn6YmtzkivmhWE2MCE4JKBXrQ==
|
||||
dependencies:
|
||||
prop-types "^15.7.x"
|
||||
|
||||
react-native-quick-sqlite@^6.1.1:
|
||||
version "6.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-native-quick-sqlite/-/react-native-quick-sqlite-6.1.1.tgz#ba35d0a4a919a5a0962306c3fee4dc46983b0839"
|
||||
@ -7997,7 +7937,7 @@ 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, uc.micro@^1.0.5:
|
||||
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==
|
||||
|
Loading…
Reference in New Issue
Block a user