diff --git a/icons/UserAvatar.tsx b/icons/UserAvatar.tsx deleted file mode 100644 index ab39982..0000000 --- a/icons/UserAvatar.tsx +++ /dev/null @@ -1,484 +0,0 @@ -// https://raw.githubusercontent.com/bluesky-social/social-app/refs/heads/main/src/view/com/util/UserAvatar.tsx -import React, {memo, useMemo} from 'react' -import {Image, Pressable, StyleSheet, View} from 'react-native' -import {Image as RNImage} from 'react-native-image-crop-picker' -import Svg, {Circle, Path, Rect} from 'react-native-svg' -import {AppBskyActorDefs, ModerationUI} from '@atproto/api' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import {msg, Trans} from '@lingui/macro' -import {useLingui} from '@lingui/react' -import {useQueryClient} from '@tanstack/react-query' - -import {usePalette} from '#/lib/hooks/usePalette' -import { - useCameraPermission, - usePhotoLibraryPermission, -} from '#/lib/hooks/usePermissions' -import {makeProfileLink} from '#/lib/routes/links' -import {colors} from '#/lib/styles' -import {logger} from '#/logger' -import {isAndroid, isNative, isWeb} from '#/platform/detection' -import {precacheProfile} from '#/state/queries/profile' -import {HighPriorityImage} from '#/view/com/util/images/Image' -import {tokens, useTheme} from '#/alf' -import {useSheetWrapper} from '#/components/Dialog/sheet-wrapper' -import { - Camera_Filled_Stroke2_Corner0_Rounded as CameraFilled, - Camera_Stroke2_Corner0_Rounded as Camera, -} from '#/components/icons/Camera' -import {StreamingLive_Stroke2_Corner0_Rounded as Library} from '#/components/icons/StreamingLive' -import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash' -import {Link} from '#/components/Link' -import {MediaInsetBorder} from '#/components/MediaInsetBorder' -import * as Menu from '#/components/Menu' -import {ProfileHoverCard} from '#/components/ProfileHoverCard' -import {openCamera, openCropper, openPicker} from '../../../lib/media/picker' - -export type UserAvatarType = 'user' | 'algo' | 'list' | 'labeler' - -interface BaseUserAvatarProps { - type?: UserAvatarType - shape?: 'circle' | 'square' - size: number - avatar?: string | null -} - -interface UserAvatarProps extends BaseUserAvatarProps { - moderation?: ModerationUI - usePlainRNImage?: boolean - onLoad?: () => void -} - -interface EditableUserAvatarProps extends BaseUserAvatarProps { - onSelectNewAvatar: (img: RNImage | null) => void -} - -interface PreviewableUserAvatarProps extends BaseUserAvatarProps { - moderation?: ModerationUI - profile: AppBskyActorDefs.ProfileViewBasic - disableHoverCard?: boolean - onBeforePress?: () => void -} - -const BLUR_AMOUNT = isWeb ? 5 : 100 - -let DefaultAvatar = ({ - type, - shape: overrideShape, - size, -}: { - type: UserAvatarType - shape?: 'square' | 'circle' - size: number -}): React.ReactNode => { - const finalShape = overrideShape ?? (type === 'user' ? 'circle' : 'square') - if (type === 'algo') { - // TODO: shape=circle - // Font Awesome Pro 6.4.0 by @fontawesome -https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. - return ( - - - - - ) - } - if (type === 'list') { - // TODO: shape=circle - // Font Awesome Pro 6.4.0 by @fontawesome -https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. - return ( - - - - - - ) - } - if (type === 'labeler') { - return ( - - {finalShape === 'square' ? ( - - ) : ( - - )} - - - ) - } - // TODO: shape=square - return ( - - - - - - ) -} -DefaultAvatar = memo(DefaultAvatar) -export {DefaultAvatar} - -let UserAvatar = ({ - type = 'user', - shape: overrideShape, - size, - avatar, - moderation, - usePlainRNImage = false, - onLoad, -}: UserAvatarProps): React.ReactNode => { - const pal = usePalette('default') - const backgroundColor = pal.colors.backgroundLight - const finalShape = overrideShape ?? (type === 'user' ? 'circle' : 'square') - - const aviStyle = useMemo(() => { - if (finalShape === 'square') { - return { - width: size, - height: size, - borderRadius: size > 32 ? 8 : 3, - backgroundColor, - } - } - return { - width: size, - height: size, - borderRadius: Math.floor(size / 2), - backgroundColor, - } - }, [finalShape, size, backgroundColor]) - - const alert = useMemo(() => { - if (!moderation?.alert) { - return null - } - return ( - - - - ) - }, [moderation?.alert, size, pal]) - - return avatar && - !((moderation?.blur && isAndroid) /* android crashes with blur */) ? ( - - {usePlainRNImage ? ( - - ) : ( - - )} - - {alert} - - ) : ( - - - {alert} - - ) -} -UserAvatar = memo(UserAvatar) -export {UserAvatar} - -let EditableUserAvatar = ({ - type = 'user', - size, - avatar, - onSelectNewAvatar, -}: EditableUserAvatarProps): React.ReactNode => { - const t = useTheme() - const pal = usePalette('default') - const {_} = useLingui() - const {requestCameraAccessIfNeeded} = useCameraPermission() - const {requestPhotoAccessIfNeeded} = usePhotoLibraryPermission() - const sheetWrapper = useSheetWrapper() - - 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 onOpenCamera = React.useCallback(async () => { - if (!(await requestCameraAccessIfNeeded())) { - return - } - - onSelectNewAvatar( - await openCamera({ - width: 1000, - height: 1000, - cropperCircleOverlay: true, - }), - ) - }, [onSelectNewAvatar, requestCameraAccessIfNeeded]) - - const onOpenLibrary = React.useCallback(async () => { - if (!(await requestPhotoAccessIfNeeded())) { - return - } - - const items = await sheetWrapper( - openPicker({ - aspect: [1, 1], - }), - ) - const item = items[0] - if (!item) { - return - } - - try { - const croppedImage = await openCropper({ - mediaType: 'photo', - cropperCircleOverlay: true, - height: 1000, - width: 1000, - path: item.path, - webAspectRatio: 1, - webCircularCrop: true, - }) - - onSelectNewAvatar(croppedImage) - } catch (e: any) { - // Don't log errors for cancelling selection to sentry on ios or android - if (!String(e).toLowerCase().includes('cancel')) { - logger.error('Failed to crop banner', {error: e}) - } - } - }, [onSelectNewAvatar, requestPhotoAccessIfNeeded, sheetWrapper]) - - const onRemoveAvatar = React.useCallback(() => { - onSelectNewAvatar(null) - }, [onSelectNewAvatar]) - - return ( - - - {({props}) => ( - - {avatar ? ( - 0), }} - accessibilityRole="image" - /> - ) : ( - - )} - - - - - )} - - - - {isNative && ( - - - Upload from Camera - - - - )} - - - - {isNative ? ( - Upload from Library - ) : ( - Upload from Files - )} - - - - - {!!avatar && ( - <> - - - - - Remove Avatar - - - - - - )} - - - ) -} -EditableUserAvatar = memo(EditableUserAvatar) -export {EditableUserAvatar} - -let PreviewableUserAvatar = ({ - moderation, - profile, - disableHoverCard, - onBeforePress, - ...rest -}: PreviewableUserAvatarProps): React.ReactNode => { - const {_} = useLingui() - const queryClient = useQueryClient() - - const onPress = React.useCallback(() => { - onBeforePress?.() - precacheProfile(queryClient, profile) - }, [profile, queryClient, onBeforePress]) - - return ( - - - - - - ) -} -PreviewableUserAvatar = memo(PreviewableUserAvatar) -export {PreviewableUserAvatar} - -// HACK -// We have started serving smaller avis but haven't updated lexicons to give the data properly -// manually string-replace to use the smaller ones -// -prf -function hackModifyThumbnailPath(uri: string, isEnabled: boolean): string { - return isEnabled -// ? uri.replace('/img/avatar/plain/', '/img/avatar_thumbnail/plain/') - ? uri.replace('https://cdn.bsky.app/img/avatar/plain/', 'https://bsky.syu.is/img/avatar/plain/') - : uri -} - -const styles = StyleSheet.create({ - editButtonContainer: { - position: 'absolute', - width: 24, - height: 24, - bottom: 0, - right: 0, - borderRadius: 12, - alignItems: 'center', - justifyContent: 'center', - backgroundColor: colors.gray5, - }, - alertIconContainer: { - position: 'absolute', - right: 0, - bottom: 0, - borderRadius: 100, - }, - alertIcon: { - color: colors.red3, - }, -}) diff --git a/install.zsh b/install.zsh index 6638e41..58823ba 100755 --- a/install.zsh +++ b/install.zsh @@ -194,19 +194,21 @@ run_update() { } web_write() { - echo $d/repos/social-app/src - cd $d/repos/social-app/src - grep -R bsky.social .|cut -d : -f 1|sort -u|xargs sed -i "s/bsky.social/syu.is/g" - grep -R bsky.app .|cut -d : -f 1|sort -u|xargs sed -i "s/bsky.app/web.syu.is/g" - grep -R public.api.syu.is ./lib/constants.ts | cut -d : -f 1|sort -u|xargs sed -i "s/public.api/bsky/g" + dt=$d/repos/social-app/src + cd $dt + grep -R bsky.social .|cut -d : -f 1|sort -u|xargs sed -i "s/bsky.social/syu.is/g" + grep -R bsky.app .|cut -d : -f 1|sort -u|xargs sed -i "s/bsky.app/web.syu.is/g" + grep -R public.api.syu.is ./lib/constants.ts | cut -d : -f 1|sort -u|xargs sed -i "s/public.api/bsky/g" - f=./view/icons/Logotype.tsx - o=$d/icons/Logotype.tsx - cp -rf $o $f + f=$dt/view/icons/Logotype.tsx + o=$d/icons/Logotype.tsx + cp -rf $o $f - f=./view/com/util/UserAvatar.tsx - o=$d/icons/UserAvatar.tsx - cp -rf $o $f + #curl -sL https://raw.githubusercontent.com/bluesky-social/social-app/refs/heads/main/src/view/com/util/UserAvatar.tsx -o $f + f=$dt/view/com/util/UserAvatar.tsx + sed -i $t "s#/img/avatar/plain/#https://cdn.bsky.app/img/avatar/plain/#g" $f + sed -i $t "s#/img/avatar_thumbnail/plain/#https://bsky.syu.is/img/avatar/plain/#g" $f + sed -i $t "s#source={{uri: avatar}}#source={{ uri: hackModifyThumbnailPath(avatar, 1 > 0), }}#g" $f } case $1 in diff --git a/repos/indigo b/repos/indigo new file mode 160000 index 0000000..c130614 --- /dev/null +++ b/repos/indigo @@ -0,0 +1 @@ +Subproject commit c130614850e554f9862d8e649373b53cee86dd3b diff --git a/repos/social-app b/repos/social-app deleted file mode 160000 index f6649e2..0000000 --- a/repos/social-app +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f6649e22a762fa8f4d3060da0a274f3b83ecb06f