mirror of
https://github.com/tooot-app/app
synced 2025-05-05 20:38:42 +02:00
commit
ff4de793fd
@ -1,5 +1,5 @@
|
|||||||
# [tooot](https://tooot.app/) app for Mastodon
|
# [tooot](https://tooot.app/) app for Mastodon
|
||||||
|
|
||||||
[](LICENSE)   
|
[](LICENSE)    [](https://crowdin.tooot.app/project/tooot)
|
||||||
|
|
||||||
  
|
  
|
||||||
|
@ -83,7 +83,8 @@
|
|||||||
"redux-persist": "^6.0.0",
|
"redux-persist": "^6.0.0",
|
||||||
"rn-placeholder": "^3.0.3",
|
"rn-placeholder": "^3.0.3",
|
||||||
"sentry-expo": "^3.0.5",
|
"sentry-expo": "^3.0.5",
|
||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0",
|
||||||
|
"valid-url": "^1.0.9"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "~7.13.10",
|
"@babel/core": "~7.13.10",
|
||||||
@ -103,6 +104,7 @@
|
|||||||
"@types/react-redux": "^7.1.16",
|
"@types/react-redux": "^7.1.16",
|
||||||
"@types/react-test-renderer": "^17.0.1",
|
"@types/react-test-renderer": "^17.0.1",
|
||||||
"@types/react-timeago": "^4.1.2",
|
"@types/react-timeago": "^4.1.2",
|
||||||
|
"@types/valid-url": "^1.0.3",
|
||||||
"@welldone-software/why-did-you-render": "^6.1.1",
|
"@welldone-software/why-did-you-render": "^6.1.1",
|
||||||
"babel-jest": "~26.6.3",
|
"babel-jest": "~26.6.3",
|
||||||
"babel-plugin-module-resolver": "^4.1.0",
|
"babel-plugin-module-resolver": "^4.1.0",
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { StyleConstants } from '@utils/styles/constants'
|
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React, { useCallback, useMemo, useRef, useState } from 'react'
|
import React, { useCallback, useMemo, useRef, useState } from 'react'
|
||||||
import {
|
import {
|
||||||
|
@ -274,12 +274,6 @@ const styles = StyleSheet.create({
|
|||||||
...StyleConstants.FontStyle.M,
|
...StyleConstants.FontStyle.M,
|
||||||
marginRight: StyleConstants.Spacing.M
|
marginRight: StyleConstants.Spacing.M
|
||||||
},
|
},
|
||||||
privateInstance: {
|
|
||||||
...StyleConstants.FontStyle.S,
|
|
||||||
fontWeight: StyleConstants.Font.Weight.Bold,
|
|
||||||
marginLeft: StyleConstants.Spacing.Global.PagePadding,
|
|
||||||
marginTop: StyleConstants.Spacing.XS
|
|
||||||
},
|
|
||||||
instanceStats: {
|
instanceStats: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'row'
|
flexDirection: 'row'
|
||||||
|
@ -7,6 +7,7 @@ import React, { useMemo } from 'react'
|
|||||||
import { StyleSheet, Text } from 'react-native'
|
import { StyleSheet, Text } from 'react-native'
|
||||||
import FastImage from 'react-native-fast-image'
|
import FastImage from 'react-native-fast-image'
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux'
|
||||||
|
import validUrl from 'valid-url'
|
||||||
|
|
||||||
const regexEmoji = new RegExp(/(:[A-Za-z0-9_]+:)/)
|
const regexEmoji = new RegExp(/(:[A-Za-z0-9_]+:)/)
|
||||||
|
|
||||||
@ -67,25 +68,30 @@ const ParseEmojis = React.memo(
|
|||||||
const emojiIndex = emojis.findIndex(emoji => {
|
const emojiIndex = emojis.findIndex(emoji => {
|
||||||
return emojiShortcode === `:${emoji.shortcode}:`
|
return emojiShortcode === `:${emoji.shortcode}:`
|
||||||
})
|
})
|
||||||
return emojiIndex === -1 ? (
|
if (emojiIndex === -1) {
|
||||||
<Text key={i}>{emojiShortcode}</Text>
|
return <Text>{emojiShortcode}</Text>
|
||||||
) : (
|
} else {
|
||||||
<Text key={i}>
|
if (i === 0) {
|
||||||
{/* When emoji starts a paragraph, lineHeight will break */}
|
return <Text key={emojiShortcode}> </Text>
|
||||||
{i === 0 ? <Text> </Text> : null}
|
} else {
|
||||||
<FastImage
|
const uri = reduceMotionEnabled
|
||||||
key={adaptiveFontsize}
|
? emojis[emojiIndex].static_url
|
||||||
source={{
|
: emojis[emojiIndex].url
|
||||||
uri: reduceMotionEnabled
|
if (validUrl.isHttpsUri(uri)) {
|
||||||
? emojis[emojiIndex].static_url
|
return (
|
||||||
: emojis[emojiIndex].url
|
<FastImage
|
||||||
}}
|
key={emojiShortcode}
|
||||||
style={styles.image}
|
source={{ uri }}
|
||||||
/>
|
style={styles.image}
|
||||||
</Text>
|
/>
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return <Text key={i}>{str}</Text>
|
return <Text key={str}>{str}</Text>
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
) : (
|
) : (
|
||||||
|
@ -95,15 +95,46 @@ const TimelineAttachment = React.memo(
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
return (
|
if (
|
||||||
<AttachmentUnsupported
|
attachment.preview_url.endsWith('.jpg') ||
|
||||||
key={index}
|
attachment.preview_url.endsWith('.jpeg') ||
|
||||||
total={status.media_attachments.length}
|
attachment.preview_url.endsWith('.png') ||
|
||||||
index={index}
|
attachment.preview_url.endsWith('.gif') ||
|
||||||
sensitiveShown={sensitiveShown}
|
attachment.remote_url?.endsWith('.jpg') ||
|
||||||
attachment={attachment}
|
attachment.remote_url?.endsWith('.jpeg') ||
|
||||||
/>
|
attachment.remote_url?.endsWith('.png') ||
|
||||||
)
|
attachment.remote_url?.endsWith('.gif')
|
||||||
|
) {
|
||||||
|
imageUrls.push({
|
||||||
|
id: attachment.id,
|
||||||
|
url: attachment.url,
|
||||||
|
remote_url: attachment.remote_url,
|
||||||
|
blurhash: attachment.blurhash,
|
||||||
|
width: attachment.meta?.original?.width,
|
||||||
|
height: attachment.meta?.original?.height
|
||||||
|
})
|
||||||
|
return (
|
||||||
|
<AttachmentImage
|
||||||
|
key={index}
|
||||||
|
total={status.media_attachments.length}
|
||||||
|
index={index}
|
||||||
|
sensitiveShown={sensitiveShown}
|
||||||
|
// @ts-ignore
|
||||||
|
image={attachment}
|
||||||
|
navigateToImagesViewer={navigateToImagesViewer}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<AttachmentUnsupported
|
||||||
|
key={index}
|
||||||
|
total={status.media_attachments.length}
|
||||||
|
index={index}
|
||||||
|
sensitiveShown={sensitiveShown}
|
||||||
|
attachment={attachment}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
[sensitiveShown]
|
[sensitiveShown]
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import analytics from '@components/analytics'
|
import analytics from '@components/analytics'
|
||||||
import haptics from '@components/haptics'
|
import haptics from '@components/haptics'
|
||||||
|
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React, { useCallback, useContext, useMemo } from 'react'
|
import React, { useCallback, useContext, useMemo } from 'react'
|
||||||
import { Pressable, SectionList, StyleSheet, Text, View } from 'react-native'
|
import { Pressable, SectionList, StyleSheet, Text, View } from 'react-native'
|
||||||
import ComposeContext from '../../utils/createContext'
|
|
||||||
import updateText from '../../updateText'
|
|
||||||
import FastImage from 'react-native-fast-image'
|
import FastImage from 'react-native-fast-image'
|
||||||
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
|
import validUrl from 'valid-url'
|
||||||
|
import updateText from '../../updateText'
|
||||||
|
import ComposeContext from '../../utils/createContext'
|
||||||
|
|
||||||
const SingleEmoji = ({ emoji }: { emoji: Mastodon.Emoji }) => {
|
const SingleEmoji = ({ emoji }: { emoji: Mastodon.Emoji }) => {
|
||||||
const { reduceMotionEnabled } = useAccessibility()
|
const { reduceMotionEnabled } = useAccessibility()
|
||||||
@ -21,21 +22,21 @@ const SingleEmoji = ({ emoji }: { emoji: Mastodon.Emoji }) => {
|
|||||||
newText: `:${emoji.shortcode}:`,
|
newText: `:${emoji.shortcode}:`,
|
||||||
type: 'emoji'
|
type: 'emoji'
|
||||||
})
|
})
|
||||||
// composeDispatch({
|
|
||||||
// type: 'emoji',
|
|
||||||
// payload: { ...composeState.emoji, active: false }
|
|
||||||
// })
|
|
||||||
haptics('Light')
|
haptics('Light')
|
||||||
}, [composeState])
|
}, [composeState])
|
||||||
const children = useMemo(
|
const children = useMemo(() => {
|
||||||
() => (
|
const uri = reduceMotionEnabled ? emoji.static_url : emoji.url
|
||||||
<FastImage
|
if (validUrl.isHttpsUri(uri)) {
|
||||||
source={{ uri: reduceMotionEnabled ? emoji.static_url : emoji.url }}
|
return (
|
||||||
style={styles.emoji}
|
<FastImage
|
||||||
/>
|
source={{ uri: reduceMotionEnabled ? emoji.static_url : emoji.url }}
|
||||||
),
|
style={styles.emoji}
|
||||||
[]
|
/>
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
return (
|
return (
|
||||||
<Pressable key={emoji.shortcode} onPress={onPress} children={children} />
|
<Pressable key={emoji.shortcode} onPress={onPress} children={children} />
|
||||||
)
|
)
|
||||||
|
@ -81,25 +81,35 @@ const TabSharedSearch: React.FC<SharedSearchProp> = ({
|
|||||||
components={{ bold: <Text style={styles.emptyFontBold} /> }}
|
components={{ bold: <Text style={styles.emptyFontBold} /> }}
|
||||||
/>
|
/>
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={[styles.emptyAdvanced, { color: theme.primaryDefault }]}>
|
<Text
|
||||||
|
style={[styles.emptyAdvanced, { color: theme.primaryDefault }]}
|
||||||
|
>
|
||||||
{t('shared.search.empty.advanced.header')}
|
{t('shared.search.empty.advanced.header')}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={[styles.emptyAdvanced, { color: theme.primaryDefault }]}>
|
<Text
|
||||||
|
style={[styles.emptyAdvanced, { color: theme.primaryDefault }]}
|
||||||
|
>
|
||||||
<Text style={{ color: theme.secondary }}>@username@domain</Text>
|
<Text style={{ color: theme.secondary }}>@username@domain</Text>
|
||||||
{' '}
|
{' '}
|
||||||
{t('shared.search.empty.advanced.example.account')}
|
{t('shared.search.empty.advanced.example.account')}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={[styles.emptyAdvanced, { color: theme.primaryDefault }]}>
|
<Text
|
||||||
|
style={[styles.emptyAdvanced, { color: theme.primaryDefault }]}
|
||||||
|
>
|
||||||
<Text style={{ color: theme.secondary }}>#example</Text>
|
<Text style={{ color: theme.secondary }}>#example</Text>
|
||||||
{' '}
|
{' '}
|
||||||
{t('shared.search.empty.advanced.example.hashtag')}
|
{t('shared.search.empty.advanced.example.hashtag')}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={[styles.emptyAdvanced, { color: theme.primaryDefault }]}>
|
<Text
|
||||||
|
style={[styles.emptyAdvanced, { color: theme.primaryDefault }]}
|
||||||
|
>
|
||||||
<Text style={{ color: theme.secondary }}>URL</Text>
|
<Text style={{ color: theme.secondary }}>URL</Text>
|
||||||
{' '}
|
{' '}
|
||||||
{t('shared.search.empty.advanced.example.statusLink')}
|
{t('shared.search.empty.advanced.example.statusLink')}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={[styles.emptyAdvanced, { color: theme.primaryDefault }]}>
|
<Text
|
||||||
|
style={[styles.emptyAdvanced, { color: theme.primaryDefault }]}
|
||||||
|
>
|
||||||
<Text style={{ color: theme.secondary }}>URL</Text>
|
<Text style={{ color: theme.secondary }}>URL</Text>
|
||||||
{' '}
|
{' '}
|
||||||
{t('shared.search.empty.advanced.example.accountLink')}
|
{t('shared.search.empty.advanced.example.accountLink')}
|
||||||
@ -113,9 +123,14 @@ const TabSharedSearch: React.FC<SharedSearchProp> = ({
|
|||||||
const sectionHeader = useCallback(
|
const sectionHeader = useCallback(
|
||||||
({ section: { translation } }) => (
|
({ section: { translation } }) => (
|
||||||
<View
|
<View
|
||||||
style={[styles.sectionHeader, { backgroundColor: theme.backgroundDefault }]}
|
style={[
|
||||||
|
styles.sectionHeader,
|
||||||
|
{ backgroundColor: theme.backgroundDefault }
|
||||||
|
]}
|
||||||
>
|
>
|
||||||
<Text style={[styles.sectionHeaderText, { color: theme.primaryDefault }]}>
|
<Text
|
||||||
|
style={[styles.sectionHeaderText, { color: theme.primaryDefault }]}
|
||||||
|
>
|
||||||
{translation}
|
{translation}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
@ -126,11 +141,14 @@ const TabSharedSearch: React.FC<SharedSearchProp> = ({
|
|||||||
({ section: { data, translation } }) =>
|
({ section: { data, translation } }) =>
|
||||||
!data.length ? (
|
!data.length ? (
|
||||||
<View
|
<View
|
||||||
style={[styles.sectionFooter, { backgroundColor: theme.backgroundDefault }]}
|
style={[
|
||||||
|
styles.sectionFooter,
|
||||||
|
{ backgroundColor: theme.backgroundDefault }
|
||||||
|
]}
|
||||||
>
|
>
|
||||||
<Text style={[styles.sectionFooterText, { color: theme.secondary }]}>
|
<Text style={[styles.sectionFooterText, { color: theme.secondary }]}>
|
||||||
<Trans
|
<Trans
|
||||||
i18nKey='sharedSearch:content.notFound'
|
i18nKey='screenTabs:shared.search.notFound'
|
||||||
values={{ searchTerm: text, type: translation }}
|
values={{ searchTerm: text, type: translation }}
|
||||||
components={{ bold: <Text style={styles.emptyFontBold} /> }}
|
components={{ bold: <Text style={styles.emptyFontBold} /> }}
|
||||||
/>
|
/>
|
||||||
|
10
yarn.lock
10
yarn.lock
@ -2798,6 +2798,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff"
|
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff"
|
||||||
integrity sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==
|
integrity sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==
|
||||||
|
|
||||||
|
"@types/valid-url@^1.0.3":
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/valid-url/-/valid-url-1.0.3.tgz#a124389fb953559c7f889795a98620e91adb3687"
|
||||||
|
integrity sha512-+33x29mg+ecU88ODdWpqaie2upIuRkhujVLA7TuJjM823cNMbeggfI6NhxewaRaRF8dy+g33e4uIg/m5Mb3xDQ==
|
||||||
|
|
||||||
"@types/yargs-parser@*":
|
"@types/yargs-parser@*":
|
||||||
version "20.2.0"
|
version "20.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.0.tgz#dd3e6699ba3237f0348cd085e4698780204842f9"
|
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.0.tgz#dd3e6699ba3237f0348cd085e4698780204842f9"
|
||||||
@ -10463,6 +10468,11 @@ v8-to-istanbul@^7.0.0:
|
|||||||
convert-source-map "^1.6.0"
|
convert-source-map "^1.6.0"
|
||||||
source-map "^0.7.3"
|
source-map "^0.7.3"
|
||||||
|
|
||||||
|
valid-url@^1.0.9:
|
||||||
|
version "1.0.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/valid-url/-/valid-url-1.0.9.tgz#1c14479b40f1397a75782f115e4086447433a200"
|
||||||
|
integrity sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA=
|
||||||
|
|
||||||
validate-npm-package-license@^3.0.1:
|
validate-npm-package-license@^3.0.1:
|
||||||
version "3.0.4"
|
version "3.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
|
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user