2020-12-04 01:17:10 +01:00
|
|
|
import ImagePicker from 'expo-image-picker'
|
|
|
|
import { forEach, groupBy, sortBy } from 'lodash'
|
|
|
|
import React, { Dispatch, useEffect, useMemo, useRef } from 'react'
|
2020-11-15 20:29:43 +01:00
|
|
|
import {
|
2020-12-04 01:17:10 +01:00
|
|
|
View,
|
|
|
|
ActivityIndicator,
|
|
|
|
FlatList,
|
2020-11-15 20:29:43 +01:00
|
|
|
Pressable,
|
2020-12-06 12:52:29 +01:00
|
|
|
ProgressViewIOS,
|
2020-11-15 20:29:43 +01:00
|
|
|
StyleSheet,
|
|
|
|
Text,
|
|
|
|
TextInput,
|
2020-12-04 01:17:10 +01:00
|
|
|
Image
|
2020-11-15 20:29:43 +01:00
|
|
|
} from 'react-native'
|
2020-11-17 23:57:23 +01:00
|
|
|
import { useQuery } from 'react-query'
|
2020-12-04 01:17:10 +01:00
|
|
|
import Emojis from 'src/components/Timelines/Timeline/Shared/Emojis'
|
2020-11-21 13:19:05 +01:00
|
|
|
import { emojisFetch } from 'src/utils/fetches/emojisFetch'
|
2020-12-04 01:17:10 +01:00
|
|
|
import { searchFetch } from 'src/utils/fetches/searchFetch'
|
2020-12-03 22:03:06 +01:00
|
|
|
import { StyleConstants } from 'src/utils/styles/constants'
|
2020-12-04 01:17:10 +01:00
|
|
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
|
|
|
import { PostAction, PostState } from '../Compose'
|
2020-12-03 22:03:06 +01:00
|
|
|
import ComposeActions from './Actions'
|
2020-12-04 01:17:10 +01:00
|
|
|
import ComposeAttachments from './Attachments'
|
|
|
|
import ComposeEmojis from './Emojis'
|
|
|
|
import ComposePoll from './Poll'
|
|
|
|
import ComposeTextInput from './TextInput'
|
|
|
|
import updateText from './updateText'
|
2020-11-15 20:29:43 +01:00
|
|
|
|
2020-11-15 22:33:09 +01:00
|
|
|
export interface Props {
|
|
|
|
postState: PostState
|
|
|
|
postDispatch: Dispatch<PostAction>
|
2020-11-15 20:29:43 +01:00
|
|
|
}
|
|
|
|
|
2020-12-03 22:03:06 +01:00
|
|
|
const ComposeRoot: React.FC<Props> = ({ postState, postDispatch }) => {
|
|
|
|
const { theme } = useTheme()
|
2020-12-04 01:17:10 +01:00
|
|
|
|
|
|
|
const { isFetching, isSuccess, data, refetch } = useQuery(
|
|
|
|
[
|
|
|
|
'Search',
|
|
|
|
{ type: postState.tag?.type, term: postState.tag?.text.substring(1) }
|
|
|
|
],
|
|
|
|
searchFetch,
|
|
|
|
{ enabled: false }
|
|
|
|
)
|
|
|
|
useEffect(() => {
|
2020-12-04 19:04:23 +01:00
|
|
|
if (postState.tag?.text) {
|
|
|
|
refetch()
|
|
|
|
}
|
2020-12-04 01:17:10 +01:00
|
|
|
}, [postState.tag?.text])
|
|
|
|
|
2020-11-19 22:45:26 +01:00
|
|
|
useEffect(() => {
|
|
|
|
;(async () => {
|
|
|
|
const { status } = await ImagePicker.requestCameraRollPermissionsAsync()
|
|
|
|
if (status !== 'granted') {
|
|
|
|
alert('Sorry, we need camera roll permissions to make this work!')
|
|
|
|
}
|
|
|
|
})()
|
|
|
|
}, [])
|
|
|
|
|
2020-11-15 20:29:43 +01:00
|
|
|
const { data: emojisData } = useQuery(['Emojis'], emojisFetch)
|
|
|
|
useEffect(() => {
|
|
|
|
if (emojisData && emojisData.length) {
|
2020-12-04 01:17:10 +01:00
|
|
|
let sortedEmojis: { title: string; data: Mastodon.Emoji[] }[] = []
|
|
|
|
forEach(
|
|
|
|
groupBy(sortBy(emojisData, ['category', 'shortcode']), 'category'),
|
|
|
|
(value, key) => sortedEmojis.push({ title: key, data: value })
|
|
|
|
)
|
|
|
|
postDispatch({
|
|
|
|
type: 'emoji',
|
|
|
|
payload: { ...postState.emoji, emojis: sortedEmojis }
|
|
|
|
})
|
2020-11-15 20:29:43 +01:00
|
|
|
}
|
|
|
|
}, [emojisData])
|
|
|
|
|
2020-12-03 22:03:06 +01:00
|
|
|
const textInputRef = useRef<TextInput>(null)
|
|
|
|
|
2020-12-05 01:55:53 +01:00
|
|
|
const listFooter = () => {
|
2020-12-04 01:17:10 +01:00
|
|
|
return (
|
|
|
|
<>
|
|
|
|
{postState.emoji.active && (
|
2020-12-03 22:03:06 +01:00
|
|
|
<View style={styles.emojis}>
|
|
|
|
<ComposeEmojis
|
|
|
|
textInputRef={textInputRef}
|
|
|
|
postState={postState}
|
|
|
|
postDispatch={postDispatch}
|
|
|
|
/>
|
|
|
|
</View>
|
2020-12-04 01:17:10 +01:00
|
|
|
)}
|
2020-12-03 22:03:06 +01:00
|
|
|
|
2020-12-05 01:55:53 +01:00
|
|
|
{(postState.attachments.length > 0 ||
|
|
|
|
postState.attachmentUploadProgress) && (
|
2020-11-20 01:41:46 +01:00
|
|
|
<View style={styles.attachments}>
|
2020-12-03 22:03:06 +01:00
|
|
|
<ComposeAttachments
|
2020-11-20 01:41:46 +01:00
|
|
|
postState={postState}
|
|
|
|
postDispatch={postDispatch}
|
|
|
|
/>
|
|
|
|
</View>
|
|
|
|
)}
|
|
|
|
{postState.poll.active && (
|
|
|
|
<View style={styles.poll}>
|
2020-12-03 22:03:06 +01:00
|
|
|
<ComposePoll postState={postState} postDispatch={postDispatch} />
|
2020-11-20 01:41:46 +01:00
|
|
|
</View>
|
|
|
|
)}
|
2020-12-04 01:17:10 +01:00
|
|
|
</>
|
|
|
|
)
|
2020-12-05 01:55:53 +01:00
|
|
|
}
|
2020-12-04 01:17:10 +01:00
|
|
|
|
|
|
|
const listEmpty = useMemo(() => {
|
|
|
|
if (isFetching) {
|
|
|
|
return <ActivityIndicator />
|
|
|
|
}
|
|
|
|
}, [isFetching])
|
|
|
|
|
|
|
|
return (
|
|
|
|
<View style={styles.base}>
|
2020-12-06 12:52:29 +01:00
|
|
|
<ProgressViewIOS
|
|
|
|
progress={postState.attachmentUploadProgress?.progress || 0}
|
|
|
|
progressViewStyle='bar'
|
|
|
|
/>
|
2020-12-04 01:17:10 +01:00
|
|
|
<FlatList
|
|
|
|
ListHeaderComponent={
|
|
|
|
<ComposeTextInput
|
|
|
|
postState={postState}
|
|
|
|
postDispatch={postDispatch}
|
|
|
|
textInputRef={textInputRef}
|
|
|
|
/>
|
|
|
|
}
|
|
|
|
ListFooterComponent={listFooter}
|
|
|
|
ListEmptyComponent={listEmpty}
|
|
|
|
data={postState.tag && isSuccess ? data[postState.tag.type] : []}
|
|
|
|
renderItem={({ item, index }) => (
|
|
|
|
<Pressable
|
|
|
|
key={index}
|
|
|
|
onPress={() => {
|
|
|
|
updateText({
|
|
|
|
postState: {
|
|
|
|
...postState,
|
|
|
|
selection: {
|
|
|
|
start: postState.tag!.offset,
|
|
|
|
end: postState.tag!.offset + postState.tag!.text.length + 1
|
|
|
|
}
|
|
|
|
},
|
|
|
|
postDispatch,
|
|
|
|
newText: item.acct ? `@${item.acct}` : `#${item.name}`,
|
|
|
|
type: 'suggestion'
|
|
|
|
})
|
|
|
|
textInputRef.current?.focus()
|
|
|
|
}}
|
|
|
|
style={styles.suggestion}
|
|
|
|
>
|
|
|
|
{item.acct ? (
|
|
|
|
<View
|
|
|
|
style={[
|
|
|
|
styles.account,
|
|
|
|
{ borderBottomColor: theme.border },
|
|
|
|
index === 0 && {
|
|
|
|
borderTopWidth: StyleSheet.hairlineWidth,
|
|
|
|
borderTopColor: theme.border
|
|
|
|
}
|
|
|
|
]}
|
|
|
|
>
|
|
|
|
<Image
|
|
|
|
source={{ uri: item.avatar }}
|
|
|
|
style={styles.accountAvatar}
|
|
|
|
/>
|
|
|
|
<View>
|
|
|
|
<Text style={[styles.accountName, { color: theme.primary }]}>
|
|
|
|
{item.emojis.length ? (
|
|
|
|
<Emojis
|
|
|
|
content={item.display_name || item.username}
|
|
|
|
emojis={item.emojis}
|
|
|
|
size={StyleConstants.Font.Size.S}
|
|
|
|
/>
|
|
|
|
) : (
|
|
|
|
item.display_name || item.username
|
|
|
|
)}
|
|
|
|
</Text>
|
|
|
|
<Text
|
|
|
|
style={[styles.accountAccount, { color: theme.primary }]}
|
|
|
|
>
|
|
|
|
@{item.acct}
|
|
|
|
</Text>
|
|
|
|
</View>
|
|
|
|
</View>
|
|
|
|
) : (
|
|
|
|
<View
|
|
|
|
style={[
|
|
|
|
styles.hashtag,
|
|
|
|
{ borderBottomColor: theme.border },
|
|
|
|
index === 0 && {
|
|
|
|
borderTopWidth: StyleSheet.hairlineWidth,
|
|
|
|
borderTopColor: theme.border
|
|
|
|
}
|
|
|
|
]}
|
|
|
|
>
|
|
|
|
<Text style={[styles.hashtagText, { color: theme.primary }]}>
|
|
|
|
#{item.name}
|
|
|
|
</Text>
|
|
|
|
</View>
|
|
|
|
)}
|
|
|
|
</Pressable>
|
|
|
|
)}
|
|
|
|
/>
|
2020-12-03 22:03:06 +01:00
|
|
|
<ComposeActions
|
|
|
|
textInputRef={textInputRef}
|
|
|
|
postState={postState}
|
|
|
|
postDispatch={postDispatch}
|
|
|
|
/>
|
2020-11-15 23:33:01 +01:00
|
|
|
</View>
|
2020-11-15 20:29:43 +01:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
const styles = StyleSheet.create({
|
2020-11-20 01:41:46 +01:00
|
|
|
base: {
|
2020-11-15 20:29:43 +01:00
|
|
|
flex: 1
|
|
|
|
},
|
2020-12-03 22:03:06 +01:00
|
|
|
contentView: { flex: 1 },
|
2020-12-04 01:17:10 +01:00
|
|
|
|
2020-11-19 22:45:26 +01:00
|
|
|
attachments: {
|
2020-12-05 01:55:53 +01:00
|
|
|
flex: 1
|
2020-11-19 22:45:26 +01:00
|
|
|
},
|
2020-11-17 23:57:23 +01:00
|
|
|
poll: {
|
2020-12-03 22:03:06 +01:00
|
|
|
flex: 1,
|
|
|
|
padding: StyleConstants.Spacing.Global.PagePadding
|
2020-11-17 23:57:23 +01:00
|
|
|
},
|
2020-12-04 01:17:10 +01:00
|
|
|
suggestion: {
|
|
|
|
flex: 1
|
|
|
|
},
|
|
|
|
account: {
|
|
|
|
flex: 1,
|
|
|
|
flexDirection: 'row',
|
|
|
|
alignItems: 'center',
|
|
|
|
paddingTop: StyleConstants.Spacing.S,
|
|
|
|
paddingBottom: StyleConstants.Spacing.S,
|
|
|
|
paddingLeft: StyleConstants.Spacing.Global.PagePadding,
|
|
|
|
paddingRight: StyleConstants.Spacing.Global.PagePadding,
|
|
|
|
borderBottomWidth: StyleSheet.hairlineWidth
|
|
|
|
},
|
|
|
|
accountAvatar: {
|
|
|
|
width: StyleConstants.Font.LineHeight.M * 2,
|
|
|
|
height: StyleConstants.Font.LineHeight.M * 2,
|
|
|
|
marginRight: StyleConstants.Spacing.S,
|
|
|
|
borderRadius: StyleConstants.Avatar.S
|
|
|
|
},
|
|
|
|
accountName: {
|
|
|
|
fontSize: StyleConstants.Font.Size.S,
|
|
|
|
fontWeight: StyleConstants.Font.Weight.Bold,
|
|
|
|
marginBottom: StyleConstants.Spacing.XS
|
|
|
|
},
|
|
|
|
accountAccount: {
|
|
|
|
fontSize: StyleConstants.Font.Size.S
|
|
|
|
},
|
|
|
|
hashtag: {
|
2020-11-15 20:29:43 +01:00
|
|
|
flex: 1,
|
2020-12-04 01:17:10 +01:00
|
|
|
paddingTop: StyleConstants.Spacing.S,
|
|
|
|
paddingBottom: StyleConstants.Spacing.S,
|
|
|
|
paddingLeft: StyleConstants.Spacing.Global.PagePadding,
|
|
|
|
paddingRight: StyleConstants.Spacing.Global.PagePadding,
|
|
|
|
borderBottomWidth: StyleSheet.hairlineWidth
|
|
|
|
},
|
|
|
|
hashtagText: {
|
|
|
|
fontSize: StyleConstants.Font.Size.S,
|
|
|
|
fontWeight: StyleConstants.Font.Weight.Bold,
|
|
|
|
marginBottom: StyleConstants.Spacing.XS
|
2020-11-15 20:29:43 +01:00
|
|
|
},
|
|
|
|
emojis: {
|
2020-12-03 22:03:06 +01:00
|
|
|
flex: 1
|
2020-11-15 20:29:43 +01:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2020-12-03 22:03:06 +01:00
|
|
|
export default ComposeRoot
|