diff options
author | Aryan Goharzad <arrygoo@gmail.com> | 2023-01-25 18:25:34 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-25 17:25:34 -0600 |
commit | eb33c3fa812cc087db14a6b6ba743e982b26c462 (patch) | |
tree | d098f7a804c67755f39e95bbbfd56887bacf476c /src/view/com/lightbox/ImageViewing/utils.ts | |
parent | adf328b50ce98c5ebd3282fe897ddfdcd0de8011 (diff) | |
download | voidsky-eb33c3fa812cc087db14a6b6ba743e982b26c462.tar.zst |
Saves image on long press (#83)
* Saves image on long press * Adds save on long press * Forking lightbox * move to wrapper only to the bottom sheet to reduce impact of this change * lint * lint * lint * Use official `share` API * Clean up cache after download * comment * comment * Reduce swipe close velocity * Updates per feedback * lint * bugfix * Adds delayed press-in for TouchableOpacity
Diffstat (limited to 'src/view/com/lightbox/ImageViewing/utils.ts')
-rw-r--r-- | src/view/com/lightbox/ImageViewing/utils.ts | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/src/view/com/lightbox/ImageViewing/utils.ts b/src/view/com/lightbox/ImageViewing/utils.ts new file mode 100644 index 000000000..7fcdc84cf --- /dev/null +++ b/src/view/com/lightbox/ImageViewing/utils.ts @@ -0,0 +1,179 @@ +/** + * Copyright (c) JOB TODAY S.A. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + +import { + Animated, + GestureResponderEvent, + PanResponder, + PanResponderGestureState, + PanResponderInstance, + NativeTouchEvent, +} from 'react-native' +import {Dimensions, Position} from './@types' + +type CacheStorageItem = {key: string; value: any} + +export const createCache = (cacheSize: number) => ({ + _storage: [] as CacheStorageItem[], + get(key: string): any { + const {value} = + this._storage.find(({key: storageKey}) => storageKey === key) || {} + + return value + }, + set(key: string, value: any) { + if (this._storage.length >= cacheSize) { + this._storage.shift() + } + + this._storage.push({key, value}) + }, +}) + +export const splitArrayIntoBatches = (arr: any[], batchSize: number): any[] => + arr.reduce((result, item) => { + const batch = result.pop() || [] + + if (batch.length < batchSize) { + batch.push(item) + result.push(batch) + } else { + result.push(batch, [item]) + } + + return result + }, []) + +export const getImageTransform = ( + image: Dimensions | null, + screen: Dimensions, +) => { + if (!image?.width || !image?.height) { + return [] as const + } + + const wScale = screen.width / image.width + const hScale = screen.height / image.height + const scale = Math.min(wScale, hScale) + const {x, y} = getImageTranslate(image, screen) + + return [{x, y}, scale] as const +} + +export const getImageStyles = ( + image: Dimensions | null, + translate: Animated.ValueXY, + scale?: Animated.Value, +) => { + if (!image?.width || !image?.height) { + return {width: 0, height: 0} + } + + const transform = translate.getTranslateTransform() + + if (scale) { + transform.push({scale}, {perspective: new Animated.Value(1000)}) + } + + return { + width: image.width, + height: image.height, + transform, + } +} + +export const getImageTranslate = ( + image: Dimensions, + screen: Dimensions, +): Position => { + const getTranslateForAxis = (axis: 'x' | 'y'): number => { + const imageSize = axis === 'x' ? image.width : image.height + const screenSize = axis === 'x' ? screen.width : screen.height + + return (screenSize - imageSize) / 2 + } + + return { + x: getTranslateForAxis('x'), + y: getTranslateForAxis('y'), + } +} + +export const getImageDimensionsByTranslate = ( + translate: Position, + screen: Dimensions, +): Dimensions => ({ + width: screen.width - translate.x * 2, + height: screen.height - translate.y * 2, +}) + +export const getImageTranslateForScale = ( + currentTranslate: Position, + targetScale: number, + screen: Dimensions, +): Position => { + const {width, height} = getImageDimensionsByTranslate( + currentTranslate, + screen, + ) + + const targetImageDimensions = { + width: width * targetScale, + height: height * targetScale, + } + + return getImageTranslate(targetImageDimensions, screen) +} + +type HandlerType = ( + event: GestureResponderEvent, + state: PanResponderGestureState, +) => void + +type PanResponderProps = { + onGrant: HandlerType + onStart?: HandlerType + onMove: HandlerType + onRelease?: HandlerType + onTerminate?: HandlerType +} + +export const createPanResponder = ({ + onGrant, + onStart, + onMove, + onRelease, + onTerminate, +}: PanResponderProps): PanResponderInstance => + PanResponder.create({ + onStartShouldSetPanResponder: () => true, + onStartShouldSetPanResponderCapture: () => true, + onMoveShouldSetPanResponder: () => true, + onMoveShouldSetPanResponderCapture: () => true, + onPanResponderGrant: onGrant, + onPanResponderStart: onStart, + onPanResponderMove: onMove, + onPanResponderRelease: onRelease, + onPanResponderTerminate: onTerminate, + onPanResponderTerminationRequest: () => false, + onShouldBlockNativeResponder: () => false, + }) + +export const getDistanceBetweenTouches = ( + touches: NativeTouchEvent[], +): number => { + const [a, b] = touches + + if (a == null || b == null) { + return 0 + } + + return Math.sqrt( + Math.pow(a.pageX - b.pageX, 2) + Math.pow(a.pageY - b.pageY, 2), + ) +} |