about summary refs log tree commit diff
path: root/src/view
diff options
context:
space:
mode:
authorhailey <me@haileyok.com>2025-05-06 10:54:08 -0700
committerGitHub <noreply@github.com>2025-05-06 10:54:08 -0700
commit521ec8e044e58633530e1864e7abc6e22554d7d3 (patch)
treee57139a4cfcb9f8859f5e1af008740fc3e8306e3 /src/view
parent973538d246a3f76550611e438152f1a6cad75f49 (diff)
downloadvoidsky-521ec8e044e58633530e1864e7abc6e22554d7d3.tar.zst
swap out cropper library (#8327)
* mostly implement

* type errors

* unused import

* rm comment

* stop accidentally deleting the image while compressing

* upgrade

* type fixes

* upgrade, remove timeout

* bump

* rm mock

* bump

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
Diffstat (limited to 'src/view')
-rw-r--r--src/view/com/composer/photos/OpenCameraBtn.tsx4
-rw-r--r--src/view/com/modals/CreateOrEditList.tsx6
-rw-r--r--src/view/com/modals/CropImage.web.tsx6
-rw-r--r--src/view/com/modals/EditProfile.tsx10
-rw-r--r--src/view/com/util/UserAvatar.tsx31
-rw-r--r--src/view/com/util/UserBanner.tsx20
6 files changed, 36 insertions, 41 deletions
diff --git a/src/view/com/composer/photos/OpenCameraBtn.tsx b/src/view/com/composer/photos/OpenCameraBtn.tsx
index fb3ab5c8f..1c9440eb1 100644
--- a/src/view/com/composer/photos/OpenCameraBtn.tsx
+++ b/src/view/com/composer/photos/OpenCameraBtn.tsx
@@ -35,9 +35,7 @@ export function OpenCameraBtn({disabled, onAdd}: Props) {
       }
 
       const img = await openCamera({
-        width: POST_IMG_MAX.width,
-        height: POST_IMG_MAX.height,
-        freeStyleCropEnabled: true,
+        aspect: [POST_IMG_MAX.width, POST_IMG_MAX.height],
       })
 
       // If we don't have permissions it's fine, we just wont save it. The post itself will still have access to
diff --git a/src/view/com/modals/CreateOrEditList.tsx b/src/view/com/modals/CreateOrEditList.tsx
index 0e4e23b97..a7eae15dd 100644
--- a/src/view/com/modals/CreateOrEditList.tsx
+++ b/src/view/com/modals/CreateOrEditList.tsx
@@ -8,7 +8,6 @@ import {
   TouchableOpacity,
   View,
 } from 'react-native'
-import {type Image as RNImage} from 'react-native-image-crop-picker'
 import {LinearGradient} from 'expo-linear-gradient'
 import {type AppBskyGraphDefs, RichText as RichTextAPI} from '@atproto/api'
 import {msg, Trans} from '@lingui/macro'
@@ -17,6 +16,7 @@ import {useLingui} from '@lingui/react'
 import {usePalette} from '#/lib/hooks/usePalette'
 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
 import {compressIfNeeded} from '#/lib/media/manip'
+import {type PickerImage} from '#/lib/media/picker.shared'
 import {cleanError, isNetworkError} from '#/lib/strings/errors'
 import {enforceLen} from '#/lib/strings/helpers'
 import {richTextToString} from '#/lib/strings/rich-text-helpers'
@@ -95,7 +95,7 @@ export function Component({
   const isDescriptionOver = graphemeLength > MAX_DESCRIPTION
 
   const [avatar, setAvatar] = useState<string | undefined>(list?.avatar)
-  const [newAvatar, setNewAvatar] = useState<RNImage | undefined | null>()
+  const [newAvatar, setNewAvatar] = useState<PickerImage | undefined | null>()
 
   const onDescriptionChange = useCallback(
     (newText: string) => {
@@ -112,7 +112,7 @@ export function Component({
   }, [closeModal])
 
   const onSelectNewAvatar = useCallback(
-    async (img: RNImage | null) => {
+    async (img: PickerImage | null) => {
       if (!img) {
         setNewAvatar(null)
         setAvatar(undefined)
diff --git a/src/view/com/modals/CropImage.web.tsx b/src/view/com/modals/CropImage.web.tsx
index 41ca30657..78c0466f0 100644
--- a/src/view/com/modals/CropImage.web.tsx
+++ b/src/view/com/modals/CropImage.web.tsx
@@ -1,14 +1,14 @@
 import React from 'react'
 import {StyleSheet, TouchableOpacity, View} from 'react-native'
-import {Image as RNImage} from 'react-native-image-crop-picker'
 import {manipulateAsync, SaveFormat} from 'expo-image-manipulator'
 import {LinearGradient} from 'expo-linear-gradient'
 import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
-import ReactCrop, {PercentCrop} from 'react-image-crop'
+import ReactCrop, {type PercentCrop} from 'react-image-crop'
 
 import {usePalette} from '#/lib/hooks/usePalette'
 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
+import {type PickerImage} from '#/lib/media/picker.shared'
 import {getDataUriSize} from '#/lib/media/util'
 import {gradients, s} from '#/lib/styles'
 import {useModalControls} from '#/state/modals'
@@ -25,7 +25,7 @@ export function Component({
   uri: string
   aspect?: number
   circular?: boolean
-  onSelect: (img?: RNImage) => void
+  onSelect: (img?: PickerImage) => void
 }) {
   const pal = usePalette('default')
   const {_} = useLingui()
diff --git a/src/view/com/modals/EditProfile.tsx b/src/view/com/modals/EditProfile.tsx
index ebc1281a3..cb1552fe5 100644
--- a/src/view/com/modals/EditProfile.tsx
+++ b/src/view/com/modals/EditProfile.tsx
@@ -8,7 +8,6 @@ import {
   TouchableOpacity,
   View,
 } from 'react-native'
-import {type Image as RNImage} from 'react-native-image-crop-picker'
 import Animated, {FadeOut} from 'react-native-reanimated'
 import {LinearGradient} from 'expo-linear-gradient'
 import {type AppBskyActorDefs} from '@atproto/api'
@@ -18,6 +17,7 @@ import {useLingui} from '@lingui/react'
 import {MAX_DESCRIPTION, MAX_DISPLAY_NAME, urls} from '#/lib/constants'
 import {usePalette} from '#/lib/hooks/usePalette'
 import {compressIfNeeded} from '#/lib/media/manip'
+import {type PickerImage} from '#/lib/media/picker.shared'
 import {cleanError} from '#/lib/strings/errors'
 import {enforceLen} from '#/lib/strings/helpers'
 import {colors, gradients, s} from '#/lib/styles'
@@ -67,16 +67,16 @@ export function Component({
     profile.avatar,
   )
   const [newUserBanner, setNewUserBanner] = useState<
-    RNImage | undefined | null
+    PickerImage | undefined | null
   >()
   const [newUserAvatar, setNewUserAvatar] = useState<
-    RNImage | undefined | null
+    PickerImage | undefined | null
   >()
   const onPressCancel = () => {
     closeModal()
   }
   const onSelectNewAvatar = useCallback(
-    async (img: RNImage | null) => {
+    async (img: PickerImage | null) => {
       setImageError('')
       if (img === null) {
         setNewUserAvatar(null)
@@ -95,7 +95,7 @@ export function Component({
   )
 
   const onSelectNewBanner = useCallback(
-    async (img: RNImage | null) => {
+    async (img: PickerImage | null) => {
       setImageError('')
       if (!img) {
         setNewUserBanner(null)
diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx
index 20fc1c65d..2450c111b 100644
--- a/src/view/com/util/UserAvatar.tsx
+++ b/src/view/com/util/UserAvatar.tsx
@@ -2,14 +2,13 @@ import React, {memo, useMemo} from 'react'
 import {
   Image,
   Pressable,
-  StyleProp,
+  type StyleProp,
   StyleSheet,
   View,
-  ViewStyle,
+  type ViewStyle,
 } from 'react-native'
-import {Image as RNImage} from 'react-native-image-crop-picker'
 import Svg, {Circle, Path, Rect} from 'react-native-svg'
-import {ModerationUI} from '@atproto/api'
+import {type ModerationUI} from '@atproto/api'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
@@ -38,8 +37,13 @@ import {Link} from '#/components/Link'
 import {MediaInsetBorder} from '#/components/MediaInsetBorder'
 import * as Menu from '#/components/Menu'
 import {ProfileHoverCard} from '#/components/ProfileHoverCard'
-import * as bsky from '#/types/bsky'
-import {openCamera, openCropper, openPicker} from '../../../lib/media/picker'
+import type * as bsky from '#/types/bsky'
+import {
+  openCamera,
+  openCropper,
+  openPicker,
+  type RNImage,
+} from '../../../lib/media/picker'
 
 export type UserAvatarType = 'user' | 'algo' | 'list' | 'labeler'
 
@@ -312,9 +316,7 @@ let EditableUserAvatar = ({
 
     onSelectNewAvatar(
       await openCamera({
-        width: 1000,
-        height: 1000,
-        cropperCircleOverlay: true,
+        aspect: [1, 1],
       }),
     )
   }, [onSelectNewAvatar, requestCameraAccessIfNeeded])
@@ -336,15 +338,10 @@ let EditableUserAvatar = ({
 
     try {
       const croppedImage = await openCropper({
-        mediaType: 'photo',
-        cropperCircleOverlay: true,
-        height: 1000,
-        width: 1000,
-        path: item.path,
-        webAspectRatio: 1,
-        webCircularCrop: true,
+        imageUri: item.path,
+        shape: 'circle',
+        aspectRatio: 1,
       })
-
       onSelectNewAvatar(croppedImage)
     } catch (e: any) {
       // Don't log errors for cancelling selection to sentry on ios or android
diff --git a/src/view/com/util/UserBanner.tsx b/src/view/com/util/UserBanner.tsx
index e0ace5e48..ab7f25b80 100644
--- a/src/view/com/util/UserBanner.tsx
+++ b/src/view/com/util/UserBanner.tsx
@@ -1,8 +1,7 @@
 import React from 'react'
 import {Pressable, StyleSheet, View} from 'react-native'
-import {Image as RNImage} from 'react-native-image-crop-picker'
 import {Image} from 'expo-image'
-import {ModerationUI} from '@atproto/api'
+import {type ModerationUI} from '@atproto/api'
 import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
@@ -25,7 +24,12 @@ import {
 import {StreamingLive_Stroke2_Corner0_Rounded as Library} from '#/components/icons/StreamingLive'
 import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash'
 import * as Menu from '#/components/Menu'
-import {openCamera, openCropper, openPicker} from '../../../lib/media/picker'
+import {
+  openCamera,
+  openCropper,
+  openPicker,
+  type RNImage,
+} from '../../../lib/media/picker'
 
 export function UserBanner({
   type,
@@ -52,8 +56,7 @@ export function UserBanner({
     }
     onSelectNewBanner?.(
       await openCamera({
-        width: 3000,
-        height: 1000,
+        aspect: [3, 1],
       }),
     )
   }, [onSelectNewBanner, requestCameraAccessIfNeeded])
@@ -70,11 +73,8 @@ export function UserBanner({
     try {
       onSelectNewBanner?.(
         await openCropper({
-          mediaType: 'photo',
-          path: items[0].path,
-          width: 3000,
-          height: 1000,
-          webAspectRatio: 3,
+          imageUri: items[0].path,
+          aspectRatio: 3 / 1,
         }),
       )
     } catch (e: any) {