diff --git a/babel.config.js b/babel.config.js index 5cc1c280..e5e6c445 100644 --- a/babel.config.js +++ b/babel.config.js @@ -3,6 +3,7 @@ module.exports = function (api) { return { presets: ['babel-preset-expo'], plugins: [ + ['@babel/plugin-proposal-optional-chaining'], [ 'module-resolver', { diff --git a/package.json b/package.json index ddc58f10..48215951 100644 --- a/package.json +++ b/package.json @@ -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 diff --git a/src/components/TootTimeline.jsx b/src/components/TootTimeline.jsx index 7a1db132..e909aade 100644 --- a/src/components/TootTimeline.jsx +++ b/src/components/TootTimeline.jsx @@ -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 ( - - - - - - {item.reblog - ? item.reblog.account.display_name - : item.account.display_name} - - - {item.reblog ? item.reblog.account.acct : item.account.acct} - - - - {relativeTime(item.created_at)} - {item.application && item.application.name !== 'Web' && ( - Linking.openURL(item.application.website)}> - {item.application.name} - - )} - + )} + + + +
+ - {notification ? ( - - ) : item.content ? ( - - ) : ( - <> - )} + ) } +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' - } -}) diff --git a/src/components/TootTimeline/Actions.jsx b/src/components/TootTimeline/Actions.jsx new file mode 100644 index 00000000..8d74b58c --- /dev/null +++ b/src/components/TootTimeline/Actions.jsx @@ -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 +// } diff --git a/src/components/TootTimeline/Avatar.jsx b/src/components/TootTimeline/Avatar.jsx new file mode 100644 index 00000000..5194e2d7 --- /dev/null +++ b/src/components/TootTimeline/Avatar.jsx @@ -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 +} + +const styles = StyleSheet.create({ + avatar: { + width: 50, + height: 50, + marginRight: 8 + } +}) + +Avatar.propTypes = { + uri: PropTypes.string.isRequired +} diff --git a/src/components/TootTimeline/Content.jsx b/src/components/TootTimeline/Content.jsx new file mode 100644 index 00000000..b88456d2 --- /dev/null +++ b/src/components/TootTimeline/Content.jsx @@ -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 && ( + setViewWidth(e.nativeEvent.layout.width)} + > + {viewWidth && ( + + )} + + ) + ) +} + +const styles = StyleSheet.create({ + width: 50, + height: 50 +}) + +Content.propTypes = { + content: PropTypes.string +} diff --git a/src/components/TootTimeline/Emojis.jsx b/src/components/TootTimeline/Emojis.jsx new file mode 100644 index 00000000..ea8877bb --- /dev/null +++ b/src/components/TootTimeline/Emojis.jsx @@ -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 ( + + ) + } else { + return ( + + {str} + + ) + } + }) + ) : ( + + {content} + + ) +} + +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 + }) + ) +} diff --git a/src/components/TootTimeline/Header.jsx b/src/components/TootTimeline/Header.jsx new file mode 100644 index 00000000..3acafd12 --- /dev/null +++ b/src/components/TootTimeline/Header.jsx @@ -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 ( + + + + + + @{account} + + + + {since} + + {application && application.name !== 'Web' && ( + + Linking.openURL(application.website)} + style={styles.application} + > + {application.name} + + + )} + + + ) +} + +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 + }) +} diff --git a/src/components/TootTimeline/Reblog.jsx b/src/components/TootTimeline/Reblog.jsx new file mode 100644 index 00000000..7f28cc0f --- /dev/null +++ b/src/components/TootTimeline/Reblog.jsx @@ -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 ( + + + + + + + ) +} + +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 +} diff --git a/src/stacks/common/Timeline.jsx b/src/stacks/common/Timeline.jsx index 20235b6f..ada66285 100644 --- a/src/stacks/common/Timeline.jsx +++ b/src/stacks/common/Timeline.jsx @@ -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' && } @@ -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' && } diff --git a/src/stacks/common/store.js b/src/stacks/common/store.js index 4e4852e5..8a5b086a 100644 --- a/src/stacks/common/store.js +++ b/src/stacks/common/store.js @@ -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' } }