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:
2
src/@types/react-navigation.d.ts
vendored
2
src/@types/react-navigation.d.ts
vendored
@@ -1,6 +1,4 @@
|
||||
declare namespace Nav {
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
|
||||
type RootStackParamList = {
|
||||
'Screen-Tabs': undefined
|
||||
'Screen-Actions':
|
||||
|
@@ -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
|
||||
|
@@ -123,7 +123,8 @@ const addAttachment = async ({
|
||||
})
|
||||
}
|
||||
|
||||
mediaSelector({ uploader, showActionSheetWithOptions })
|
||||
const result = await mediaSelector({ showActionSheetWithOptions })
|
||||
await uploader(result)
|
||||
}
|
||||
|
||||
export default addAttachment
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user