This repository has been archived on 2025-07-31. You can view files and clone it, but cannot push or open issues or pull requests.
Files
terminally-online/src/components/floatingActionButton.tsx
2023-07-29 22:43:58 +03:00

140 lines
3.8 KiB
TypeScript

import React, { useCallback, useEffect, useState } from 'react';
import { Keyboard, StyleSheet } from 'react-native';
import { FAB, Snackbar } from 'react-native-paper';
import { ParamListBase, useNavigation } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { pick } from 'react-native-document-picker';
import { useDeviceOrientation } from '@react-native-community/hooks';
import Clipboard from '@react-native-clipboard/clipboard';
import { documentPickerResponseToAddMemeFile, ROUTE } from '../types';
import {
allowedMimeTypes,
getFilenameFromUri,
guessMimeType,
noOp,
} from '../utilities';
const floatingActionButtonStyles = StyleSheet.create({
fab: {
paddingBottom: 90,
paddingRight: 10,
},
fabLandscape: {
paddingBottom: 40,
paddingRight: 12,
},
snackbar: {
marginBottom: 90,
},
});
const FloatingActionButton = ({ visible = true }: { visible?: boolean }) => {
const { navigate } =
useNavigation<NativeStackNavigationProp<ParamListBase>>();
const orientation = useDeviceOrientation();
const [state, setState] = useState(false);
const [keyboardOpen, setKeyboardOpen] = useState(false);
const [snackbarMessage, setSnackbarMessage] = useState<string>();
useEffect(() => {
const keyboardDidShowListener = Keyboard.addListener(
'keyboardDidShow',
() => setKeyboardOpen(true),
);
const keyboardDidHideListener = Keyboard.addListener(
'keyboardDidHide',
() => setKeyboardOpen(false),
);
return () => {
keyboardDidShowListener.remove();
keyboardDidHideListener.remove();
};
}, []);
const handleAddMeme = useCallback(async () => {
const response = await pick({
type: allowedMimeTypes,
allowMultiSelection: true,
}).catch(noOp);
if (!response) return;
const files = documentPickerResponseToAddMemeFile(response);
navigate(ROUTE.ADD_MEME, { files });
}, [navigate]);
const handleAddTag = useCallback(() => {
navigate(ROUTE.ADD_TAG);
}, [navigate]);
const handlePaste = useCallback(async () => {
const uri = await Clipboard.getURI();
if (!uri) {
setSnackbarMessage('Clipboard does not contain a URI.');
return;
}
const mimeType = guessMimeType(uri);
if (!mimeType) {
setSnackbarMessage('Unsupported MIME type.');
return;
}
navigate(ROUTE.ADD_MEME, {
files: [
{
uri: uri,
filename: getFilenameFromUri(uri),
type: mimeType,
},
],
});
}, [navigate]);
return (
<>
<FAB.Group
open={state}
visible={visible && !keyboardOpen}
icon={state ? 'close' : 'plus'}
actions={[
{
icon: 'content-paste',
label: 'Paste',
onPress: handlePaste,
},
{
icon: 'tag',
label: 'Tag',
onPress: handleAddTag,
},
{
icon: 'image',
label: 'Meme',
onPress: handleAddMeme,
},
]}
onStateChange={({ open }) => setState(open)}
style={
orientation === 'portrait'
? floatingActionButtonStyles.fab
: floatingActionButtonStyles.fabLandscape
}
/>
<Snackbar
visible={!!snackbarMessage}
// eslint-disable-next-line unicorn/no-useless-undefined
onDismiss={() => setSnackbarMessage(undefined)}
style={floatingActionButtonStyles.snackbar}
action={{
label: 'Dismiss',
// eslint-disable-next-line unicorn/no-useless-undefined
onPress: () => setSnackbarMessage(undefined),
}}>
{snackbarMessage}
</Snackbar>
</>
);
};
export default FloatingActionButton;