Replaces the alert with dropdown for profile image and banner (#123)
* replaces the alert with dropdown for profile image and banner * lint
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import React, {useCallback} from 'react'
|
||||
import {Alert, Image, StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||
import React from 'react'
|
||||
import {Image, StyleSheet, View} from 'react-native'
|
||||
import Svg, {Circle, Text, Defs, LinearGradient, Stop} from 'react-native-svg'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
Image as PickedImage,
|
||||
} from 'react-native-image-crop-picker'
|
||||
import {colors, gradients} from '../../lib/styles'
|
||||
import {DropdownButton} from './forms/DropdownButton'
|
||||
|
||||
export function UserAvatar({
|
||||
size,
|
||||
@@ -25,43 +26,6 @@ export function UserAvatar({
|
||||
}) {
|
||||
const initials = getInitials(displayName || handle)
|
||||
|
||||
const handleEditAvatar = useCallback(() => {
|
||||
Alert.alert('Select upload method', '', [
|
||||
{
|
||||
text: 'Take a new photo',
|
||||
onPress: () => {
|
||||
openCamera({
|
||||
mediaType: 'photo',
|
||||
cropping: true,
|
||||
width: 2000,
|
||||
height: 2000,
|
||||
cropperCircleOverlay: true,
|
||||
forceJpg: true, // ios only
|
||||
compressImageQuality: 1,
|
||||
}).then(onSelectNewAvatar)
|
||||
},
|
||||
},
|
||||
{
|
||||
text: 'Select from gallery',
|
||||
onPress: () => {
|
||||
openPicker({
|
||||
mediaType: 'photo',
|
||||
}).then(async item => {
|
||||
await openCropper({
|
||||
mediaType: 'photo',
|
||||
path: item.path,
|
||||
width: 2000,
|
||||
height: 2000,
|
||||
cropperCircleOverlay: true,
|
||||
forceJpg: true, // ios only
|
||||
compressImageQuality: 1,
|
||||
}).then(onSelectNewAvatar)
|
||||
})
|
||||
},
|
||||
},
|
||||
])
|
||||
}, [onSelectNewAvatar])
|
||||
|
||||
const renderSvg = (svgSize: number, svgInitials: string) => (
|
||||
<Svg width={svgSize} height={svgSize} viewBox="0 0 100 100">
|
||||
<Defs>
|
||||
@@ -83,9 +47,60 @@ export function UserAvatar({
|
||||
</Svg>
|
||||
)
|
||||
|
||||
const dropdownItems = [
|
||||
{
|
||||
label: 'Camera',
|
||||
icon: 'camera',
|
||||
// TODO: dark mode icon
|
||||
onPress: () => {
|
||||
openCamera({
|
||||
mediaType: 'photo',
|
||||
cropping: true,
|
||||
width: 2000,
|
||||
height: 2000,
|
||||
cropperCircleOverlay: true,
|
||||
forceJpg: true, // ios only
|
||||
compressImageQuality: 1,
|
||||
}).then(onSelectNewAvatar)
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Library',
|
||||
icon: 'image',
|
||||
onPress: () => {
|
||||
openPicker({
|
||||
mediaType: 'photo',
|
||||
}).then(async item => {
|
||||
await openCropper({
|
||||
mediaType: 'photo',
|
||||
path: item.path,
|
||||
width: 2000,
|
||||
height: 2000,
|
||||
cropperCircleOverlay: true,
|
||||
forceJpg: true, // ios only
|
||||
compressImageQuality: 1,
|
||||
}).then(onSelectNewAvatar)
|
||||
})
|
||||
},
|
||||
},
|
||||
// TODO: Remove avatar https://github.com/bluesky-social/social-app/issues/122
|
||||
// {
|
||||
// label: 'Remove',
|
||||
// icon: ['far', 'trash-can'],
|
||||
// onPress: () => {
|
||||
// // Remove avatar API call
|
||||
// },
|
||||
// },
|
||||
]
|
||||
// onSelectNewAvatar is only passed as prop on the EditProfile component
|
||||
return onSelectNewAvatar ? (
|
||||
<TouchableOpacity onPress={handleEditAvatar}>
|
||||
<DropdownButton
|
||||
type="bare"
|
||||
items={dropdownItems}
|
||||
openToRight
|
||||
rightOffset={-10}
|
||||
bottomOffset={-10}
|
||||
menuWidth={170}>
|
||||
{avatar ? (
|
||||
<Image
|
||||
style={{
|
||||
@@ -105,7 +120,7 @@ export function UserAvatar({
|
||||
style={{color: colors.white}}
|
||||
/>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</DropdownButton>
|
||||
) : avatar ? (
|
||||
<Image
|
||||
style={{width: size, height: size, borderRadius: Math.floor(size / 2)}}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, {useCallback} from 'react'
|
||||
import {StyleSheet, View, TouchableOpacity, Alert, Image} from 'react-native'
|
||||
import React from 'react'
|
||||
import {StyleSheet, View, Image} from 'react-native'
|
||||
import Svg, {Rect, Defs, LinearGradient, Stop} from 'react-native-svg'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {Image as PickedImage} from 'react-native-image-crop-picker'
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
openCropper,
|
||||
openPicker,
|
||||
} from 'react-native-image-crop-picker'
|
||||
import {DropdownButton} from './forms/DropdownButton'
|
||||
|
||||
export function UserBanner({
|
||||
banner,
|
||||
@@ -17,14 +18,35 @@ export function UserBanner({
|
||||
banner?: string | null
|
||||
onSelectNewBanner?: (img: PickedImage) => void
|
||||
}) {
|
||||
const handleEditBanner = useCallback(() => {
|
||||
Alert.alert('Select upload method', '', [
|
||||
{
|
||||
text: 'Take a new photo',
|
||||
onPress: () => {
|
||||
openCamera({
|
||||
const dropdownItems = [
|
||||
{
|
||||
label: 'Camera',
|
||||
icon: 'camera',
|
||||
// TODO: Add darkmode support https://github.com/bluesky-social/social-app/issues/78
|
||||
onPress: () => {
|
||||
openCamera({
|
||||
mediaType: 'photo',
|
||||
cropping: true,
|
||||
compressImageMaxWidth: 6000,
|
||||
width: 6000,
|
||||
compressImageMaxHeight: 2000,
|
||||
height: 2000,
|
||||
forceJpg: true, // ios only
|
||||
compressImageQuality: 1,
|
||||
includeExif: true,
|
||||
}).then(onSelectNewBanner)
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Library',
|
||||
icon: 'image',
|
||||
onPress: () => {
|
||||
openPicker({
|
||||
mediaType: 'photo',
|
||||
}).then(async item => {
|
||||
await openCropper({
|
||||
mediaType: 'photo',
|
||||
cropping: true,
|
||||
path: item.path,
|
||||
compressImageMaxWidth: 6000,
|
||||
width: 6000,
|
||||
compressImageMaxHeight: 2000,
|
||||
@@ -33,30 +55,18 @@ export function UserBanner({
|
||||
compressImageQuality: 1,
|
||||
includeExif: true,
|
||||
}).then(onSelectNewBanner)
|
||||
},
|
||||
})
|
||||
},
|
||||
{
|
||||
text: 'Select from gallery',
|
||||
onPress: () => {
|
||||
openPicker({
|
||||
mediaType: 'photo',
|
||||
}).then(async item => {
|
||||
await openCropper({
|
||||
mediaType: 'photo',
|
||||
path: item.path,
|
||||
compressImageMaxWidth: 6000,
|
||||
width: 6000,
|
||||
compressImageMaxHeight: 2000,
|
||||
height: 2000,
|
||||
forceJpg: true, // ios only
|
||||
compressImageQuality: 1,
|
||||
includeExif: true,
|
||||
}).then(onSelectNewBanner)
|
||||
})
|
||||
},
|
||||
},
|
||||
])
|
||||
}, [onSelectNewBanner])
|
||||
},
|
||||
// TODO: Remove banner https://github.com/bluesky-social/social-app/issues/122
|
||||
// {
|
||||
// label: 'Remove',
|
||||
// icon: ['far', 'trash-can'],
|
||||
// onPress: () => {
|
||||
// // Remove banner api call
|
||||
// },
|
||||
// },
|
||||
]
|
||||
|
||||
const renderSvg = () => (
|
||||
<Svg width="100%" height="150" viewBox="50 0 200 100">
|
||||
@@ -77,7 +87,13 @@ export function UserBanner({
|
||||
|
||||
// setUserBanner is only passed as prop on the EditProfile component
|
||||
return onSelectNewBanner ? (
|
||||
<TouchableOpacity onPress={handleEditBanner}>
|
||||
<DropdownButton
|
||||
type="bare"
|
||||
items={dropdownItems}
|
||||
openToRight
|
||||
rightOffset={-200}
|
||||
bottomOffset={-10}
|
||||
menuWidth={170}>
|
||||
{banner ? (
|
||||
<Image style={styles.bannerImage} source={{uri: banner}} />
|
||||
) : (
|
||||
@@ -90,7 +106,7 @@ export function UserBanner({
|
||||
style={{color: colors.white}}
|
||||
/>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</DropdownButton>
|
||||
) : banner ? (
|
||||
<Image
|
||||
style={styles.bannerImage}
|
||||
|
||||
@@ -36,6 +36,9 @@ export function DropdownButton({
|
||||
label,
|
||||
menuWidth,
|
||||
children,
|
||||
openToRight = false,
|
||||
rightOffset = 0,
|
||||
bottomOffset = 0,
|
||||
}: {
|
||||
type: DropdownButtonType
|
||||
style?: StyleProp<ViewStyle>
|
||||
@@ -43,6 +46,9 @@ export function DropdownButton({
|
||||
label?: string
|
||||
menuWidth?: number
|
||||
children?: React.ReactNode
|
||||
openToRight?: boolean
|
||||
rightOffset?: number
|
||||
bottomOffset?: number
|
||||
}) {
|
||||
const ref = useRef<TouchableOpacity>(null)
|
||||
|
||||
@@ -59,12 +65,11 @@ export function DropdownButton({
|
||||
if (!menuWidth) {
|
||||
menuWidth = 200
|
||||
}
|
||||
createDropdownMenu(
|
||||
pageX + width - menuWidth,
|
||||
pageY + height,
|
||||
menuWidth,
|
||||
items,
|
||||
)
|
||||
const newX = openToRight
|
||||
? pageX + width + rightOffset
|
||||
: pageX + width - menuWidth
|
||||
const newY = pageY + height + bottomOffset
|
||||
createDropdownMenu(newX, newY, menuWidth, items)
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -184,7 +189,7 @@ function createDropdownMenu(
|
||||
{items.map((item, index) => (
|
||||
<TouchableOpacity
|
||||
key={index}
|
||||
style={[styles.menuItem]}
|
||||
style={styles.menuItem}
|
||||
onPress={() => onPressItem(index)}>
|
||||
{item.icon && (
|
||||
<FontAwesomeIcon style={styles.icon} icon={item.icon} />
|
||||
|
||||
Reference in New Issue
Block a user