mattermost-mobile-upstream/app/screens/gallery/index.tsx
Carlos Garcia b9aee2b803
Mm 68768 auto cache rolling cleanup (#9958)
* auto cache rolling cleanup for posts

* ai threads rolling cleanup

* auto rolling cleanup of playbook runs

* fix to import and use renamed module

* makes post cleanup atomic by moving processing to sql layer

* restore previous file viewer post id and use full error logging

* performs vacuum as last step and removes unused code

* return early on empty channel array

* address gallery items without a post id

* prevent drafts to be deleted as part of auto cache cleanups

* unset channel oldest visible on channel switch

* clear oldest visible on empty array

* revert early return to prevent flickering

* restore previous playbookrun id on unmount

* fixes issue creating data retention deletion batches

* move active threads root cleanup protection to SQL execution

* notify observers of range changes in post lists

* in flight protection for auto cache cleanup runs

* add space around operator

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* use bound args while composing SQL for post deletes

* support for NaN when parsing ephemeral mode settings and refactor cleanup processing

* run updates through the model layer so cached values and observers are synced

* keep draft root posts on cleanups

* execute cleanups sequentially during launch and join db vacuum

add some more test coverage for cleanups and fixes

* apply PR suggestions

* use serverUrl to get database in cleanupPosts

* use operator handlers when possible in tests

* addresses coderabbit comments

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-09-03 12:46:19 +02:00

114 lines
3.6 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useCallback, useEffect, useRef, useState} from 'react';
import {DeviceEventEmitter, View} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {Events, Screens} from '@constants';
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
import {useWindowDimensions} from '@hooks/device';
import useDidMount from '@hooks/did_mount';
import {useGalleryControls} from '@hooks/gallery';
import {navigateBack} from '@screens/navigation';
import EphemeralStore from '@store/ephemeral_store';
import Footer from './footer';
import Gallery, {type GalleryRef} from './gallery';
import Header from './header';
import type {GalleryItemType} from '@typings/screens/gallery';
export type GalleryProps = {
galleryIdentifier: string;
hideActions: boolean;
initialIndex: number;
items: GalleryItemType[];
}
const GalleryScreen = ({galleryIdentifier, hideActions, initialIndex, items}: GalleryProps) => {
const dim = useWindowDimensions();
const {bottom: bottomInset} = useSafeAreaInsets();
const [localIndex, setLocalIndex] = useState(initialIndex);
useDidMount(() => {
const previousPostId = EphemeralStore.getCurrentFileViewerPostId();
const postId = items[initialIndex]?.postId;
if (postId) {
EphemeralStore.setCurrentFileViewerPostId(postId);
} else {
EphemeralStore.clearCurrentFileViewerPostId();
}
return () => EphemeralStore.setCurrentFileViewerPostId(previousPostId);
});
const {headerAndFooterHidden, hideHeaderAndFooter, headerStyles, footerStyles} = useGalleryControls(bottomInset);
const galleryRef = useRef<GalleryRef>(null);
const containerStyle = dim;
const onClose = useCallback(() => {
requestAnimationFrame(() => {
hideHeaderAndFooter();
galleryRef.current?.close();
});
}, [hideHeaderAndFooter]);
const close = useCallback(() => {
requestAnimationFrame(async () => {
navigateBack();
});
}, []);
const onIndexChange = useCallback((index: number) => {
setLocalIndex(index);
const postId = items[index]?.postId;
if (postId) {
EphemeralStore.setCurrentFileViewerPostId(postId);
} else {
EphemeralStore.clearCurrentFileViewerPostId();
}
}, [items]);
useEffect(() => {
const listener = DeviceEventEmitter.addListener(Events.CLOSE_GALLERY, () => {
onClose();
});
return () => {
listener.remove();
};
}, [onClose]);
useAndroidHardwareBackHandler(Screens.GALLERY, close);
return (
<View style={containerStyle}>
<Header
index={localIndex}
onClose={onClose}
style={headerStyles}
total={items.length}
/>
<Gallery
headerAndFooterHidden={headerAndFooterHidden}
galleryIdentifier={galleryIdentifier}
initialIndex={initialIndex}
items={items}
onHide={close}
onIndexChange={onIndexChange}
hideHeaderAndFooter={hideHeaderAndFooter}
ref={galleryRef}
targetDimensions={dim}
/>
<Footer
hideActions={hideActions}
item={items[localIndex]}
style={footerStyles}
/>
</View>
);
};
export default GalleryScreen;