mirror of
https://github.com/hanzo-io/team.git
synced 2026-10-30 18:56:23 +00:00
114 lines
3.4 KiB
TypeScript
114 lines
3.4 KiB
TypeScript
import { ImageMessage } from "@raven/types/common/Message";
|
|
import { UserFields } from "@raven/types/common/UserFields";
|
|
import { View } from "react-native";
|
|
import { Image } from "expo-image";
|
|
import useFileURL, { UseFileURLReturnType } from "@hooks/useFileURL";
|
|
import { Gesture, GestureDetector, TapGesture } from "react-native-gesture-handler";
|
|
import { runOnJS } from "react-native-reanimated";
|
|
import { router } from "expo-router";
|
|
import { useCallback, useMemo } from "react";
|
|
|
|
interface ImageMessageProps {
|
|
message: ImageMessage,
|
|
user?: UserFields,
|
|
doubleTapGesture: TapGesture
|
|
}
|
|
|
|
export const ImageMessageRenderer = ({ message, doubleTapGesture }: ImageMessageProps) => {
|
|
|
|
|
|
const { source, ...otherAttributes } = useGetImageAttributes(message)
|
|
|
|
const handleImagePress = useCallback(() => {
|
|
router.push({
|
|
pathname: './file-viewer',
|
|
params: { uri: source?.uri },
|
|
}, {
|
|
relativeToDirectory: true
|
|
})
|
|
}, [source?.uri])
|
|
|
|
/** Route to file viewer on single tap - but wait for double tap to fail */
|
|
const singleTapGesture = useMemo(() => {
|
|
return Gesture.Tap()
|
|
.numberOfTaps(1)
|
|
.hitSlop(10)
|
|
.onStart(() => {
|
|
runOnJS(handleImagePress)()
|
|
}).requireExternalGestureToFail(doubleTapGesture)
|
|
}, [handleImagePress, doubleTapGesture])
|
|
|
|
|
|
return (
|
|
<GestureDetector gesture={singleTapGesture}>
|
|
<View collapsable={false} className='flex-1 pt-0.5' style={{
|
|
width: otherAttributes.width,
|
|
height: otherAttributes.height,
|
|
}}>
|
|
<ImageMessageLayout source={source} {...otherAttributes} />
|
|
</View>
|
|
</GestureDetector>
|
|
)
|
|
|
|
}
|
|
|
|
const useGetImageAttributes = (message: ImageMessage) => {
|
|
const source = useFileURL(message.file)
|
|
const { width, height, alt, blurhash } = useMemo(() => {
|
|
const width = message?.thumbnail_width ? message?.thumbnail_width / 2 : 300
|
|
const height = message?.thumbnail_height ? message?.thumbnail_height / 2 : 200
|
|
const alt = `Image file sent by ${message.owner} at ${message.creation}`
|
|
|
|
return { width, height, alt, blurhash: message.blurhash }
|
|
}, [message])
|
|
|
|
return { source, width, height, alt, blurhash }
|
|
}
|
|
|
|
|
|
export const ImageMessageView = ({ message }: { message: ImageMessage }) => {
|
|
|
|
const attributes = useGetImageAttributes(message)
|
|
|
|
return <View
|
|
className="flex-row items-center pt-1 gap-1"
|
|
style={{
|
|
width: attributes.width,
|
|
height: attributes.height,
|
|
}}
|
|
>
|
|
<ImageMessageLayout {...attributes} />
|
|
</View>
|
|
|
|
|
|
}
|
|
|
|
const DEFAULT_BLURHASH = 'L1P%O.-;fQ-;~qj[fQj[%MfQfQfQ'
|
|
|
|
const ImageMessageLayout = ({ source, width, height, alt, blurhash = DEFAULT_BLURHASH }: { source?: UseFileURLReturnType, width: number, height: number, alt: string, blurhash?: string }) => {
|
|
|
|
return <View
|
|
className="flex-row items-center gap-1"
|
|
style={{
|
|
width: width,
|
|
height: height,
|
|
}}
|
|
>
|
|
|
|
<Image
|
|
source={source}
|
|
style={{
|
|
borderRadius: 8,
|
|
width: width,
|
|
height: height,
|
|
}}
|
|
placeholder={blurhash ? { blurhash, height, width } : undefined}
|
|
contentFit="cover"
|
|
transition={200}
|
|
alt={alt}
|
|
/>
|
|
|
|
|
|
|
|
</View>
|
|
} |