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