mirror of
https://github.com/tooot-app/app
synced 2025-02-27 00:57:41 +01:00
Working emojis in reblog and names
This commit is contained in:
parent
2bc6e3277c
commit
996cf0c1e7
@ -3,6 +3,7 @@ module.exports = function (api) {
|
||||
return {
|
||||
presets: ['babel-preset-expo'],
|
||||
plugins: [
|
||||
['@babel/plugin-proposal-optional-chaining'],
|
||||
[
|
||||
'module-resolver',
|
||||
{
|
||||
|
@ -34,6 +34,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "~7.9.0",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.12.1",
|
||||
"babel-plugin-module-resolver": "^4.0.0"
|
||||
},
|
||||
"private": true
|
||||
|
@ -1,52 +1,60 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import { Image, StyleSheet, Text, View } from 'react-native'
|
||||
import HTML from 'react-native-render-html'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
|
||||
import relativeTime from 'src/utils/relativeTime'
|
||||
import Reblog from './TootTimeline/Reblog'
|
||||
import Avatar from './TootTimeline/Avatar'
|
||||
import Header from './TootTimeline/Header'
|
||||
import Content from './TootTimeline/Content'
|
||||
import Actions from './TootTimeline/Actions'
|
||||
|
||||
export default function TootTimeline ({ item, notification }) {
|
||||
return (
|
||||
<View style={styles.tootTimeline}>
|
||||
<View style={styles.header}>
|
||||
<Image
|
||||
source={{
|
||||
uri: item.reblog ? item.reblog.account.avatar : item.account.avatar
|
||||
}}
|
||||
style={styles.avatar}
|
||||
{item.reblog && (
|
||||
<Reblog
|
||||
name={item.account.display_name || item.account.username}
|
||||
emojis={item.account.emojis}
|
||||
/>
|
||||
<View>
|
||||
<View style={styles.name}>
|
||||
<Text>
|
||||
{item.reblog
|
||||
? item.reblog.account.display_name
|
||||
: item.account.display_name}
|
||||
</Text>
|
||||
<Text>
|
||||
{item.reblog ? item.reblog.account.acct : item.account.acct}
|
||||
</Text>
|
||||
</View>
|
||||
<View>
|
||||
<Text>{relativeTime(item.created_at)}</Text>
|
||||
{item.application && item.application.name !== 'Web' && (
|
||||
<Text onPress={() => Linking.openURL(item.application.website)}>
|
||||
{item.application.name}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
<View style={styles.toot}>
|
||||
<Avatar uri={item.reblog?.account.avatar || item.account.avatar} />
|
||||
<View style={{flexGrow: 1}}>
|
||||
<Header
|
||||
name={
|
||||
(item.reblog?.account.display_name
|
||||
? item.reblog?.account.display_name
|
||||
: item.reblog?.account.username) ||
|
||||
(item.account.display_name
|
||||
? item.account.display_name
|
||||
: item.account.username)
|
||||
}
|
||||
emojis={item.reblog?.account.emojis || item.account.emojis}
|
||||
account={item.reblog?.account.acct || item.account.acct}
|
||||
created_at={item.created_at}
|
||||
application={item.application || null}
|
||||
/>
|
||||
<Content
|
||||
content={notification ? item.status.content : item.content}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
{notification ? (
|
||||
<HTML html={item.status.content} />
|
||||
) : item.content ? (
|
||||
<HTML html={item.content} />
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<Actions />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
tootTimeline: {
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
padding: 12
|
||||
},
|
||||
toot: {
|
||||
flexDirection: 'row'
|
||||
}
|
||||
})
|
||||
|
||||
TootTimeline.propTypes = {
|
||||
item: PropTypes.shape({
|
||||
account: PropTypes.shape({
|
||||
@ -63,20 +71,3 @@ TootTimeline.propTypes = {
|
||||
}).isRequired,
|
||||
notification: PropTypes.bool
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
tootTimeline: {
|
||||
flex: 1,
|
||||
padding: 15
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
avatar: {
|
||||
width: 40,
|
||||
height: 40
|
||||
},
|
||||
name: {
|
||||
flexDirection: 'row'
|
||||
}
|
||||
})
|
||||
|
16
src/components/TootTimeline/Actions.jsx
Normal file
16
src/components/TootTimeline/Actions.jsx
Normal file
@ -0,0 +1,16 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { StyleSheet } from 'react-native'
|
||||
|
||||
export default function Actions () {
|
||||
return <></>
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
width: 50,
|
||||
height: 50
|
||||
})
|
||||
|
||||
// Actions.propTypes = {
|
||||
// uri: PropTypes.string
|
||||
// }
|
19
src/components/TootTimeline/Avatar.jsx
Normal file
19
src/components/TootTimeline/Avatar.jsx
Normal file
@ -0,0 +1,19 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Image, StyleSheet } from 'react-native'
|
||||
|
||||
export default function Avatar ({ uri }) {
|
||||
return <Image source={{ uri: uri }} style={styles.avatar} />
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
avatar: {
|
||||
width: 50,
|
||||
height: 50,
|
||||
marginRight: 8
|
||||
}
|
||||
})
|
||||
|
||||
Avatar.propTypes = {
|
||||
uri: PropTypes.string.isRequired
|
||||
}
|
31
src/components/TootTimeline/Content.jsx
Normal file
31
src/components/TootTimeline/Content.jsx
Normal file
@ -0,0 +1,31 @@
|
||||
import React, { useState } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Dimensions, StyleSheet, View } from 'react-native'
|
||||
import HTML from 'react-native-render-html'
|
||||
|
||||
// !! Need to solve dimension issue
|
||||
|
||||
export default function Content ({ content }) {
|
||||
const [viewWidth, setViewWidth] = useState()
|
||||
return (
|
||||
content && (
|
||||
<View
|
||||
style={{ width: '100%' }}
|
||||
onLayout={e => setViewWidth(e.nativeEvent.layout.width)}
|
||||
>
|
||||
{viewWidth && (
|
||||
<HTML html={content} containerStyle={{ width: viewWidth }} />
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
width: 50,
|
||||
height: 50
|
||||
})
|
||||
|
||||
Content.propTypes = {
|
||||
content: PropTypes.string
|
||||
}
|
53
src/components/TootTimeline/Emojis.jsx
Normal file
53
src/components/TootTimeline/Emojis.jsx
Normal file
@ -0,0 +1,53 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Image, Text } from 'react-native'
|
||||
|
||||
const regexEmoji = new RegExp(/(:[a-z0-9_]+:)/g)
|
||||
const regexEmojiSelect = new RegExp(/:([a-z0-9_]+):/)
|
||||
|
||||
export default function Emojis ({ content, emojis, dimension }) {
|
||||
const hasEmojis = content.match(regexEmoji)
|
||||
return hasEmojis ? (
|
||||
content.split(regexEmoji).map((str, i) => {
|
||||
if (str.match(regexEmoji)) {
|
||||
const emojiShortcode = str.split(regexEmojiSelect)[1]
|
||||
const emojiIndex = emojis.findIndex(emoji => {
|
||||
return emoji.shortcode === emojiShortcode
|
||||
})
|
||||
return (
|
||||
<Image
|
||||
key={i}
|
||||
source={{ uri: emojis[emojiIndex].url }}
|
||||
style={{ width: dimension, height: dimension }}
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Text
|
||||
key={i}
|
||||
style={{ fontSize: dimension, lineHeight: dimension + 1 }}
|
||||
>
|
||||
{str}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
})
|
||||
) : (
|
||||
<Text style={{ fontSize: dimension, lineHeight: dimension + 1 }}>
|
||||
{content}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
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
|
||||
})
|
||||
)
|
||||
}
|
86
src/components/TootTimeline/Header.jsx
Normal file
86
src/components/TootTimeline/Header.jsx
Normal file
@ -0,0 +1,86 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { StyleSheet, Text, View } from 'react-native'
|
||||
|
||||
import Emojis from './Emojis'
|
||||
import relativeTime from 'src/utils/relativeTime'
|
||||
|
||||
export default function Header ({
|
||||
name,
|
||||
emojis,
|
||||
account,
|
||||
created_at,
|
||||
application
|
||||
}) {
|
||||
const [since, setSince] = useState(relativeTime(created_at))
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setSince(relativeTime(created_at))
|
||||
}, 1000)
|
||||
})
|
||||
|
||||
return (
|
||||
<View>
|
||||
<View style={styles.names}>
|
||||
<View style={styles.name}>
|
||||
<Emojis content={name} emojis={emojis} dimension={14} />
|
||||
</View>
|
||||
<Text style={styles.account}>@{account}</Text>
|
||||
</View>
|
||||
<View style={styles.meta}>
|
||||
<View>
|
||||
<Text style={styles.created_at}>{since}</Text>
|
||||
</View>
|
||||
{application && application.name !== 'Web' && (
|
||||
<View>
|
||||
<Text
|
||||
onPress={() => Linking.openURL(application.website)}
|
||||
style={styles.application}
|
||||
>
|
||||
{application.name}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
names: {
|
||||
flexDirection: 'row',
|
||||
marginBottom: 8
|
||||
},
|
||||
name: {
|
||||
flexDirection: 'row',
|
||||
marginRight: 8
|
||||
},
|
||||
account: {
|
||||
fontSize: 12,
|
||||
lineHeight: 14
|
||||
},
|
||||
meta: {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
created_at: {
|
||||
fontSize: 12,
|
||||
lineHeight: 12,
|
||||
marginRight: 8
|
||||
},
|
||||
application: {
|
||||
fontSize: 12,
|
||||
lineHeight: 11
|
||||
}
|
||||
})
|
||||
|
||||
Header.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
emojis: Emojis.propTypes.emojis,
|
||||
account: PropTypes.string.isRequired,
|
||||
created_at: PropTypes.string.isRequired,
|
||||
application: PropTypes.exact({
|
||||
name: PropTypes.string.isRequired,
|
||||
website: PropTypes.string
|
||||
})
|
||||
}
|
36
src/components/TootTimeline/Reblog.jsx
Normal file
36
src/components/TootTimeline/Reblog.jsx
Normal file
@ -0,0 +1,36 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { StyleSheet, Text, View } from 'react-native'
|
||||
import { Feather } from '@expo/vector-icons'
|
||||
|
||||
import Emojis from './Emojis'
|
||||
|
||||
export default function Reblog ({ name, emojis }) {
|
||||
return (
|
||||
<View style={styles.reblog}>
|
||||
<Feather name='repeat' size={12} color='black' style={styles.icon} />
|
||||
<View style={styles.name}>
|
||||
<Emojis content={name} emojis={emojis} dimension={12} />
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
reblog: {
|
||||
flexDirection: 'row',
|
||||
marginBottom: 8
|
||||
},
|
||||
icon: {
|
||||
marginLeft: 50 - 12,
|
||||
marginRight: 8
|
||||
},
|
||||
name: {
|
||||
flexDirection: 'row'
|
||||
}
|
||||
})
|
||||
|
||||
Reblog.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
emojis: Emojis.propTypes.emojis
|
||||
}
|
@ -21,7 +21,6 @@ const Default = ({ dispatch, toots, status, timeline }) => {
|
||||
dispatch(fetch({ ...timeline, id: toots[toots.length - 1].id }))
|
||||
}
|
||||
onEndReachedThreshold={0.5}
|
||||
style={{ height: '100%', width: '100%' }}
|
||||
/>
|
||||
{status === 'loading' && <ActivityIndicator />}
|
||||
</>
|
||||
@ -42,12 +41,9 @@ const Notifications = ({ dispatch, toots, status, timeline }) => {
|
||||
}
|
||||
refreshing={status === 'loading'}
|
||||
onEndReached={() =>
|
||||
dispatch(
|
||||
fetch({ ...timeline, id: toots[toots.length - 1].id })
|
||||
)
|
||||
dispatch(fetch({ ...timeline, id: toots[toots.length - 1].id }))
|
||||
}
|
||||
onEndReachedThreshold={0.5}
|
||||
style={{ height: '100%', width: '100%' }}
|
||||
/>
|
||||
{status === 'loading' && <ActivityIndicator />}
|
||||
</>
|
||||
|
@ -6,8 +6,8 @@ import timelineSlice from 'src/stacks/common/timelineSlice'
|
||||
// get site information from local storage and pass to reducers
|
||||
const preloadedState = {
|
||||
instanceInfo: {
|
||||
current: 'm.cmx.im',
|
||||
currentToken: 'Cxx19XX2VNHnPy_dr_HCHMh4HvwHEvYwWrrU3r3BNzQ',
|
||||
current: 'social.xmflsct.com',
|
||||
currentToken: 'qjzJ0IjvZ1apsn0_wBkGcdjKgX7Dao9KEPhGwggPwAo',
|
||||
remote: 'mastodon.social'
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user