about summary refs log tree commit diff
path: root/src/view/com/util/images
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com/util/images')
-rw-r--r--src/view/com/util/images/AutoSizedImage.tsx138
-rw-r--r--src/view/com/util/images/Image.tsx12
-rw-r--r--src/view/com/util/images/Image.web.tsx11
-rw-r--r--src/view/com/util/images/ImageHorzList.tsx2
-rw-r--r--src/view/com/util/images/ImageLayoutGrid.tsx36
-rw-r--r--src/view/com/util/images/constants.ts1
-rw-r--r--src/view/com/util/images/image-crop-picker/ImageCropPicker.tsx2
-rw-r--r--src/view/com/util/images/image-crop-picker/ImageCropPicker.web.tsx12
8 files changed, 92 insertions, 122 deletions
diff --git a/src/view/com/util/images/AutoSizedImage.tsx b/src/view/com/util/images/AutoSizedImage.tsx
index cdefc7123..0443c7be4 100644
--- a/src/view/com/util/images/AutoSizedImage.tsx
+++ b/src/view/com/util/images/AutoSizedImage.tsx
@@ -1,125 +1,59 @@
-import React, {useState, useEffect} from 'react'
-import {
-  Image,
-  ImageStyle,
-  LayoutChangeEvent,
-  StyleProp,
-  StyleSheet,
-  TouchableOpacity,
-  View,
-  ViewStyle,
-} from 'react-native'
-import {Text} from '../text/Text'
-import {useTheme} from '../../../lib/ThemeContext'
-import {usePalette} from '../../../lib/hooks/usePalette'
-import {DELAY_PRESS_IN} from './constants'
+import React from 'react'
+import {StyleProp, StyleSheet, TouchableOpacity, ViewStyle} from 'react-native'
+import Image, {OnLoadEvent} from 'view/com/util/images/Image'
+import {clamp} from 'lib/numbers'
 
