Merge branch 'main' of github.com:bluesky-social/social-app into main
commit
a1a61ef2e5
|
@ -51,10 +51,10 @@ export function init(store: RootStoreModel) {
|
||||||
store.onSessionLoaded(() => {
|
store.onSessionLoaded(() => {
|
||||||
const sess = store.session.currentSession
|
const sess = store.session.currentSession
|
||||||
if (sess) {
|
if (sess) {
|
||||||
if (sess.email) {
|
if (sess.did) {
|
||||||
|
const did_hashed = sha256(sess.did)
|
||||||
|
segmentClient.identify(did_hashed, {did_hashed})
|
||||||
store.log.debug('Ping w/hash')
|
store.log.debug('Ping w/hash')
|
||||||
const email_hashed = sha256(sess.email)
|
|
||||||
segmentClient.identify(email_hashed, {email_hashed})
|
|
||||||
} else {
|
} else {
|
||||||
store.log.debug('Ping w/o hash')
|
store.log.debug('Ping w/o hash')
|
||||||
segmentClient.identify()
|
segmentClient.identify()
|
||||||
|
|
|
@ -46,10 +46,10 @@ export function init(store: RootStoreModel) {
|
||||||
store.onSessionLoaded(() => {
|
store.onSessionLoaded(() => {
|
||||||
const sess = store.session.currentSession
|
const sess = store.session.currentSession
|
||||||
if (sess) {
|
if (sess) {
|
||||||
if (sess.email) {
|
if (sess.did) {
|
||||||
|
const did_hashed = sha256(sess.did)
|
||||||
|
segmentClient.identify(did_hashed, {did_hashed})
|
||||||
store.log.debug('Ping w/hash')
|
store.log.debug('Ping w/hash')
|
||||||
const email_hashed = sha256(sess.email)
|
|
||||||
segmentClient.identify(email_hashed, {email_hashed})
|
|
||||||
} else {
|
} else {
|
||||||
store.log.debug('Ping w/o hash')
|
store.log.debug('Ping w/o hash')
|
||||||
segmentClient.identify()
|
segmentClient.identify()
|
||||||
|
|
|
@ -116,6 +116,7 @@ export class PostsFeedItemModel {
|
||||||
},
|
},
|
||||||
() => this.rootStore.agent.deleteLike(url),
|
() => this.rootStore.agent.deleteLike(url),
|
||||||
)
|
)
|
||||||
|
track('Post:Unlike')
|
||||||
} else {
|
} else {
|
||||||
// like
|
// like
|
||||||
await updateDataOptimistically(
|
await updateDataOptimistically(
|
||||||
|
@ -129,11 +130,10 @@ export class PostsFeedItemModel {
|
||||||
this.post.viewer!.like = res.uri
|
this.post.viewer!.like = res.uri
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
track('Post:Like')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.rootStore.log.error('Failed to toggle like', error)
|
this.rootStore.log.error('Failed to toggle like', error)
|
||||||
} finally {
|
|
||||||
track(this.post.viewer.like ? 'Post:Unlike' : 'Post:Like')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,6 +141,7 @@ export class PostsFeedItemModel {
|
||||||
this.post.viewer = this.post.viewer || {}
|
this.post.viewer = this.post.viewer || {}
|
||||||
try {
|
try {
|
||||||
if (this.post.viewer?.repost) {
|
if (this.post.viewer?.repost) {
|
||||||
|
// unrepost
|
||||||
const url = this.post.viewer.repost
|
const url = this.post.viewer.repost
|
||||||
await updateDataOptimistically(
|
await updateDataOptimistically(
|
||||||
this.post,
|
this.post,
|
||||||
|
@ -150,7 +151,9 @@ export class PostsFeedItemModel {
|
||||||
},
|
},
|
||||||
() => this.rootStore.agent.deleteRepost(url),
|
() => this.rootStore.agent.deleteRepost(url),
|
||||||
)
|
)
|
||||||
|
track('Post:Unrepost')
|
||||||
} else {
|
} else {
|
||||||
|
// repost
|
||||||
await updateDataOptimistically(
|
await updateDataOptimistically(
|
||||||
this.post,
|
this.post,
|
||||||
() => {
|
() => {
|
||||||
|
@ -162,11 +165,10 @@ export class PostsFeedItemModel {
|
||||||
this.post.viewer!.repost = res.uri
|
this.post.viewer!.repost = res.uri
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
track('Post:Repost')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.rootStore.log.error('Failed to toggle repost', error)
|
this.rootStore.log.error('Failed to toggle repost', error)
|
||||||
} finally {
|
|
||||||
track(this.post.viewer.repost ? 'Post:Unrepost' : 'Post:Repost')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,13 +176,13 @@ export class PostsFeedItemModel {
|
||||||
try {
|
try {
|
||||||
if (this.isThreadMuted) {
|
if (this.isThreadMuted) {
|
||||||
this.rootStore.mutedThreads.uris.delete(this.rootUri)
|
this.rootStore.mutedThreads.uris.delete(this.rootUri)
|
||||||
|
track('Post:ThreadUnmute')
|
||||||
} else {
|
} else {
|
||||||
this.rootStore.mutedThreads.uris.add(this.rootUri)
|
this.rootStore.mutedThreads.uris.add(this.rootUri)
|
||||||
|
track('Post:ThreadMute')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.rootStore.log.error('Failed to toggle thread mute', error)
|
this.rootStore.log.error('Failed to toggle thread mute', error)
|
||||||
} finally {
|
|
||||||
track(this.isThreadMuted ? 'Post:ThreadUnmute' : 'Post:ThreadMute')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ import {ListModel} from 'state/models/content/list'
|
||||||
import {s, colors, gradients} from 'lib/styles'
|
import {s, colors, gradients} from 'lib/styles'
|
||||||
import {enforceLen} from 'lib/strings/helpers'
|
import {enforceLen} from 'lib/strings/helpers'
|
||||||
import {compressIfNeeded} from 'lib/media/manip'
|
import {compressIfNeeded} from 'lib/media/manip'
|
||||||
import {UserAvatar} from '../util/UserAvatar'
|
import {EditableUserAvatar} from '../util/UserAvatar'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {useTheme} from 'lib/ThemeContext'
|
import {useTheme} from 'lib/ThemeContext'
|
||||||
import {useAnalytics} from 'lib/analytics/analytics'
|
import {useAnalytics} from 'lib/analytics/analytics'
|
||||||
|
@ -148,7 +148,7 @@ export function Component({
|
||||||
)}
|
)}
|
||||||
<Text style={[styles.label, pal.text]}>List Avatar</Text>
|
<Text style={[styles.label, pal.text]}>List Avatar</Text>
|
||||||
<View style={[styles.avi, {borderColor: pal.colors.background}]}>
|
<View style={[styles.avi, {borderColor: pal.colors.background}]}>
|
||||||
<UserAvatar
|
<EditableUserAvatar
|
||||||
type="list"
|
type="list"
|
||||||
size={80}
|
size={80}
|
||||||
avatar={avatar}
|
avatar={avatar}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import {enforceLen} from 'lib/strings/helpers'
|
||||||
import {MAX_DISPLAY_NAME, MAX_DESCRIPTION} from 'lib/constants'
|
import {MAX_DISPLAY_NAME, MAX_DESCRIPTION} from 'lib/constants'
|
||||||
import {compressIfNeeded} from 'lib/media/manip'
|
import {compressIfNeeded} from 'lib/media/manip'
|
||||||
import {UserBanner} from '../util/UserBanner'
|
import {UserBanner} from '../util/UserBanner'
|
||||||
import {UserAvatar} from '../util/UserAvatar'
|
import {EditableUserAvatar} from '../util/UserAvatar'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {useTheme} from 'lib/ThemeContext'
|
import {useTheme} from 'lib/ThemeContext'
|
||||||
import {useAnalytics} from 'lib/analytics/analytics'
|
import {useAnalytics} from 'lib/analytics/analytics'
|
||||||
|
@ -153,7 +153,7 @@ export function Component({
|
||||||
onSelectNewBanner={onSelectNewBanner}
|
onSelectNewBanner={onSelectNewBanner}
|
||||||
/>
|
/>
|
||||||
<View style={[styles.avi, {borderColor: pal.colors.background}]}>
|
<View style={[styles.avi, {borderColor: pal.colors.background}]}>
|
||||||
<UserAvatar
|
<EditableUserAvatar
|
||||||
size={80}
|
size={80}
|
||||||
avatar={userAvatar}
|
avatar={userAvatar}
|
||||||
onSelectNewAvatar={onSelectNewAvatar}
|
onSelectNewAvatar={onSelectNewAvatar}
|
||||||
|
|
|
@ -77,6 +77,8 @@ export function Component({}: {}) {
|
||||||
keyboardAppearance={theme.colorScheme}
|
keyboardAppearance={theme.colorScheme}
|
||||||
value={email}
|
value={email}
|
||||||
onChangeText={setEmail}
|
onChangeText={setEmail}
|
||||||
|
onSubmitEditing={onPressSignup}
|
||||||
|
enterKeyHint="done"
|
||||||
accessible={true}
|
accessible={true}
|
||||||
accessibilityLabel="Email"
|
accessibilityLabel="Email"
|
||||||
accessibilityHint="Input your email to get on the Bluesky waitlist"
|
accessibilityHint="Input your email to get on the Bluesky waitlist"
|
||||||
|
|
|
@ -100,7 +100,7 @@ export function Component({
|
||||||
accessibilityHint="Sets image aspect ratio to wide">
|
accessibilityHint="Sets image aspect ratio to wide">
|
||||||
<RectWideIcon
|
<RectWideIcon
|
||||||
size={24}
|
size={24}
|
||||||
style={as === AspectRatio.Wide ? s.blue3 : undefined}
|
style={as === AspectRatio.Wide ? s.blue3 : pal.text}
|
||||||
/>
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
|
@ -110,7 +110,7 @@ export function Component({
|
||||||
accessibilityHint="Sets image aspect ratio to tall">
|
accessibilityHint="Sets image aspect ratio to tall">
|
||||||
<RectTallIcon
|
<RectTallIcon
|
||||||
size={24}
|
size={24}
|
||||||
style={as === AspectRatio.Tall ? s.blue3 : undefined}
|
style={as === AspectRatio.Tall ? s.blue3 : pal.text}
|
||||||
/>
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
|
@ -120,7 +120,7 @@ export function Component({
|
||||||
accessibilityHint="Sets image aspect ratio to square">
|
accessibilityHint="Sets image aspect ratio to square">
|
||||||
<SquareIcon
|
<SquareIcon
|
||||||
size={24}
|
size={24}
|
||||||
style={as === AspectRatio.Square ? s.blue3 : undefined}
|
style={as === AspectRatio.Square ? s.blue3 : pal.text}
|
||||||
/>
|
/>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -132,20 +132,19 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({
|
||||||
}, [store, view])
|
}, [store, view])
|
||||||
|
|
||||||
const onPressToggleFollow = React.useCallback(() => {
|
const onPressToggleFollow = React.useCallback(() => {
|
||||||
track(
|
|
||||||
view.viewer.following
|
|
||||||
? 'ProfileHeader:FollowButtonClicked'
|
|
||||||
: 'ProfileHeader:UnfollowButtonClicked',
|
|
||||||
)
|
|
||||||
view?.toggleFollowing().then(
|
view?.toggleFollowing().then(
|
||||||
() => {
|
() => {
|
||||||
setShowSuggestedFollows(Boolean(view.viewer.following))
|
setShowSuggestedFollows(Boolean(view.viewer.following))
|
||||||
|
|
||||||
Toast.show(
|
Toast.show(
|
||||||
`${
|
`${
|
||||||
view.viewer.following ? 'Following' : 'No longer following'
|
view.viewer.following ? 'Following' : 'No longer following'
|
||||||
} ${sanitizeDisplayName(view.displayName || view.handle)}`,
|
} ${sanitizeDisplayName(view.displayName || view.handle)}`,
|
||||||
)
|
)
|
||||||
|
track(
|
||||||
|
view.viewer.following
|
||||||
|
? 'ProfileHeader:FollowButtonClicked'
|
||||||
|
: 'ProfileHeader:UnfollowButtonClicked',
|
||||||
|
)
|
||||||
},
|
},
|
||||||
err => store.log.error('Failed to toggle follow', err),
|
err => store.log.error('Failed to toggle follow', err),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {View, StyleSheet, ScrollView, Pressable} from 'react-native'
|
import {View, StyleSheet, Pressable, ScrollView} from 'react-native'
|
||||||
import Animated, {
|
import Animated, {
|
||||||
useSharedValue,
|
useSharedValue,
|
||||||
withTiming,
|
withTiming,
|
||||||
|
@ -26,6 +26,7 @@ import {sanitizeHandle} from 'lib/strings/handles'
|
||||||
import {makeProfileLink} from 'lib/routes/links'
|
import {makeProfileLink} from 'lib/routes/links'
|
||||||
import {Link} from 'view/com/util/Link'
|
import {Link} from 'view/com/util/Link'
|
||||||
import {useAnalytics} from 'lib/analytics/analytics'
|
import {useAnalytics} from 'lib/analytics/analytics'
|
||||||
|
import {isWeb} from 'platform/detection'
|
||||||
|
|
||||||
const OUTER_PADDING = 10
|
const OUTER_PADDING = 10
|
||||||
const INNER_PADDING = 14
|
const INNER_PADDING = 14
|
||||||
|
@ -100,7 +101,6 @@ export function ProfileHeaderSuggestedFollows({
|
||||||
backgroundColor: pal.viewLight.backgroundColor,
|
backgroundColor: pal.viewLight.backgroundColor,
|
||||||
height: '100%',
|
height: '100%',
|
||||||
paddingTop: INNER_PADDING / 2,
|
paddingTop: INNER_PADDING / 2,
|
||||||
paddingBottom: INNER_PADDING,
|
|
||||||
}}>
|
}}>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
|
@ -130,11 +130,15 @@ export function ProfileHeaderSuggestedFollows({
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
horizontal
|
horizontal={true}
|
||||||
showsHorizontalScrollIndicator={false}
|
showsHorizontalScrollIndicator={isWeb}
|
||||||
|
persistentScrollbar={true}
|
||||||
|
scrollIndicatorInsets={{bottom: 0}}
|
||||||
|
scrollEnabled={true}
|
||||||
contentContainerStyle={{
|
contentContainerStyle={{
|
||||||
alignItems: 'flex-start',
|
alignItems: 'flex-start',
|
||||||
paddingLeft: INNER_PADDING / 2,
|
paddingLeft: INNER_PADDING / 2,
|
||||||
|
paddingBottom: INNER_PADDING,
|
||||||
}}>
|
}}>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import React, {ComponentProps, useMemo} from 'react'
|
import React, {ComponentProps, memo, useMemo} from 'react'
|
||||||
import {observer} from 'mobx-react-lite'
|
|
||||||
import {
|
import {
|
||||||
Linking,
|
Linking,
|
||||||
GestureResponderEvent,
|
GestureResponderEvent,
|
||||||
|
@ -50,7 +49,7 @@ interface Props extends ComponentProps<typeof TouchableOpacity> {
|
||||||
anchorNoUnderline?: boolean
|
anchorNoUnderline?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Link = observer(function Link({
|
export const Link = memo(function Link({
|
||||||
testID,
|
testID,
|
||||||
style,
|
style,
|
||||||
href,
|
href,
|
||||||
|
@ -136,7 +135,7 @@ export const Link = observer(function Link({
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
export const TextLink = observer(function TextLink({
|
export const TextLink = memo(function TextLink({
|
||||||
testID,
|
testID,
|
||||||
type = 'md',
|
type = 'md',
|
||||||
style,
|
style,
|
||||||
|
@ -236,7 +235,7 @@ interface DesktopWebTextLinkProps extends TextProps {
|
||||||
accessibilityHint?: string
|
accessibilityHint?: string
|
||||||
title?: string
|
title?: string
|
||||||
}
|
}
|
||||||
export const DesktopWebTextLink = observer(function DesktopWebTextLink({
|
export const DesktopWebTextLink = memo(function DesktopWebTextLink({
|
||||||
testID,
|
testID,
|
||||||
type = 'md',
|
type = 'md',
|
||||||
style,
|
style,
|
||||||
|
|
|
@ -23,14 +23,18 @@ interface BaseUserAvatarProps {
|
||||||
type?: Type
|
type?: Type
|
||||||
size: number
|
size: number
|
||||||
avatar?: string | null
|
avatar?: string | null
|
||||||
moderation?: ModerationUI
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UserAvatarProps extends BaseUserAvatarProps {
|
interface UserAvatarProps extends BaseUserAvatarProps {
|
||||||
onSelectNewAvatar?: (img: RNImage | null) => void
|
moderation?: ModerationUI
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EditableUserAvatarProps extends BaseUserAvatarProps {
|
||||||
|
onSelectNewAvatar: (img: RNImage | null) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PreviewableUserAvatarProps extends BaseUserAvatarProps {
|
interface PreviewableUserAvatarProps extends BaseUserAvatarProps {
|
||||||
|
moderation?: ModerationUI
|
||||||
did: string
|
did: string
|
||||||
handle: string
|
handle: string
|
||||||
}
|
}
|
||||||
|
@ -106,8 +110,65 @@ export function UserAvatar({
|
||||||
size,
|
size,
|
||||||
avatar,
|
avatar,
|
||||||
moderation,
|
moderation,
|
||||||
onSelectNewAvatar,
|
|
||||||
}: UserAvatarProps) {
|
}: UserAvatarProps) {
|
||||||
|
const pal = usePalette('default')
|
||||||
|
|
||||||
|
const aviStyle = useMemo(() => {
|
||||||
|
if (type === 'algo' || type === 'list') {
|
||||||
|
return {
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
borderRadius: size > 32 ? 8 : 3,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
borderRadius: Math.floor(size / 2),
|
||||||
|
}
|
||||||
|
}, [type, size])
|
||||||
|
|
||||||
|
const alert = useMemo(() => {
|
||||||
|
if (!moderation?.alert) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<View style={[styles.alertIconContainer, pal.view]}>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon="exclamation-circle"
|
||||||
|
style={styles.alertIcon}
|
||||||
|
size={Math.floor(size / 3)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}, [moderation?.alert, size, pal])
|
||||||
|
|
||||||
|
return avatar &&
|
||||||
|
!((moderation?.blur && isAndroid) /* android crashes with blur */) ? (
|
||||||
|
<View style={{width: size, height: size}}>
|
||||||
|
<HighPriorityImage
|
||||||
|
testID="userAvatarImage"
|
||||||
|
style={aviStyle}
|
||||||
|
contentFit="cover"
|
||||||
|
source={{uri: avatar}}
|
||||||
|
blurRadius={moderation?.blur ? BLUR_AMOUNT : 0}
|
||||||
|
/>
|
||||||
|
{alert}
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<View style={{width: size, height: size}}>
|
||||||
|
<DefaultAvatar type={type} size={size} />
|
||||||
|
{alert}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function EditableUserAvatar({
|
||||||
|
type = 'user',
|
||||||
|
size,
|
||||||
|
avatar,
|
||||||
|
onSelectNewAvatar,
|
||||||
|
}: EditableUserAvatarProps) {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const {requestCameraAccessIfNeeded} = useCameraPermission()
|
const {requestCameraAccessIfNeeded} = useCameraPermission()
|
||||||
|
@ -146,7 +207,7 @@ export function UserAvatar({
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
onSelectNewAvatar?.(
|
onSelectNewAvatar(
|
||||||
await openCamera(store, {
|
await openCamera(store, {
|
||||||
width: 1000,
|
width: 1000,
|
||||||
height: 1000,
|
height: 1000,
|
||||||
|
@ -186,7 +247,7 @@ export function UserAvatar({
|
||||||
path: item.path,
|
path: item.path,
|
||||||
})
|
})
|
||||||
|
|
||||||
onSelectNewAvatar?.(croppedImage)
|
onSelectNewAvatar(croppedImage)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
!!avatar && {
|
!!avatar && {
|
||||||
|
@ -203,7 +264,7 @@ export function UserAvatar({
|
||||||
web: 'trash',
|
web: 'trash',
|
||||||
},
|
},
|
||||||
onPress: async () => {
|
onPress: async () => {
|
||||||
onSelectNewAvatar?.(null)
|
onSelectNewAvatar(null)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
].filter(Boolean) as DropdownItem[],
|
].filter(Boolean) as DropdownItem[],
|
||||||
|
@ -216,23 +277,7 @@ export function UserAvatar({
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
const alert = useMemo(() => {
|
|
||||||
if (!moderation?.alert) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<View style={[styles.alertIconContainer, pal.view]}>
|
|
||||||
<FontAwesomeIcon
|
|
||||||
icon="exclamation-circle"
|
|
||||||
style={styles.alertIcon}
|
|
||||||
size={Math.floor(size / 3)}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}, [moderation?.alert, size, pal])
|
|
||||||
|
|
||||||
// onSelectNewAvatar is only passed as prop on the EditProfile component
|
|
||||||
return onSelectNewAvatar ? (
|
|
||||||
<NativeDropdown
|
<NativeDropdown
|
||||||
testID="changeAvatarBtn"
|
testID="changeAvatarBtn"
|
||||||
items={dropdownItems}
|
items={dropdownItems}
|
||||||
|
@ -256,23 +301,6 @@ export function UserAvatar({
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</NativeDropdown>
|
</NativeDropdown>
|
||||||
) : avatar &&
|
|
||||||
!((moderation?.blur && isAndroid) /* android crashes with blur */) ? (
|
|
||||||
<View style={{width: size, height: size}}>
|
|
||||||
<HighPriorityImage
|
|
||||||
testID="userAvatarImage"
|
|
||||||
style={aviStyle}
|
|
||||||
contentFit="cover"
|
|
||||||
source={{uri: avatar}}
|
|
||||||
blurRadius={moderation?.blur ? BLUR_AMOUNT : 0}
|
|
||||||
/>
|
|
||||||
{alert}
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<View style={{width: size, height: size}}>
|
|
||||||
<DefaultAvatar type={type} size={size} />
|
|
||||||
{alert}
|
|
||||||
</View>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,8 +63,8 @@ function ImageLayoutGridInner(props: ImageLayoutGridInnerProps) {
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<View style={styles.flexRow}>
|
<View style={styles.flexRow}>
|
||||||
<View style={{flex: 1}}>
|
|
||||||
<View style={styles.smallItem}>
|
<View style={styles.smallItem}>
|
||||||
<GalleryItem {...props} index={0} imageStyle={styles.image} />
|
<GalleryItem {...props} index={0} imageStyle={styles.image} />
|
||||||
</View>
|
</View>
|
||||||
|
@ -72,7 +72,7 @@ function ImageLayoutGridInner(props: ImageLayoutGridInnerProps) {
|
||||||
<GalleryItem {...props} index={2} imageStyle={styles.image} />
|
<GalleryItem {...props} index={2} imageStyle={styles.image} />
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View style={{flex: 1}}>
|
<View style={styles.flexRow}>
|
||||||
<View style={styles.smallItem}>
|
<View style={styles.smallItem}>
|
||||||
<GalleryItem {...props} index={1} imageStyle={styles.image} />
|
<GalleryItem {...props} index={1} imageStyle={styles.image} />
|
||||||
</View>
|
</View>
|
||||||
|
@ -80,7 +80,7 @@ function ImageLayoutGridInner(props: ImageLayoutGridInnerProps) {
|
||||||
<GalleryItem {...props} index={3} imageStyle={styles.image} />
|
<GalleryItem {...props} index={3} imageStyle={styles.image} />
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</>
|
||||||
)
|
)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {TextLink} from 'view/com/util/Link'
|
||||||
import {CenteredView} from 'view/com/util/Views'
|
import {CenteredView} from 'view/com/util/Views'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {s} from 'lib/styles'
|
import {s} from 'lib/styles'
|
||||||
|
import {HELP_DESK_URL} from 'lib/constants'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Support'>
|
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Support'>
|
||||||
export const SupportScreen = (_props: Props) => {
|
export const SupportScreen = (_props: Props) => {
|
||||||
|
@ -29,14 +30,13 @@ export const SupportScreen = (_props: Props) => {
|
||||||
Support
|
Support
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={[pal.text, s.p20]}>
|
<Text style={[pal.text, s.p20]}>
|
||||||
If you need help, email us at{' '}
|
The support form has been moved. If you need help, please
|
||||||
<TextLink
|
<TextLink
|
||||||
href="mailto:support@bsky.app"
|
href={HELP_DESK_URL}
|
||||||
text="support@bsky.app"
|
text=" click here"
|
||||||
style={pal.link}
|
style={pal.link}
|
||||||
/>{' '}
|
/>{' '}
|
||||||
with a description of your issue and information about how we can help
|
or visit {HELP_DESK_URL} to get in touch with us.
|
||||||
you.
|
|
||||||
</Text>
|
</Text>
|
||||||
</CenteredView>
|
</CenteredView>
|
||||||
</View>
|
</View>
|
||||||
|
|
Loading…
Reference in New Issue