mattermost-mobile/app/hooks/gallery.ts
Guillermo Vayá f024e00ca6
[MM-67056] Show actions on image gallery for android (#9386)
* show actions on image gallery for android

* use a constant, update dependencies

* use original window metrics if safe insets fail

* restore deps
2026-01-12 14:52:41 +01:00

125 lines
3.1 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {useCallback, useEffect} from 'react';
import {
Easing, runOnJS, useAnimatedRef, useAnimatedStyle,
useSharedValue,
withTiming, type WithTimingConfig,
} from 'react-native-reanimated';
import {useGallery} from '@context/gallery';
export function diff(context: any, name: string, value: any) {
'worklet';
if (!context.___diffs) {
context.___diffs = {};
}
if (!context.___diffs[name]) {
context.___diffs[name] = {
stash: 0,
prev: null,
};
}
const d = context.___diffs[name];
d.stash = d.prev === null ? 0 : value - d.prev;
d.prev = value;
return d.stash;
}
export const translateYConfig: WithTimingConfig = {
duration: 400,
easing: Easing.bezier(0.33, 0.01, 0, 1),
};
export function useGalleryControls(bottomInset = 0) {
const headerAndFooterHidden = useSharedValue(false);
const headerStyles = useAnimatedStyle(() => ({
opacity: headerAndFooterHidden.value ? withTiming(0) : withTiming(1),
transform: [
{
translateY: headerAndFooterHidden.value ? withTiming(-100, translateYConfig) : withTiming(0, translateYConfig),
},
],
position: 'absolute',
top: 0,
width: '100%',
zIndex: 1,
}));
const footerStyles = useAnimatedStyle(() => ({
opacity: headerAndFooterHidden.value ? withTiming(0) : withTiming(1),
transform: [
{
translateY: headerAndFooterHidden.value ? withTiming(100, translateYConfig) : withTiming(0, translateYConfig),
},
],
position: 'absolute',
bottom: bottomInset,
width: '100%',
zIndex: 1,
}), [bottomInset]);
const hideHeaderAndFooter = useCallback((hidden?: boolean) => {
'worklet';
if (hidden == null) {
// if we don't pass hidden, then we toggle the current value
headerAndFooterHidden.value = !headerAndFooterHidden.value;
return;
}
if (headerAndFooterHidden.value === hidden) {
return;
}
headerAndFooterHidden.value = hidden;
}, [headerAndFooterHidden]);
return {
headerAndFooterHidden,
headerStyles,
footerStyles,
hideHeaderAndFooter,
};
}
export function useGalleryItem(
identifier: string,
index: number,
onPress: (identifier: string, itemIndex: number) => void,
) {
const gallery = useGallery(identifier);
const ref = useAnimatedRef<any>();
const {opacity, activeIndex} = gallery.sharedValues;
const styles = useAnimatedStyle(() => {
return {
opacity: activeIndex.value === index ? opacity.value : 1,
};
}, []);
useEffect(() => {
gallery.registerItem(index, ref);
}, []);
const onGestureEvent = () => {
'worklet';
activeIndex.value = index;
runOnJS(onPress)(identifier, index);
};
return {
ref,
styles,
onGestureEvent,
};
}