1
0
mirror of https://github.com/tooot-app/app synced 2025-06-05 22:19:13 +02:00

Basic profile images working

This commit is contained in:
Zhiyuan Zheng
2021-05-13 02:03:24 +02:00
parent 87343989cf
commit d4c93750c7
7 changed files with 279 additions and 138 deletions

View File

@@ -1,6 +1,4 @@
declare namespace Nav {
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
type RootStackParamList = {
'Screen-Tabs': undefined
'Screen-Actions':

View File

@@ -1,13 +1,14 @@
import * as ImagePicker from 'expo-image-picker'
import { Alert, Linking } from 'react-native'
import { ActionSheetOptions } from '@expo/react-native-action-sheet'
import i18next from 'i18next'
import analytics from '@components/analytics'
import { ActionSheetOptions } from '@expo/react-native-action-sheet'
import * as ImageManipulator from 'expo-image-manipulator'
import * as ImagePicker from 'expo-image-picker'
import { ImageInfo } from 'expo-image-picker/build/ImagePicker.types'
import i18next from 'i18next'
import { Alert, Linking } from 'react-native'
export interface Props {
mediaTypes?: ImagePicker.MediaTypeOptions
uploader: (imageInfo: ImageInfo) => void
resize?: { width?: number; height?: number } // Resize mode contain
showActionSheetWithOptions: (
options: ActionSheetOptions,
callback: (i: number) => void
@@ -16,118 +17,134 @@ export interface Props {
const mediaSelector = async ({
mediaTypes = ImagePicker.MediaTypeOptions.All,
uploader,
resize,
showActionSheetWithOptions
}: Props): Promise<any> => {
showActionSheetWithOptions(
{
title: i18next.t('componentMediaSelector:title'),
options: [
i18next.t('componentMediaSelector:options.library'),
i18next.t('componentMediaSelector:options.photo'),
i18next.t('componentMediaSelector:options.cancel')
],
cancelButtonIndex: 2
},
async buttonIndex => {
if (buttonIndex === 0) {
const {
status
} = await ImagePicker.requestMediaLibraryPermissionsAsync()
if (status !== 'granted') {
Alert.alert(
i18next.t('componentMediaSelector:library.alert.title'),
i18next.t('componentMediaSelector:library.alert.message'),
[
{
text: i18next.t(
'componentMediaSelector:library.alert.buttons.cancel'
),
style: 'cancel',
onPress: () =>
analytics('mediaSelector_nopermission', { action: 'cancel' })
},
{
text: i18next.t(
'componentMediaSelector:library.alert.buttons.settings'
),
style: 'default',
onPress: () => {
analytics('mediaSelector_nopermission', {
action: 'settings'
})
Linking.openURL('app-settings:')
}
}
]
)
} else {
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes,
exif: false
})
if (!result.cancelled) {
// https://github.com/expo/expo/issues/11214
const fixResult = {
...result,
uri: result.uri.replace('file:/data', 'file:///data')
}
uploader(fixResult)
return
}: Props): Promise<ImageInfo> => {
return new Promise((resolve, reject) => {
const resolveResult = async (result: ImageInfo) => {
if (resize && result.type === 'image') {
let newResult: ImageManipulator.ImageResult
if (resize.width && resize.height) {
if (resize.width / resize.height > result.width / result.height) {
newResult = await ImageManipulator.manipulateAsync(result.uri, [
{ resize: { width: resize.width } }
])
} else {
newResult = await ImageManipulator.manipulateAsync(result.uri, [
{ resize: { height: resize.height } }
])
}
}
} else if (buttonIndex === 1) {
const { status } = await ImagePicker.requestCameraPermissionsAsync()
if (status !== 'granted') {
Alert.alert(
i18next.t('componentMediaSelector:photo.alert.title'),
i18next.t('componentMediaSelector:photo.alert.message'),
[
{
text: i18next.t(
'componentMediaSelector:photo.alert.buttons.cancel'
),
style: 'cancel',
onPress: () => {
analytics('compose_addattachment_camera_nopermission', {
action: 'cancel'
})
}
},
{
text: i18next.t(
'componentMediaSelector:photo.alert.buttons.settings'
),
style: 'default',
onPress: () => {
analytics('compose_addattachment_camera_nopermission', {
action: 'settings'
})
Linking.openURL('app-settings:')
}
}
]
)
} else {
const result = await ImagePicker.launchCameraAsync({
mediaTypes,
exif: false
})
newResult = await ImageManipulator.manipulateAsync(result.uri, [
{ resize }
])
}
resolve(newResult)
} else {
resolve(result)
}
}
if (!result.cancelled) {
// https://github.com/expo/expo/issues/11214
const fixResult = {
...result,
uri: result.uri.replace('file:/data', 'file:///data')
showActionSheetWithOptions(
{
title: i18next.t('componentMediaSelector:title'),
options: [
i18next.t('componentMediaSelector:options.library'),
i18next.t('componentMediaSelector:options.photo'),
i18next.t('componentMediaSelector:options.cancel')
],
cancelButtonIndex: 2
},
async buttonIndex => {
if (buttonIndex === 0) {
const {
status
} = await ImagePicker.requestMediaLibraryPermissionsAsync()
if (status !== 'granted') {
Alert.alert(
i18next.t('componentMediaSelector:library.alert.title'),
i18next.t('componentMediaSelector:library.alert.message'),
[
{
text: i18next.t(
'componentMediaSelector:library.alert.buttons.cancel'
),
style: 'cancel',
onPress: () =>
analytics('mediaSelector_nopermission', {
action: 'cancel'
})
},
{
text: i18next.t(
'componentMediaSelector:library.alert.buttons.settings'
),
style: 'default',
onPress: () => {
analytics('mediaSelector_nopermission', {
action: 'settings'
})
Linking.openURL('app-settings:')
}
}
]
)
} else {
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes,
exif: false
})
if (!result.cancelled) {
await resolveResult(result)
}
}
} else if (buttonIndex === 1) {
const { status } = await ImagePicker.requestCameraPermissionsAsync()
if (status !== 'granted') {
Alert.alert(
i18next.t('componentMediaSelector:photo.alert.title'),
i18next.t('componentMediaSelector:photo.alert.message'),
[
{
text: i18next.t(
'componentMediaSelector:photo.alert.buttons.cancel'
),
style: 'cancel',
onPress: () => {
analytics('compose_addattachment_camera_nopermission', {
action: 'cancel'
})
}
},
{
text: i18next.t(
'componentMediaSelector:photo.alert.buttons.settings'
),
style: 'default',
onPress: () => {
analytics('compose_addattachment_camera_nopermission', {
action: 'settings'
})
Linking.openURL('app-settings:')
}
}
]
)
} else {
const result = await ImagePicker.launchCameraAsync({
mediaTypes,
exif: false
})
if (!result.cancelled) {
await resolveResult(result)
}
uploader(fixResult)
return
}
}
}
}
)
)
})
}
export default mediaSelector

View File

@@ -123,7 +123,8 @@ const addAttachment = async ({
})
}
mediaSelector({ uploader, showActionSheetWithOptions })
const result = await mediaSelector({ showActionSheetWithOptions })
await uploader(result)
}
export default addAttachment

View File

@@ -1,7 +1,10 @@
import GracefullyImage from '@components/GracefullyImage'
import mediaSelector from '@components/mediaSelector'
import { MenuContainer, MenuRow } from '@components/Menu'
import { useActionSheet } from '@expo/react-native-action-sheet'
import { StackScreenProps } from '@react-navigation/stack'
import { useProfileMutation, useProfileQuery } from '@utils/queryHooks/profile'
import * as ImagePicker from 'expo-image-picker'
import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { ScrollView } from 'react-native-gesture-handler'
@@ -87,30 +90,48 @@ const TabMeProfileRoot: React.FC<StackScreenProps<
<MenuRow
title={t('me.profile.root.avatar.title')}
description={t('me.profile.root.avatar.description')}
// content={
// <GracefullyImage
// style={{ flex: 1 }}
// uri={{
// original: data?.avatar_static
// }}
// />
// }
// loading={isLoading}
// iconBack='ChevronRight'
content={
<GracefullyImage
key={data?.avatar_static}
style={{ flex: 1 }}
uri={{
original: data?.avatar_static
}}
/>
}
loading={isLoading}
iconBack='ChevronRight'
onPress={async () => {
const image = await mediaSelector({
showActionSheetWithOptions,
mediaTypes: ImagePicker.MediaTypeOptions.Images,
resize: { width: 400, height: 400 }
})
mutate({ type: 'avatar', data: image.uri })
}}
/>
<MenuRow
title={t('me.profile.root.banner.title')}
description={t('me.profile.root.banner.description')}
// content={
// <GracefullyImage
// style={{ flex: 1 }}
// uri={{
// original: data?.header_static
// }}
// />
// }
// loading={isLoading}
// iconBack='ChevronRight'
content={
<GracefullyImage
key={data?.header_static}
style={{ flex: 1 }}
uri={{
original: data?.header_static
}}
/>
}
loading={isLoading}
iconBack='ChevronRight'
onPress={async () => {
const image = await mediaSelector({
showActionSheetWithOptions,
mediaTypes: ImagePicker.MediaTypeOptions.Images,
resize: { width: 1500, height: 500 }
})
mutate({ type: 'header', data: image.uri })
}}
/>
<MenuRow
title={t('me.profile.root.note.title')}
@@ -118,9 +139,10 @@ const TabMeProfileRoot: React.FC<StackScreenProps<
loading={isLoading}
iconBack='ChevronRight'
onPress={() => {
navigation.navigate('Tab-Me-Profile-Note', {
note: data?.source?.note || ''
})
data &&
navigation.navigate('Tab-Me-Profile-Note', {
note: data.source?.note
})
}}
/>
<MenuRow