diff --git a/src/components/floatingActionButton.tsx b/src/components/floatingActionButton.tsx index fe176ec..0e0d748 100644 --- a/src/components/floatingActionButton.tsx +++ b/src/components/floatingActionButton.tsx @@ -1,10 +1,13 @@ -import React, { useCallback, useEffect, useState } from 'react'; -import { Keyboard, StyleSheet } from 'react-native'; -import { FAB, Snackbar } from 'react-native-paper'; +import React, { useCallback, useState } from 'react'; +import { StyleSheet } from 'react-native'; +import { FAB } 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 { + useDeviceOrientation, + useKeyboard, +} from '@react-native-community/hooks'; import Clipboard from '@react-native-clipboard/clipboard'; import { documentPickerResponseToAddMemeFile, ROUTE } from '../types'; import { @@ -13,6 +16,8 @@ import { guessMimeType, noOp, } from '../utilities'; +import { useDispatch } from 'react-redux'; +import { setSnackbarMessage } from '../state'; const floatingActionButtonStyles = StyleSheet.create({ fab: { @@ -23,36 +28,16 @@ const floatingActionButtonStyles = StyleSheet.create({ paddingBottom: 40, paddingRight: 12, }, - snackbar: { - marginBottom: 90, - }, }); const FloatingActionButton = ({ visible = true }: { visible?: boolean }) => { const { navigate } = useNavigation>(); const orientation = useDeviceOrientation(); + const keyboardOpen = useKeyboard().keyboardShown; + const dispatch = useDispatch(); const [state, setState] = useState(false); - const [keyboardOpen, setKeyboardOpen] = useState(false); - - const [snackbarMessage, setSnackbarMessage] = useState(); - - 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({ @@ -71,12 +56,12 @@ const FloatingActionButton = ({ visible = true }: { visible?: boolean }) => { const handlePaste = useCallback(async () => { const uri = await Clipboard.getURI(); if (!uri) { - setSnackbarMessage('Clipboard does not contain a URI.'); + dispatch(setSnackbarMessage('Clipboard does not contain a URI.')); return; } const mimeType = guessMimeType(uri); if (!mimeType) { - setSnackbarMessage('Unsupported MIME type.'); + dispatch(setSnackbarMessage('Unsupported MIME type.')); return; } navigate(ROUTE.ADD_MEME, { @@ -88,7 +73,7 @@ const FloatingActionButton = ({ visible = true }: { visible?: boolean }) => { }, ], }); - }, [navigate]); + }, [dispatch, navigate]); return ( <> @@ -120,18 +105,6 @@ const FloatingActionButton = ({ visible = true }: { visible?: boolean }) => { : floatingActionButtonStyles.fabLandscape } /> - setSnackbarMessage(undefined)} - style={floatingActionButtonStyles.snackbar} - action={{ - label: 'Dismiss', - // eslint-disable-next-line unicorn/no-useless-undefined - onPress: () => setSnackbarMessage(undefined), - }}> - {snackbarMessage} - ); }; diff --git a/src/navigation.tsx b/src/navigation.tsx index b2ffcc0..36e8440 100644 --- a/src/navigation.tsx +++ b/src/navigation.tsx @@ -7,8 +7,8 @@ import { import FontAwesome5 from 'react-native-vector-icons/FontAwesome5'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; -import { useTheme } from 'react-native-paper'; -import { useSelector } from 'react-redux'; +import { Snackbar, useTheme } from 'react-native-paper'; +import { useDispatch, useSelector } from 'react-redux'; import { Memes, Tags, @@ -32,11 +32,28 @@ import { } from './types'; import { RootState } from './state'; import ShareMenu from 'react-native-share-menu'; +import { setSnackbarMessage } from './state/navigation'; +import { StyleSheet } from 'react-native'; +import { useKeyboard } from '@react-native-community/hooks'; + +const tabNavigatorStyles = StyleSheet.create({ + snackbar: { + marginBottom: 90, + }, + snackbarKeyboard: { + marginBottom: 10, + }, +}); const TabNavigator = () => { const navVisible = useSelector( (state: RootState) => state.navigation.navVisible, ); + const snackbarMessage = useSelector( + (state: RootState) => state.navigation.snackbarMessage, + ); + const dispatch = useDispatch(); + const keyboardOpen = useKeyboard().keyboardShown; const [route, setRoute] = React.useState(ROUTE.MEMES); const TabNavigatorBase = createBottomTabNavigator(); @@ -87,6 +104,22 @@ const TabNavigator = () => { /> + dispatch(setSnackbarMessage(undefined))} + style={ + keyboardOpen + ? tabNavigatorStyles.snackbarKeyboard + : tabNavigatorStyles.snackbar + } + action={{ + label: 'Dismiss', + // eslint-disable-next-line unicorn/no-useless-undefined + onPress: () => dispatch(setSnackbarMessage(undefined)), + }}> + {snackbarMessage} + ); }; diff --git a/src/screens/settings.tsx b/src/screens/settings.tsx index 3391bde..0487257 100644 --- a/src/screens/settings.tsx +++ b/src/screens/settings.tsx @@ -5,7 +5,6 @@ import { List, Portal, SegmentedButtons, - Snackbar, Switch, Text, useTheme, @@ -17,6 +16,7 @@ import { setGridColumns, setMasonryColumns, setNoMedia, + setSnackbarMessage, } from '../state'; import StorageLocationChangeDialog from '../components/storageLocationChangeDialog'; import { useRealm } from '@realm/react'; @@ -27,9 +27,6 @@ const settingsStyles = StyleSheet.create({ scrollView: { paddingHorizontal: '4%', }, - snackbar: { - marginBottom: 90, - }, marginBottom: { marginBottom: 15, }, @@ -60,8 +57,6 @@ const Settings = () => { const dispatch = useDispatch(); const realm = useRealm(); - const [snackbarMessage, setSnackbarMessage] = useState(); - const [ storageLocationChangeDialogVisible, setStorageLocationChangeDialogVisible, @@ -82,7 +77,7 @@ const Settings = () => { }); }); - setSnackbarMessage('Meme metadata refreshed.'); + dispatch(setSnackbarMessage('Meme metadata refreshed.')); }; return ( @@ -156,25 +151,13 @@ const Settings = () => { - - - - setSnackbarMessage(undefined)} - style={settingsStyles.snackbar} - action={{ - label: 'Dismiss', - // eslint-disable-next-line unicorn/no-useless-undefined - onPress: () => setSnackbarMessage(undefined), - }}> - {snackbarMessage} - + { + dispatch(setSnackbarMessage(message)); + }} + /> ); diff --git a/src/state/index.ts b/src/state/index.ts index 44208bc..89dc8c2 100644 --- a/src/state/index.ts +++ b/src/state/index.ts @@ -79,4 +79,5 @@ export { type NavigationState, setNavVisible, toggleNavVisible, + setSnackbarMessage, } from './navigation'; diff --git a/src/state/navigation.ts b/src/state/navigation.ts index c45e133..c20f949 100644 --- a/src/state/navigation.ts +++ b/src/state/navigation.ts @@ -2,10 +2,12 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; interface NavigationState { navVisible: boolean; + snackbarMessage: string | undefined; } const initialState: NavigationState = { navVisible: true, + snackbarMessage: undefined, }; const navigationSlice = createSlice({ @@ -18,14 +20,19 @@ const navigationSlice = createSlice({ toggleNavVisible: state => { state.navVisible = !state.navVisible; }, + setSnackbarMessage: (state, action: PayloadAction) => { + state.snackbarMessage = action.payload; + }, }, }); -const { setNavVisible, toggleNavVisible } = navigationSlice.actions; +const { setNavVisible, toggleNavVisible, setSnackbarMessage } = + navigationSlice.actions; export { type NavigationState, setNavVisible, toggleNavVisible, + setSnackbarMessage, }; export default navigationSlice.reducer;