mirror of
https://github.com/tooot-app/app
synced 2025-02-09 00:18:38 +01:00
Add centrally located prop-types
This commit is contained in:
parent
2ab227a370
commit
301772e735
@ -1,5 +1,7 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import propTypesEmoji from 'src/prop-types/emoji'
|
||||
import propTypesMention from 'src/prop-types/mention'
|
||||
import { StyleSheet, Text } from 'react-native'
|
||||
import HTMLView from 'react-native-htmlview'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
@ -109,16 +111,9 @@ const HTMLstyles = StyleSheet.create({
|
||||
|
||||
ParseContent.propTypes = {
|
||||
content: PropTypes.string.isRequired,
|
||||
emojis: Emojis.propTypes.emojis,
|
||||
emojis: PropTypes.arrayOf(propTypesEmoji),
|
||||
emojiSize: PropTypes.number,
|
||||
mentions: PropTypes.arrayOf(
|
||||
PropTypes.exact({
|
||||
id: PropTypes.string.isRequired,
|
||||
username: PropTypes.string.isRequired,
|
||||
url: PropTypes.string.isRequired,
|
||||
acct: PropTypes.string.isRequired
|
||||
})
|
||||
),
|
||||
mentions: PropTypes.arrayOf(propTypesMention),
|
||||
showFullLink: PropTypes.bool,
|
||||
linesTruncated: PropTypes.number
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import propTypesCard from 'src/prop-types/card'
|
||||
import { Image, Pressable, StyleSheet, Text, View } from 'react-native'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
|
||||
@ -54,20 +54,5 @@ const styles = StyleSheet.create({
|
||||
})
|
||||
|
||||
Card.propTypes = {
|
||||
card: PropTypes.exact({
|
||||
url: PropTypes.string.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
description: PropTypes.string,
|
||||
type: PropTypes.oneOf(['link', 'photo', 'video']),
|
||||
author_name: PropTypes.string,
|
||||
author_url: PropTypes.string,
|
||||
provider_name: PropTypes.string,
|
||||
provider_url: PropTypes.string,
|
||||
html: PropTypes.string,
|
||||
width: PropTypes.number,
|
||||
height: PropTypes.number,
|
||||
image: PropTypes.string,
|
||||
embed_url: PropTypes.string,
|
||||
blurhash: PropTypes.string
|
||||
}).isRequired
|
||||
card: propTypesCard
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import propTypesEmoji from 'src/prop-types/emoji'
|
||||
import { Image, Text } from 'react-native'
|
||||
|
||||
const regexEmoji = new RegExp(/(:[a-z0-9_]+:)/)
|
||||
@ -44,13 +45,5 @@ export default function Emojis ({ content, emojis, dimension }) {
|
||||
|
||||
Emojis.propTypes = {
|
||||
content: PropTypes.string.isRequired,
|
||||
emojis: PropTypes.arrayOf(
|
||||
PropTypes.exact({
|
||||
shortcode: PropTypes.string.isRequired,
|
||||
url: PropTypes.string.isRequired,
|
||||
static_url: PropTypes.string.isRequired,
|
||||
visible_in_picker: PropTypes.bool.isRequired,
|
||||
category: PropTypes.string
|
||||
})
|
||||
)
|
||||
emojis: PropTypes.arrayOf(propTypesEmoji)
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import propTypesAttachment from 'src/prop-types/attachment'
|
||||
import {
|
||||
Button,
|
||||
Image,
|
||||
@ -131,7 +132,7 @@ const styles = StyleSheet.create({
|
||||
})
|
||||
|
||||
Media.propTypes = {
|
||||
// media_attachments
|
||||
media_attachments: PropTypes.arrayOf(propTypesAttachment),
|
||||
sensitive: PropTypes.bool.isRequired,
|
||||
width: PropTypes.number.isRequired
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import propTypesPoll from 'src/prop-types/poll'
|
||||
import { StyleSheet, Text, View } from 'react-native'
|
||||
|
||||
import Emojis from './Emojis'
|
||||
@ -43,21 +43,5 @@ const styles = StyleSheet.create({
|
||||
})
|
||||
|
||||
Poll.propTypes = {
|
||||
poll: PropTypes.exact({
|
||||
id: PropTypes.string.isRequired,
|
||||
expires_at: PropTypes.string.isRequired,
|
||||
expired: PropTypes.bool.isRequired,
|
||||
multiple: PropTypes.bool.isRequired,
|
||||
votes_count: PropTypes.number,
|
||||
voters_count: PropTypes.number,
|
||||
voted: PropTypes.bool.isRequired,
|
||||
own_votes: PropTypes.array,
|
||||
options: PropTypes.arrayOf(
|
||||
PropTypes.exact({
|
||||
title: PropTypes.string.isRequired,
|
||||
votes_count: PropTypes.number.isRequired
|
||||
})
|
||||
),
|
||||
emojis: Emojis.propTypes.emojis
|
||||
}).isRequired
|
||||
poll: propTypesPoll
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import propTypesEmoji from 'src/prop-types/emoji'
|
||||
import { StyleSheet, Text, View } from 'react-native'
|
||||
import { Feather } from '@expo/vector-icons'
|
||||
|
||||
@ -32,5 +33,5 @@ const styles = StyleSheet.create({
|
||||
|
||||
Reblog.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
emojis: Emojis.propTypes.emojis
|
||||
emojis: PropTypes.arrayOf(propTypesEmoji)
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import propTypesNotification from 'src/prop-types/notification'
|
||||
import { Dimensions, Pressable, StyleSheet, View } from 'react-native'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
|
||||
@ -12,7 +13,7 @@ import Media from './Toot/Media'
|
||||
import Card from './Toot/Card'
|
||||
import Actions from './Toot/Actions'
|
||||
|
||||
export default function Toot ({ toot }) {
|
||||
export default function TootNotification ({ toot }) {
|
||||
const navigation = useNavigation()
|
||||
|
||||
let actualContent
|
||||
@ -107,18 +108,6 @@ const styles = StyleSheet.create({
|
||||
}
|
||||
})
|
||||
|
||||
Toot.propTypes = {
|
||||
toot: PropTypes.shape({
|
||||
account: PropTypes.shape({
|
||||
avatar: PropTypes.string.isRequired,
|
||||
display_name: PropTypes.string.isRequired,
|
||||
acct: PropTypes.string.isRequired
|
||||
}).isRequired,
|
||||
created_at: PropTypes.string.isRequired,
|
||||
application: PropTypes.exact({
|
||||
name: PropTypes.string.isRequired,
|
||||
website: PropTypes.string
|
||||
}),
|
||||
content: PropTypes.string
|
||||
}).isRequired
|
||||
TootNotification.propTypes = {
|
||||
toot: propTypesNotification
|
||||
}
|
112
src/components/TootTimeline.jsx
Normal file
112
src/components/TootTimeline.jsx
Normal file
@ -0,0 +1,112 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import propTypesStatus from 'src/prop-types/status'
|
||||
import { Dimensions, Pressable, StyleSheet, View } from 'react-native'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
|
||||
import Reblog from './Toot/Reblog'
|
||||
import Avatar from './Toot/Avatar'
|
||||
import Header from './Toot/Header'
|
||||
import Content from './Toot/Content'
|
||||
import Poll from './Toot/Poll'
|
||||
import Media from './Toot/Media'
|
||||
import Card from './Toot/Card'
|
||||
import Actions from './Toot/Actions'
|
||||
|
||||
export default function TootTimeline ({ toot }) {
|
||||
const navigation = useNavigation()
|
||||
|
||||
let actualContent
|
||||
if (toot.reblog) {
|
||||
actualContent = toot.reblog
|
||||
} else {
|
||||
actualContent = toot
|
||||
}
|
||||
|
||||
const tootView = useMemo(() => {
|
||||
return (
|
||||
<View style={styles.tootTimeline}>
|
||||
{toot.reblog && (
|
||||
<Reblog
|
||||
name={toot.account.display_name || toot.account.username}
|
||||
emojis={toot.account.emojis}
|
||||
/>
|
||||
)}
|
||||
<View style={styles.toot}>
|
||||
<Avatar
|
||||
uri={actualContent.account.avatar}
|
||||
id={actualContent.account.id}
|
||||
/>
|
||||
<View style={styles.details}>
|
||||
<Header
|
||||
name={
|
||||
actualContent.account.display_name ||
|
||||
actualContent.account.username
|
||||
}
|
||||
emojis={actualContent.account.emojis}
|
||||
account={actualContent.account.acct}
|
||||
created_at={toot.created_at}
|
||||
application={toot.application}
|
||||
/>
|
||||
{/* Can pass toot info to next page to speed up performance */}
|
||||
<Pressable
|
||||
onPress={() =>
|
||||
navigation.navigate('Toot', { toot: actualContent.id })
|
||||
}
|
||||
>
|
||||
{actualContent.content ? (
|
||||
<Content
|
||||
content={actualContent.content}
|
||||
emojis={actualContent.emojis}
|
||||
mentions={actualContent.mentions}
|
||||
spoiler_text={actualContent.spoiler_text}
|
||||
tags={actualContent.tags}
|
||||
style={{ flex: 1 }}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{actualContent.poll && <Poll poll={actualContent.poll} />}
|
||||
{actualContent.media_attachments && (
|
||||
<Media
|
||||
media_attachments={actualContent.media_attachments}
|
||||
sensitive={actualContent.sensitive}
|
||||
width={Dimensions.get('window').width - 24 - 50 - 8}
|
||||
/>
|
||||
)}
|
||||
{actualContent.card && <Card card={actualContent.card} />}
|
||||
</Pressable>
|
||||
<Actions
|
||||
replies_count={actualContent.replies_count}
|
||||
reblogs_count={actualContent.reblogs_count}
|
||||
reblogged={actualContent.reblogged}
|
||||
favourites_count={actualContent.favourites_count}
|
||||
favourited={actualContent.favourited}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
})
|
||||
|
||||
return tootView
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
tootTimeline: {
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
padding: 12
|
||||
},
|
||||
toot: {
|
||||
flex: 1,
|
||||
flexDirection: 'row'
|
||||
},
|
||||
details: {
|
||||
flex: 1,
|
||||
flexGrow: 1
|
||||
}
|
||||
})
|
||||
|
||||
TootTimeline.propTypes = {
|
||||
toot: propTypesStatus
|
||||
}
|
37
src/prop-types/account.js
Normal file
37
src/prop-types/account.js
Normal file
@ -0,0 +1,37 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import propTypesEmoji from './emoji'
|
||||
import propTypesStatus from './status'
|
||||
|
||||
const propTypesAccount = PropTypes.shape({
|
||||
// Base
|
||||
id: PropTypes.string.isRequired,
|
||||
username: PropTypes.string.isRequired,
|
||||
acct: PropTypes.string.isRequired,
|
||||
url: PropTypes.string.isRequired,
|
||||
|
||||
// Attributes
|
||||
display_name: PropTypes.string.isRequired,
|
||||
note: PropTypes.string,
|
||||
avatar: PropTypes.string.isRequired,
|
||||
avatar_static: PropTypes.string.isRequired,
|
||||
header: PropTypes.string.isRequired,
|
||||
header_static: PropTypes.string.isRequired,
|
||||
locked: PropTypes.bool.isRequired,
|
||||
emojis: PropTypes.arrayOf(propTypesEmoji),
|
||||
discoverable: PropTypes.bool.isRequired,
|
||||
|
||||
// Statistics
|
||||
created_at: PropTypes.string.isRequired,
|
||||
last_status_at: PropTypes.string.isRequired,
|
||||
statuses_count: PropTypes.number.isRequired,
|
||||
followers_count: PropTypes.number.isRequired,
|
||||
following_count: PropTypes.number.isRequired,
|
||||
|
||||
// Others
|
||||
moved: propTypesStatus,
|
||||
// fields prop-types
|
||||
bot: PropTypes.bool.isRequired
|
||||
// source prop-types
|
||||
})
|
||||
|
||||
export default propTypesAccount
|
10
src/prop-types/application.js
Normal file
10
src/prop-types/application.js
Normal file
@ -0,0 +1,10 @@
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
const propTypesApplication = PropTypes.shape({
|
||||
// Base
|
||||
name: PropTypes.string.isRequired,
|
||||
website: PropTypes.string,
|
||||
vapid_key: PropTypes.string
|
||||
})
|
||||
|
||||
export default propTypesApplication
|
19
src/prop-types/attachment.js
Normal file
19
src/prop-types/attachment.js
Normal file
@ -0,0 +1,19 @@
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
const propTypesAttachment = PropTypes.shape({
|
||||
// Base
|
||||
id: PropTypes.string.isRequired,
|
||||
type: PropTypes.oneOf(['unknown', 'image', 'gifv', 'video', 'audio'])
|
||||
.isRequired,
|
||||
url: PropTypes.string.isRequired,
|
||||
preview_url: PropTypes.string.isRequired,
|
||||
|
||||
// Others
|
||||
remote_url: PropTypes.string,
|
||||
text_url: PropTypes.string,
|
||||
meta: PropTypes.object,
|
||||
description: PropTypes.string,
|
||||
blurhash: PropTypes.string
|
||||
})
|
||||
|
||||
export default propTypesAttachment
|
23
src/prop-types/card.js
Normal file
23
src/prop-types/card.js
Normal file
@ -0,0 +1,23 @@
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
const propTypesCard = PropTypes.shape({
|
||||
// Base
|
||||
url: PropTypes.string.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
description: PropTypes.string.isRequired,
|
||||
type: PropTypes.oneOf(['link', 'photo', 'video', 'rich']).isRequired,
|
||||
|
||||
// Attributes
|
||||
author_name: PropTypes.string,
|
||||
author_url: PropTypes.string,
|
||||
provider_name: PropTypes.string,
|
||||
provider_url: PropTypes.string,
|
||||
html: PropTypes.string,
|
||||
width: PropTypes.number,
|
||||
height: PropTypes.number,
|
||||
image: PropTypes.string,
|
||||
embed_url: PropTypes.string,
|
||||
blurhash: PropTypes.string
|
||||
})
|
||||
|
||||
export default propTypesCard
|
12
src/prop-types/emoji.js
Normal file
12
src/prop-types/emoji.js
Normal file
@ -0,0 +1,12 @@
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
const propTypesEmoji = PropTypes.shape({
|
||||
// Base
|
||||
shortcode: PropTypes.string.isRequired,
|
||||
url: PropTypes.string.isRequired,
|
||||
static_url: PropTypes.string.isRequired,
|
||||
visible_in_picker: PropTypes.bool.isRequired,
|
||||
category: PropTypes.string
|
||||
})
|
||||
|
||||
export default propTypesEmoji
|
11
src/prop-types/mention.js
Normal file
11
src/prop-types/mention.js
Normal file
@ -0,0 +1,11 @@
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
const propTypesMention = PropTypes.shape({
|
||||
// Base
|
||||
id: PropTypes.string.isRequired,
|
||||
username: PropTypes.string.isRequired,
|
||||
acct: PropTypes.string.isRequired,
|
||||
url: PropTypes.string.isRequired
|
||||
})
|
||||
|
||||
export default propTypesMention
|
17
src/prop-types/notification.js
Normal file
17
src/prop-types/notification.js
Normal file
@ -0,0 +1,17 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import propTypesAccount from './account'
|
||||
import propTypesStatus from './status'
|
||||
|
||||
const propTypesNotification = PropTypes.shape({
|
||||
// Base
|
||||
id: PropTypes.string.isRequired,
|
||||
type: PropTypes.oneOf(['follow', 'mention', 'reblog', 'favourite', 'poll'])
|
||||
.isRequired,
|
||||
created_at: PropTypes.string.isRequired,
|
||||
account: propTypesAccount,
|
||||
|
||||
// Others
|
||||
status: propTypesStatus
|
||||
})
|
||||
|
||||
export default propTypesNotification
|
23
src/prop-types/poll.js
Normal file
23
src/prop-types/poll.js
Normal file
@ -0,0 +1,23 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import propTypesEmoji from './emoji'
|
||||
|
||||
const propTypesPoll = PropTypes.shape({
|
||||
// Base
|
||||
id: PropTypes.string.isRequired,
|
||||
expires_at: PropTypes.string.isRequired,
|
||||
expired: PropTypes.bool.isRequired,
|
||||
multiple: PropTypes.bool.isRequired,
|
||||
votes_count: PropTypes.number.isRequired,
|
||||
voters_count: PropTypes.number.isRequired,
|
||||
voted: PropTypes.bool,
|
||||
own_votes: PropTypes.arrayOf(PropTypes.number),
|
||||
options: PropTypes.arrayOf(
|
||||
PropTypes.exact({
|
||||
title: PropTypes.string.isRequired,
|
||||
votes_count: PropTypes.number.isRequired
|
||||
})
|
||||
).isRequired,
|
||||
emojis: PropTypes.arrayOf(propTypesEmoji)
|
||||
})
|
||||
|
||||
export default propTypesPoll
|
51
src/prop-types/status.js
Normal file
51
src/prop-types/status.js
Normal file
@ -0,0 +1,51 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import propTypesAccount from './account'
|
||||
import propTypesAttachment from './attachment'
|
||||
import propTypesApplication from './application'
|
||||
import propTypesMention from './mention'
|
||||
import propTypesTag from './tag'
|
||||
import propTypesEmoji from './emoji'
|
||||
import propTypesPoll from './poll'
|
||||
import propTypesCard from './card'
|
||||
|
||||
const propTypesStatus = PropTypes.shape({
|
||||
// Base
|
||||
id: PropTypes.string.isRequired,
|
||||
uri: PropTypes.string.isRequired,
|
||||
created_at: PropTypes.string.isRequired,
|
||||
account: propTypesAccount,
|
||||
content: PropTypes.string.isRequired, // Might not be required
|
||||
visibility: PropTypes.oneOf(['public', 'unlisted', 'private', 'direct'])
|
||||
.isRequired,
|
||||
sensitive: PropTypes.bool.isRequired,
|
||||
spoiler_text: PropTypes.string,
|
||||
media_attachments: PropTypes.arrayOf(propTypesAttachment),
|
||||
application: propTypesApplication,
|
||||
|
||||
// Attributes
|
||||
mentions: PropTypes.arrayOf(propTypesMention),
|
||||
tags: PropTypes.arrayOf(propTypesTag),
|
||||
emojis: PropTypes.arrayOf(propTypesEmoji),
|
||||
|
||||
// Interaction
|
||||
reblogs_count: PropTypes.number.isRequired,
|
||||
favourites_count: PropTypes.number.isRequired,
|
||||
replies_count: PropTypes.number.isRequired,
|
||||
favourited: PropTypes.bool,
|
||||
reblogged: PropTypes.bool,
|
||||
muted: PropTypes.bool,
|
||||
bookmarked: PropTypes.bool,
|
||||
pinned: PropTypes.bool,
|
||||
|
||||
// Others
|
||||
url: PropTypes.string,
|
||||
in_reply_to_id: PropTypes.string,
|
||||
in_reply_to_account_id: PropTypes.string,
|
||||
reblog: propTypesStatus,
|
||||
poll: propTypesPoll,
|
||||
card: propTypesCard,
|
||||
language: PropTypes.string,
|
||||
text: PropTypes.string
|
||||
})
|
||||
|
||||
export default propTypesStatus
|
10
src/prop-types/tag.js
Normal file
10
src/prop-types/tag.js
Normal file
@ -0,0 +1,10 @@
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
const propTypesTag = PropTypes.shape({
|
||||
// Base
|
||||
name: PropTypes.string.isRequired,
|
||||
url: PropTypes.string.isRequired
|
||||
// history prop-types
|
||||
})
|
||||
|
||||
export default propTypesTag
|
@ -26,7 +26,7 @@ export default function Notifications () {
|
||||
}}
|
||||
>
|
||||
<Stack.Screen name='Notifications'>
|
||||
{props => <Timeline page='Notifications' {...props} />}
|
||||
{() => <Timeline page='Notifications' />}
|
||||
</Stack.Screen>
|
||||
</Stack.Navigator>
|
||||
)
|
||||
|
@ -3,7 +3,8 @@ import PropTypes from 'prop-types'
|
||||
import { ActivityIndicator, FlatList, Text, View } from 'react-native'
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
|
||||
import Toot from 'src/components/Toot'
|
||||
import TootNotification from 'src/components/TootNotification'
|
||||
import TootTimeline from 'src/components/TootTimeline'
|
||||
import { fetch } from './timelineSlice'
|
||||
|
||||
// Opening nesting hashtag pages
|
||||
@ -37,9 +38,13 @@ export default function Timeline ({
|
||||
style={{ minHeight: '100%' }}
|
||||
data={state.toots}
|
||||
keyExtractor={({ id }) => id}
|
||||
renderItem={({ item, index, separators }) => (
|
||||
<Toot key={item.key} toot={item} />
|
||||
)}
|
||||
renderItem={({ item, index, separators }) =>
|
||||
page === 'Notifications' ? (
|
||||
<TootNotification key={item.key} toot={item} />
|
||||
) : (
|
||||
<TootTimeline key={item.key} toot={item} />
|
||||
)
|
||||
}
|
||||
{...(state.pointer && { initialScrollIndex: state.pointer })}
|
||||
{...(!disableRefresh && {
|
||||
onRefresh: () =>
|
||||
|
Loading…
x
Reference in New Issue
Block a user