upload images in composer v1

This commit is contained in:
João Ferreiro 2022-11-28 16:46:58 +00:00
parent f5ff0fd274
commit 5ea750599d
10 changed files with 283 additions and 33 deletions

View file

@ -0,0 +1,25 @@
import {PhotoIdentifier} from './../../../node_modules/@react-native-camera-roll/camera-roll/src/CameraRoll'
import {makeAutoObservable} from 'mobx'
import {CameraRoll} from '@react-native-camera-roll/camera-roll'
import {RootStoreModel} from './root-store'
export class UserLocalPhotosModel {
// state
photos: PhotoIdentifier[] = []
constructor(public rootStore: RootStoreModel) {
makeAutoObservable(this, {
rootStore: false,
})
}
async setup() {
await this._getPhotos()
}
private async _getPhotos() {
CameraRoll.getPhotos({first: 20}).then(r => {
this.photos = r.edges
})
}
}

View file

@ -9,10 +9,13 @@ import {
TextInput,
TouchableOpacity,
View,
ScrollView,
Image,
} from 'react-native'
import LinearGradient from 'react-native-linear-gradient'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {UserAutocompleteViewModel} from '../../../state/models/user-autocomplete-view'
import {UserLocalPhotosModel} from '../../../state/models/user-local-photos'
import {Autocomplete} from './Autocomplete'
import Toast from '../util/Toast'
import ProgressCircle from '../util/ProgressCircle'
@ -22,6 +25,7 @@ import * as apilib from '../../../state/lib/api'
import {ComposerOpts} from '../../../state/models/shell-ui'
import {s, colors, gradients} from '../../lib/styles'
import {detectLinkables} from '../../../lib/strings'
import {openPicker, openCamera} from 'react-native-image-crop-picker'
const MAX_TEXT_LENGTH = 256
const WARNING_TEXT_LENGTH = 200
@ -40,15 +44,24 @@ export const ComposePost = observer(function ComposePost({
const [isProcessing, setIsProcessing] = useState(false)
const [error, setError] = useState('')
const [text, setText] = useState('')
const [photoUris, setPhotoUris] = useState<string[]>([])
const autocompleteView = useMemo<UserAutocompleteViewModel>(
() => new UserAutocompleteViewModel(store),
[],
)
const localPhotos = useMemo<UserLocalPhotosModel>(
() => new UserLocalPhotosModel(store),
[],
)
useEffect(() => {
autocompleteView.setup()
})
useEffect(() => {
localPhotos.setup()
}, [])
const onChangeText = (newText: string) => {
setText(newText)
@ -183,12 +196,109 @@ export const ComposePost = observer(function ComposePost({
multiline
scrollEnabled
onChangeText={(text: string) => onChangeText(text)}
placeholder={replyTo ? 'Write your reply' : "What's up?"}
placeholder={
replyTo
? 'Write your reply'
: photoUris.length === 0
? "What's up?"
: 'Add a comment...'
}
style={styles.textInput}>
{textDecorated}
</TextInput>
<View
style={[s.flexRow, {alignItems: 'center'}, s.pt10, s.pb10, s.pr5]}>
{photoUris.length !== 0 && (
<View style={styles.selectedImageContainer}>
{photoUris.length !== 0 &&
photoUris.map(item => (
<View
style={[
styles.selectedImage,
photoUris.length === 1
? styles.selectedImage250
: photoUris.length === 2
? styles.selectedImage175
: styles.selectedImage85,
]}>
<TouchableOpacity
onPress={() => {
setPhotoUris(
photoUris.filter(filterItem => filterItem !== item),
)
}}
style={styles.removePhotoButton}>
<FontAwesomeIcon
icon="xmark"
size={16}
style={{color: colors.white}}
/>
</TouchableOpacity>
<Image
style={[
styles.selectedImage,
photoUris.length === 1
? styles.selectedImage250
: photoUris.length === 2
? styles.selectedImage175
: styles.selectedImage85,
]}
source={{uri: item}}
/>
</View>
))}
</View>
)}
{localPhotos.photos != null && text === '' && photoUris.length === 0 && (
<ScrollView
horizontal
style={styles.photosContainer}
showsHorizontalScrollIndicator={false}>
<TouchableOpacity
style={[styles.galleryButton, styles.photo]}
onPress={() => {
openCamera({multiple: true, maxFiles: 4}).then()
}}>
<FontAwesomeIcon
icon="camera"
size={24}
style={{color: colors.blue3}}
/>
</TouchableOpacity>
{localPhotos.photos.map(item => (
<TouchableOpacity
style={styles.photoButton}
onPress={() => {
setPhotoUris([item.node.image.uri, ...photoUris])
}}>
<Image
style={styles.photo}
source={{uri: item.node.image.uri}}
/>
</TouchableOpacity>
))}
<TouchableOpacity
style={[styles.galleryButton, styles.photo]}
onPress={() => {
openPicker({multiple: true, maxFiles: 4}).then(items => {
setPhotoUris([
...items.reduce(
(accum, cur) => accum.concat(cur.sourceURL!),
[] as string[],
),
...photoUris,
])
})
}}>
<FontAwesomeIcon
icon="image"
style={{color: colors.blue3}}
size={24}
/>
</TouchableOpacity>
</ScrollView>
)}
<View style={styles.separator} />
<View style={[s.flexRow, s.pt10, s.pb10, s.pr5, styles.contentCenter]}>
<View style={s.flex1} />
<Text style={[s.mr10, {color: progressColor}]}>
{MAX_TEXT_LENGTH - text.length}
@ -275,4 +385,69 @@ const styles = StyleSheet.create({
marginTop: 5,
marginBottom: 10,
},
contentCenter: {alignItems: 'center'},
selectedImageContainer: {
flex: 10,
flexDirection: 'row',
},
selectedImage: {
borderRadius: 8,
margin: 2,
},
selectedImage250: {
width: 250,
height: 250,
},
selectedImage175: {
width: 175,
height: 175,
},
selectedImage85: {
width: 85,
height: 85,
},
photosContainer: {
width: '100%',
maxHeight: 96,
padding: 8,
overflow: 'hidden',
},
removePhotoButton: {
position: 'absolute',
top: 8,
right: 8,
width: 24,
height: 24,
borderRadius: 12,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: colors.black,
zIndex: 1,
},
galleryButton: {
borderWidth: 1,
borderColor: colors.gray3,
alignItems: 'center',
justifyContent: 'center',
},
photoButton: {
width: 75,
height: 75,
marginRight: 8,
borderWidth: 1,
borderRadius: 16,
borderColor: colors.gray3,
},
photo: {
width: 75,
height: 75,
marginRight: 8,
borderRadius: 16,
},
separator: {
borderBottomColor: 'black',
borderBottomWidth: StyleSheet.hairlineWidth,
width: '110%',
marginLeft: -16,
},
})

View file

@ -56,6 +56,9 @@ import {faUserXmark} from '@fortawesome/free-solid-svg-icons/faUserXmark'
import {faTicket} from '@fortawesome/free-solid-svg-icons/faTicket'
import {faTrashCan} from '@fortawesome/free-regular-svg-icons/faTrashCan'
import {faX} from '@fortawesome/free-solid-svg-icons/faX'
import {faCamera} from '@fortawesome/free-solid-svg-icons/faCamera'
import {faImage} from '@fortawesome/free-solid-svg-icons/faImage'
import {faXmark} from '@fortawesome/free-solid-svg-icons/faXmark'
export function setup() {
library.add(
@ -115,5 +118,8 @@ export function setup() {
faTicket,
faTrashCan,
faX,
faCamera,
faImage,
faXmark,
)
}