-const MAX_HEIGHT = 300
-
-interface Dim {
-  width: number
-  height: number
-}
+export const DELAY_PRESS_IN = 500
+const MIN_ASPECT_RATIO = 0.33 // 1/3
+const MAX_ASPECT_RATIO = 5 // 5/1
 
 export function AutoSizedImage({
   uri,
   onPress,
   onLongPress,
+  onPressIn,
   style,
-  containerStyle,
+  children = null,
 }: {
   uri: string
   onPress?: () => void
   onLongPress?: () => void
-  style?: StyleProp<ImageStyle>
-  containerStyle?: StyleProp<ViewStyle>
+  onPressIn?: () => void
+  style?: StyleProp<ViewStyle>
+  children?: React.ReactNode
 }) {
-  const theme = useTheme()
-  const errPal = usePalette('error')
-  const [error, setError] = useState<string | undefined>('')
-  const [imgInfo, setImgInfo] = useState<Dim | undefined>()
-  const [containerInfo, setContainerInfo] = useState<Dim | undefined>()
-
-  useEffect(() => {
-    let aborted = false
-    if (!imgInfo) {
-      Image.getSize(
-        uri,
-        (width: number, height: number) => {
-          if (!aborted) {
-            setImgInfo({width, height})
-          }
-        },
-        (err: any) => {
-          if (!aborted) {
-            setError(String(err))
-          }
-        },
-      )
-    }
-    return () => {
-      aborted = true
-    }
-  }, [uri, imgInfo])
-
-  const onLayout = (evt: LayoutChangeEvent) => {
-    setContainerInfo({
-      width: evt.nativeEvent.layout.width,
-      height: evt.nativeEvent.layout.height,
-    })
-  }
-
-  let calculatedStyle: StyleProp<ImageStyle> | undefined
-  if (imgInfo && containerInfo) {
-    // imgInfo.height / imgInfo.width = x / containerInfo.width
-    // x = imgInfo.height / imgInfo.width * containerInfo.width
-    calculatedStyle = {
-      height: Math.min(
-        MAX_HEIGHT,
-        (imgInfo.height / imgInfo.width) * containerInfo.width,
+  const [aspectRatio, setAspectRatio] = React.useState<number>(1)
+  const onLoad = (e: OnLoadEvent) => {
+    setAspectRatio(
+      clamp(
+        e.nativeEvent.width / e.nativeEvent.height,
+        MIN_ASPECT_RATIO,
+        MAX_ASPECT_RATIO,
       ),
-    }
+    )
   }
-
   return (
-    <View style={style}>
-      <TouchableOpacity
-        onPress={onPress}
-        onLongPress={onLongPress}
-        delayPressIn={DELAY_PRESS_IN}>
-        {error ? (
-          <View style={[styles.errorContainer, errPal.view, containerStyle]}>
-            <Text style={errPal.text}>{error}</Text>
-          </View>
-        ) : calculatedStyle ? (
-          <View style={[styles.container, containerStyle]}>
-            <Image style={calculatedStyle} source={{uri}} />
-          </View>
-        ) : (
-          <View
-            style={[
-              style,
-              styles.placeholder,
-              {backgroundColor: theme.palette.default.backgroundLight},
-            ]}
-            onLayout={onLayout}
-          />
-        )}
-      </TouchableOpacity>
-    </View>
+    <TouchableOpacity
+      onPress={onPress}
+      onLongPress={onLongPress}
+      onPressIn={onPressIn}
+      delayPressIn={DELAY_PRESS_IN}
+      style={[styles.container, style]}>
+      <Image
+        style={[styles.image, {aspectRatio}]}
+        source={{uri}}
+        onLoad={onLoad}
+      />
+      {children}
+    </TouchableOpacity>
   )
 }
 
 const styles = StyleSheet.create({
-  placeholder: {
-    width: '100%',
-    aspectRatio: 1,
-  },
-  errorContainer: {
-    paddingHorizontal: 12,
-    paddingVertical: 8,
-  },
   container: {
     overflow: 'hidden',
   },
+  image: {
+    width: '100%',
+  },
 })
diff --git a/src/view/com/util/images/Image.tsx b/src/view/com/util/images/Image.tsx
new file mode 100644
index 000000000..8c95a581e
--- /dev/null
+++ b/src/view/com/util/images/Image.tsx
@@ -0,0 +1,12 @@
+import React from 'react'
+import FastImage, {FastImageProps, Source} from 'react-native-fast-image'
+export default FastImage
+export type {OnLoadEvent, ImageStyle, Source} from 'react-native-fast-image'
+
+export function HighPriorityImage({source, ...props}: FastImageProps) {
+  const updatedSource = {
+    uri: typeof source === 'object' && source ? source.uri : '',
+    priority: FastImage.priority.high,
+  } as Source
+  return <FastImage source={updatedSource} {...props} />
+}
diff --git a/src/view/com/util/images/Image.web.tsx b/src/view/com/util/images/Image.web.tsx
new file mode 100644
index 000000000..ecd9d730a
--- /dev/null
+++ b/src/view/com/util/images/Image.web.tsx
@@ -0,0 +1,11 @@
+import {
+  Image,
+  NativeSyntheticEvent,
+  ImageLoadEventData,
+  ImageSourcePropType,
+} from 'react-native'
+export default Image
+export const HighPriorityImage = Image
+export type OnLoadEvent = NativeSyntheticEvent<ImageLoadEventData>
+export type Source = ImageSourcePropType
+export type {ImageStyle} from 'react-native'
diff --git a/src/view/com/util/images/ImageHorzList.tsx b/src/view/com/util/images/ImageHorzList.tsx
index 366424308..bed13406c 100644
--- a/src/view/com/util/images/ImageHorzList.tsx
+++ b/src/view/com/util/images/ImageHorzList.tsx
@@ -1,12 +1,12 @@
 import React from 'react'
 import {
-  Image,
   StyleProp,
   StyleSheet,
   TouchableWithoutFeedback,
   View,
   ViewStyle,
 } from 'react-native'
+import Image from 'view/com/util/images/Image'
 
 export function ImageHorzList({
   uris,
diff --git a/src/view/com/util/images/ImageLayoutGrid.tsx b/src/view/com/util/images/ImageLayoutGrid.tsx
index 97ad9d700..a1c732649 100644
--- a/src/view/com/util/images/ImageLayoutGrid.tsx
+++ b/src/view/com/util/images/ImageLayoutGrid.tsx
@@ -1,7 +1,5 @@
 import React from 'react'
 import {
-  Image,
-  ImageStyle,
   LayoutChangeEvent,
   StyleProp,
   StyleSheet,
@@ -9,7 +7,9 @@ import {
   View,
   ViewStyle,
 } from 'react-native'
-import {DELAY_PRESS_IN} from './constants'
+import Image, {ImageStyle} from 'view/com/util/images/Image'
+
+export const DELAY_PRESS_IN = 500
 
 interface Dim {
   width: number
@@ -23,12 +23,14 @@ export function ImageLayoutGrid({
   uris,
   onPress,
   onLongPress,
+  onPressIn,
   style,
 }: {
   type: ImageLayoutGridType
   uris: string[]
   onPress?: (index: number) => void
   onLongPress?: (index: number) => void
+  onPressIn?: (index: number) => void
   style?: StyleProp<ViewStyle>
 }) {
   const [containerInfo, setContainerInfo] = React.useState<Dim | undefined>()
@@ -47,6 +49,7 @@ export function ImageLayoutGrid({
           type={type}
           uris={uris}
           onPress={onPress}
+          onPressIn={onPressIn}
           onLongPress={onLongPress}
           containerInfo={containerInfo}
         />
@@ -60,15 +63,17 @@ function ImageLayoutGridInner({
   uris,
   onPress,
   onLongPress,
+  onPressIn,
   containerInfo,
 }: {
   type: ImageLayoutGridType
   uris: string[]
   onPress?: (index: number) => void
   onLongPress?: (index: number) => void
+  onPressIn?: (index: number) => void
   containerInfo: Dim
 }) {
-  const size1 = React.useMemo<ImageStyle>(() => {
+  const size1 = React.useMemo<StyleProp<ImageStyle>>(() => {
     if (type === 'three') {
       const size = (containerInfo.width - 10) / 3
       return {width: size, height: size, resizeMode: 'cover', borderRadius: 4}
@@ -77,7 +82,7 @@ function ImageLayoutGridInner({
       return {width: size, height: size, resizeMode: 'cover', borderRadius: 4}
     }
   }, [type, containerInfo])
-  const size2 = React.useMemo<ImageStyle>(() => {
+  const size2 = React.useMemo<StyleProp<ImageStyle>>(() => {
     if (type === 'three') {
       const size = ((containerInfo.width - 10) / 3) * 2 + 5
       return {width: size, height: size, resizeMode: 'cover', borderRadius: 4}
@@ -93,6 +98,7 @@ function ImageLayoutGridInner({
         <TouchableOpacity
           delayPressIn={DELAY_PRESS_IN}
           onPress={() => onPress?.(0)}
+          onPressIn={() => onPressIn?.(0)}
           onLongPress={() => onLongPress?.(0)}>
           <Image source={{uri: uris[0]}} style={size1} />
         </TouchableOpacity>
@@ -100,6 +106,7 @@ function ImageLayoutGridInner({
         <TouchableOpacity
           delayPressIn={DELAY_PRESS_IN}
           onPress={() => onPress?.(1)}
+          onPressIn={() => onPressIn?.(1)}
           onLongPress={() => onLongPress?.(1)}>
           <Image source={{uri: uris[1]}} style={size1} />
         </TouchableOpacity>
@@ -112,6 +119,7 @@ function ImageLayoutGridInner({
         <TouchableOpacity
           delayPressIn={DELAY_PRESS_IN}
           onPress={() => onPress?.(0)}
+          onPressIn={() => onPressIn?.(0)}
           onLongPress={() => onLongPress?.(0)}>
           <Image source={{uri: uris[0]}} style={size2} />
         </TouchableOpacity>
@@ -120,6 +128,7 @@ function ImageLayoutGridInner({
           <TouchableOpacity
             delayPressIn={DELAY_PRESS_IN}
             onPress={() => onPress?.(1)}
+            onPressIn={() => onPressIn?.(1)}
             onLongPress={() => onLongPress?.(1)}>
             <Image source={{uri: uris[1]}} style={size1} />
           </TouchableOpacity>
@@ -127,6 +136,7 @@ function ImageLayoutGridInner({
           <TouchableOpacity
             delayPressIn={DELAY_PRESS_IN}
             onPress={() => onPress?.(2)}
+            onPressIn={() => onPressIn?.(2)}
             onLongPress={() => onLongPress?.(2)}>
             <Image source={{uri: uris[2]}} style={size1} />
           </TouchableOpacity>
@@ -141,29 +151,33 @@ function ImageLayoutGridInner({
           <TouchableOpacity
             delayPressIn={DELAY_PRESS_IN}
             onPress={() => onPress?.(0)}
+            onPressIn={() => onPressIn?.(0)}
             onLongPress={() => onLongPress?.(0)}>
             <Image source={{uri: uris[0]}} style={size1} />
           </TouchableOpacity>
           <View style={styles.hSpace} />
           <TouchableOpacity
             delayPressIn={DELAY_PRESS_IN}
-            onPress={() => onPress?.(1)}
-            onLongPress={() => onLongPress?.(1)}>
-            <Image source={{uri: uris[1]}} style={size1} />
+            onPress={() => onPress?.(2)}
+            onPressIn={() => onPressIn?.(2)}
+            onLongPress={() => onLongPress?.(2)}>
+            <Image source={{uri: uris[2]}} style={size1} />
           </TouchableOpacity>
         </View>
         <View style={styles.wSpace} />
         <View>
           <TouchableOpacity
             delayPressIn={DELAY_PRESS_IN}
-            onPress={() => onPress?.(2)}
-            onLongPress={() => onLongPress?.(2)}>
-            <Image source={{uri: uris[2]}} style={size1} />
+            onPress={() => onPress?.(1)}
+            onPressIn={() => onPressIn?.(1)}
+            onLongPress={() => onLongPress?.(1)}>
+            <Image source={{uri: uris[1]}} style={size1} />
           </TouchableOpacity>
           <View style={styles.hSpace} />
           <TouchableOpacity
             delayPressIn={DELAY_PRESS_IN}
             onPress={() => onPress?.(3)}
+            onPressIn={() => onPressIn?.(3)}
             onLongPress={() => onLongPress?.(3)}>
             <Image source={{uri: uris[3]}} style={size1} />
           </TouchableOpacity>
diff --git a/src/view/com/util/images/constants.ts b/src/view/com/util/images/constants.ts
deleted file mode 100644
index cb2c26cea..000000000
--- a/src/view/com/util/images/constants.ts
+++ /dev/null
@@ -1 +0,0 @@
-export const DELAY_PRESS_IN = 500
diff --git a/src/view/com/util/images/image-crop-picker/ImageCropPicker.tsx b/src/view/com/util/images/image-crop-picker/ImageCropPicker.tsx
index ddc9e87fd..d723fef99 100644
--- a/src/view/com/util/images/image-crop-picker/ImageCropPicker.tsx
+++ b/src/view/com/util/images/image-crop-picker/ImageCropPicker.tsx
@@ -4,7 +4,7 @@ import {
   openCropper as openCropperFn,
   ImageOrVideo,
 } from 'react-native-image-crop-picker'
-import {RootStoreModel} from '../../../../../state'
+import {RootStoreModel} from 'state/index'
 import {PickerOpts, CameraOpts, CropperOpts, PickedMedia} from './types'
 export type {PickedMedia} from './types'
 
diff --git a/src/view/com/util/images/image-crop-picker/ImageCropPicker.web.tsx b/src/view/com/util/images/image-crop-picker/ImageCropPicker.web.tsx
index a7037f3a4..d632590d6 100644
--- a/src/view/com/util/images/image-crop-picker/ImageCropPicker.web.tsx
+++ b/src/view/com/util/images/image-crop-picker/ImageCropPicker.web.tsx
@@ -1,9 +1,9 @@
 /// <reference lib="dom" />
 
-import {CropImageModal} from '../../../../../state/models/shell-ui'
+import {CropImageModal} from 'state/models/shell-ui'
 import {PickerOpts, CameraOpts, CropperOpts, PickedMedia} from './types'
 export type {PickedMedia} from './types'
-import {RootStoreModel} from '../../../../../state'
+import {RootStoreModel} from 'state/index'
 
 interface PickedFile {
   uri: string
@@ -31,17 +31,17 @@ export async function openPicker(
 
 export async function openCamera(
   _store: RootStoreModel,
-  opts: CameraOpts,
+  _opts: CameraOpts,
 ): Promise<PickedMedia> {
-  const mediaType = opts.mediaType || 'photo'
+  // const mediaType = opts.mediaType || 'photo' TODO
   throw new Error('TODO')
 }
 
 export async function openCropper(
   _store: RootStoreModel,
-  opts: CropperOpts,
+  _opts: CropperOpts,
 ): Promise<PickedMedia> {
-  const mediaType = opts.mediaType || 'photo'
+  // const mediaType = opts.mediaType || 'photo' TODO
   throw new Error('TODO')
 }