Skip to content

Commit

Permalink
feat: post images (#265)
Browse files Browse the repository at this point in the history
  • Loading branch information
ugur-eren authored Jul 24, 2024
1 parent 0dc954e commit 9f0d974
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 26 deletions.
21 changes: 18 additions & 3 deletions JoyboyCommunity/src/modules/Post/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {useProfile, useReact, useReactions, useReplyNotes, useStyles, useTheme}
import {useTipModal} from '../../hooks/modals';
import {useAuth} from '../../store/auth';
import {MainStackNavigationProps} from '../../types';
import {shortenPubkey} from '../../utils/helpers';
import {getImageRatio, shortenPubkey} from '../../utils/helpers';
import {getElapsedTimeStringFull} from '../../utils/timestamp';
import stylesheet from './styles';

Expand All @@ -29,7 +29,6 @@ export type PostProps = {

export const Post: React.FC<PostProps> = ({asComment, event}) => {
const repostedEvent = undefined;
const postSource = undefined;

const {theme} = useTheme();
const styles = useStyles(stylesheet);
Expand Down Expand Up @@ -65,6 +64,16 @@ export const Post: React.FC<PostProps> = ({asComment, event}) => {
return likesCount - dislikesCount;
}, [reactions.data]);

const postSource = useMemo(() => {
if (!event?.tags) return;

const imageTag = event.tags.find((tag) => tag[0] === 'image');
if (!imageTag) return;

const dimensions = imageTag[2].split('x').map(Number);
return {uri: imageTag[1], width: dimensions[0], height: dimensions[1]};
}, [event?.tags]);

// Animated style for the icon
const animatedIconStyle = useAnimatedStyle(() => ({
transform: [{scale: scale.value}],
Expand Down Expand Up @@ -185,7 +194,13 @@ export const Post: React.FC<PostProps> = ({asComment, event}) => {
</Text>

{postSource && (
<Image source={{uri: postSource}} resizeMode="cover" style={styles.contentImage} />
<Image
source={postSource}
style={[
styles.contentImage,
{aspectRatio: getImageRatio(postSource.width, postSource.height)},
]}
/>
)}
</Pressable>
</View>
Expand Down
4 changes: 3 additions & 1 deletion JoyboyCommunity/src/modules/Post/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,10 @@ export default ThemedStyleSheet((theme) => ({
},
contentImage: {
width: '100%',
height: 160,
height: 'auto',
resizeMode: 'cover',
borderRadius: 8,
overflow: 'hidden',
marginTop: Spacing.small,
},

Expand Down
75 changes: 53 additions & 22 deletions JoyboyCommunity/src/screens/CreatePost/index.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,61 @@
import {useQueryClient} from '@tanstack/react-query';
import * as ImagePicker from 'expo-image-picker';
import {useState} from 'react';
import {KeyboardAvoidingView, Pressable, TextInput, View} from 'react-native';
import {Image, KeyboardAvoidingView, Pressable, TextInput, View} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';

import {CopyIcon, GalleryIcon, GifIcon, SendIconContained} from '../../assets/icons';
import {GalleryIcon, SendIconContained} from '../../assets/icons';
import {TextButton} from '../../components';
import {useSendNote, useStyles, useTheme} from '../../hooks';
import {useFileUpload} from '../../hooks/api';
import {useToast} from '../../hooks/modals';
import {CreatePostScreenProps} from '../../types';
import {getImageRatio} from '../../utils/helpers';
import stylesheet from './styles';

export const CreatePost: React.FC<CreatePostScreenProps> = ({navigation}) => {
const {theme} = useTheme();
const styles = useStyles(stylesheet);

const [note, setNote] = useState<string | undefined>();
const [image, setImage] = useState<ImagePicker.ImagePickerAsset | undefined>();

const fileUpload = useFileUpload();
const sendNote = useSendNote();
const queryClient = useQueryClient();
const {showToast} = useToast();

const handleSendNote = () => {
const onGalleryPress = async () => {
const pickerResult = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
allowsMultipleSelection: false,
selectionLimit: 1,
exif: false,
quality: 0.75,
});

if (pickerResult.canceled || !pickerResult.assets.length) return;
setImage(pickerResult.assets[0]);
};

const handleSendNote = async () => {
if (!note || note?.length == 0) {
showToast({type: 'error', title: 'Please write your note'});
return;
}

let imageUrl: string | undefined;
if (image) {
const result = await fileUpload.mutateAsync(image);
if (result.data.url) imageUrl = result.data.url;
}

sendNote.mutate(
{content: note},
{
content: note,
tags: image && imageUrl ? [['image', imageUrl, `${image.width}x${image.height}`]] : [],
},
{
onSuccess() {
showToast({type: 'success', title: 'Note sent successfully'});
Expand All @@ -54,29 +82,32 @@ export const CreatePost: React.FC<CreatePostScreenProps> = ({navigation}) => {

<KeyboardAvoidingView behavior="padding" style={styles.content}>
<SafeAreaView edges={['bottom', 'left', 'right']} style={styles.content}>
<TextInput
style={styles.input}
value={note}
onChangeText={setNote}
autoFocus
multiline={true}
placeholder="Make a post"
placeholderTextColor={theme.colors.inputPlaceholder}
/>
<View style={styles.form}>
<TextInput
style={styles.input}
value={note}
onChangeText={setNote}
autoFocus
multiline={true}
placeholder="Make a post"
placeholderTextColor={theme.colors.inputPlaceholder}
/>

{image && (
<View style={styles.imageContainer}>
<Image
source={{uri: image.uri}}
style={[styles.image, {aspectRatio: getImageRatio(image.width, image.height)}]}
/>
</View>
)}
</View>

<View style={styles.buttons}>
<View style={styles.mediaButtons}>
<Pressable>
<Pressable onPress={onGalleryPress}>
<GalleryIcon width="24" height="24" color={theme.colors.primary} />
</Pressable>

<Pressable>
<GifIcon width="24" height="24" color={theme.colors.primary} />
</Pressable>

<Pressable>
<CopyIcon width="24" height="24" color={theme.colors.primary} />
</Pressable>
</View>

<Pressable style={styles.sendButton} onPress={handleSendNote}>
Expand Down
12 changes: 12 additions & 0 deletions JoyboyCommunity/src/screens/CreatePost/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export default ThemedStyleSheet((theme) => ({
flex: 1,
backgroundColor: theme.colors.background,
},
form: {
flex: 1,
},
input: {
flex: 1,
padding: Spacing.large,
Expand All @@ -33,6 +36,15 @@ export default ThemedStyleSheet((theme) => ({
lineHeight: 24,
...Typography.medium,
},
imageContainer: {
padding: Spacing.pagePadding,
},
image: {
width: '100%',
resizeMode: 'cover',
borderRadius: 8,
overflow: 'hidden',
},

buttons: {
position: 'relative',
Expand Down
4 changes: 4 additions & 0 deletions JoyboyCommunity/src/utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,7 @@ export const dataURLToBlob = (dataURL: string) => {

return new Blob([ab], {type: mimeString});
};

export const getImageRatio = (width: number, height: number, minRatio = 0.75, maxRatio = 1.5) => {
return Math.max(minRatio, Math.min(maxRatio, width / height));
};

0 comments on commit 9f0d974

Please sign in to comment.