Add root snackbar

Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
2023-07-29 23:11:00 +03:00
parent 5770a9b234
commit e794832f38
5 changed files with 67 additions and 70 deletions

View File

@@ -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<NativeStackNavigationProp<ParamListBase>>();
const orientation = useDeviceOrientation();
const keyboardOpen = useKeyboard().keyboardShown;
const dispatch = useDispatch();
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({
@@ -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
}
/>
<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>
</>
);
};

View File

@@ -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 = () => {
/>
</TabNavigatorBase.Navigator>
<FloatingActionButton visible={navVisible && route !== ROUTE.SETTINGS} />
<Snackbar
visible={!!snackbarMessage}
// eslint-disable-next-line unicorn/no-useless-undefined
onDismiss={() => 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}
</Snackbar>
</>
);
};

View File

@@ -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<string>();
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 = () => {
</List.Section>
</ScrollView>
<Portal>
<Portal>
<StorageLocationChangeDialog
visible={storageLocationChangeDialogVisible}
setVisible={setStorageLocationChangeDialogVisible}
setSnackbarMessage={setSnackbarMessage}
/>
</Portal>
<Snackbar
visible={!!snackbarMessage}
// eslint-disable-next-line unicorn/no-useless-undefined
onDismiss={() => setSnackbarMessage(undefined)}
style={settingsStyles.snackbar}
action={{
label: 'Dismiss',
// eslint-disable-next-line unicorn/no-useless-undefined
onPress: () => setSnackbarMessage(undefined),
}}>
{snackbarMessage}
</Snackbar>
<StorageLocationChangeDialog
visible={storageLocationChangeDialogVisible}
setVisible={setStorageLocationChangeDialogVisible}
setSnackbarMessage={message => {
dispatch(setSnackbarMessage(message));
}}
/>
</Portal>
</>
);

View File

@@ -79,4 +79,5 @@ export {
type NavigationState,
setNavVisible,
toggleNavVisible,
setSnackbarMessage,
} from './navigation';

View File

@@ -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<string | undefined>) => {
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;