Add home screen state persistence

Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
2023-07-11 21:29:49 +03:00
parent 99195fe481
commit 5518fba787
11 changed files with 154 additions and 70 deletions

View File

@@ -10,10 +10,10 @@ import type {} from 'redux-thunk/extend-redux';
import { lightTheme, darkTheme } from './theme'; import { lightTheme, darkTheme } from './theme';
import { Meme, Tag } from './database'; import { Meme, Tag } from './database';
import NavigationContainer from './navigation'; import NavigationContainer from './navigation';
import { store, persistor, updateStorageUri, validateSettings } from './redux'; import { store, persistor, updateStorageUri, validateSettings } from './state';
import { LoadingView } from './components'; import { LoadingView } from './components';
import { Welcome } from './screens'; import { Welcome } from './screens';
import { noOp } from './constants'; import { noOp } from './utilities';
const App = () => { const App = () => {
const [showWelcome, setShowWelcome] = useState(false); const [showWelcome, setShowWelcome] = useState(false);
@@ -43,13 +43,13 @@ const App = () => {
}, []); }, []);
return ( return (
<Provider store={store}> <PaperProvider theme={theme}>
<PersistGate <Provider store={store}>
loading={<LoadingView />} <PersistGate
persistor={persistor} loading={<LoadingView />}
onBeforeLift={onBeforeLift}> persistor={persistor}
<RealmProvider schema={[Meme, Tag]}> onBeforeLift={onBeforeLift}>
<PaperProvider theme={theme}> <RealmProvider schema={[Meme, Tag]}>
<SafeAreaProvider> <SafeAreaProvider>
<StatusBar <StatusBar
barStyle={isDarkMode ? 'light-content' : 'dark-content'} barStyle={isDarkMode ? 'light-content' : 'dark-content'}
@@ -68,10 +68,10 @@ const App = () => {
<NavigationContainer /> <NavigationContainer />
)} )}
</SafeAreaProvider> </SafeAreaProvider>
</PaperProvider> </RealmProvider>
</RealmProvider> </PersistGate>
</PersistGate> </Provider>
</Provider> </PaperProvider>
); );
}; };

View File

@@ -7,37 +7,46 @@ import {
Divider, Divider,
useTheme, useTheme,
} from 'react-native-paper'; } from 'react-native-paper';
import { useDispatch, useSelector } from 'react-redux';
import { PaddedView } from '../components'; import { PaddedView } from '../components';
import styles, { verticalScale } from '../styles'; import styles, { verticalScale } from '../styles';
import { SORT, SORT_DIRECTION, VIEW } from '../types'; import { SORT, SORT_DIRECTION } from '../types';
import { getNextView, getSortIcon, getViewIcon } from '../utilities'; import { getSortIcon, getViewIcon } from '../utilities';
import {
RootState,
cycleView,
toggleSortDirection,
setSortDirection,
toggleFavoritesOnly,
setSort,
} from '../state';
const Home = () => { const Home = () => {
const theme = useTheme(); const theme = useTheme();
const sort = useSelector((state: RootState) => state.home.sort);
const sortDirection = useSelector(
(state: RootState) => state.home.sortDirection,
);
const view = useSelector((state: RootState) => state.home.view);
const favoritesOnly = useSelector(
(state: RootState) => state.home.favoritesOnly,
);
const dispatch = useDispatch();
const [sortMenuVisible, setSortMenuVisible] = useState(false); const [sortMenuVisible, setSortMenuVisible] = useState(false);
const [sort, setSort] = useState(SORT.TITLE);
const [sortDirection, setSortDirection] = useState(SORT_DIRECTION.ASCENDING);
const [viewType, setViewType] = useState(VIEW.MASONRY);
const [favoritesOnly, setFavoritesOnly] = useState(false);
const handleSortModeChange = (newSort: SORT) => { const handleSortModeChange = (newSort: SORT) => {
if (newSort === sort) { if (newSort === sort) {
setSortDirection( dispatch(toggleSortDirection());
sortDirection === SORT_DIRECTION.ASCENDING
? SORT_DIRECTION.DESCENDING
: SORT_DIRECTION.ASCENDING,
);
} else { } else {
setSort(newSort); dispatch(setSort(newSort));
if (newSort === SORT.TITLE) { if (newSort === SORT.TITLE) {
setSortDirection(SORT_DIRECTION.ASCENDING); dispatch(setSortDirection(SORT_DIRECTION.ASCENDING));
} else { } else {
setSortDirection(SORT_DIRECTION.DESCENDING); dispatch(setSortDirection(SORT_DIRECTION.DESCENDING));
} }
} }
setSortMenuVisible(false); setSortMenuVisible(false);
}; };
@@ -72,13 +81,13 @@ const Home = () => {
icon={favoritesOnly ? 'heart' : 'heart-outline'} icon={favoritesOnly ? 'heart' : 'heart-outline'}
iconColor={theme.colors.primary} iconColor={theme.colors.primary}
size={verticalScale(16)} size={verticalScale(16)}
onPress={() => setFavoritesOnly(!favoritesOnly)} onPress={() => dispatch(toggleFavoritesOnly())}
/> />
<IconButton <IconButton
icon={getViewIcon(viewType)} icon={getViewIcon(view)}
iconColor={theme.colors.primary} iconColor={theme.colors.primary}
size={verticalScale(16)} size={verticalScale(16)}
onPress={() => setViewType(getNextView(viewType))} onPress={() => dispatch(cycleView())}
/> />
</View> </View>
</View> </View>

View File

@@ -7,7 +7,7 @@ import { useDispatch, useSelector } from 'react-redux';
import { PaddedView } from '../components'; import { PaddedView } from '../components';
import styles from '../styles'; import styles from '../styles';
import { Meme } from '../database'; import { Meme } from '../database';
import { RootState, updateNoMedia, updateStorageUri } from '../redux'; import { RootState, updateNoMedia, updateStorageUri } from '../state';
import type {} from 'redux-thunk/extend-redux'; import type {} from 'redux-thunk/extend-redux';
const SettingsScreen = () => { const SettingsScreen = () => {

79
src/state/home.ts Normal file
View File

@@ -0,0 +1,79 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { SORT, SORT_DIRECTION, VIEW } from '../types';
interface HomeState {
sort: SORT;
sortDirection: SORT_DIRECTION;
view: VIEW;
favoritesOnly: boolean;
}
const initialState: HomeState = {
sort: SORT.TITLE,
sortDirection: SORT_DIRECTION.ASCENDING,
view: VIEW.MASONRY,
favoritesOnly: false,
};
const homeSlice = createSlice({
name: 'home',
initialState,
reducers: {
setSort: (state, action: PayloadAction<SORT>) => {
state.sort = action.payload;
},
setSortDirection: (state, action: PayloadAction<SORT_DIRECTION>) => {
state.sortDirection = action.payload;
},
toggleSortDirection: state => {
state.sortDirection ^= 1;
},
setView: (state, action: PayloadAction<VIEW>) => {
state.view = action.payload;
},
cycleView: state => {
switch (state.view) {
case VIEW.MASONRY: {
state.view = VIEW.LIST;
break;
}
case VIEW.LIST: {
state.view = VIEW.GRID;
break;
}
case VIEW.GRID: {
state.view = VIEW.MASONRY;
break;
}
}
},
setFavoritesOnly: (state, action: PayloadAction<boolean>) => {
state.favoritesOnly = action.payload;
},
toggleFavoritesOnly: state => {
state.favoritesOnly = !state.favoritesOnly;
},
},
});
const {
setSort,
setSortDirection,
toggleSortDirection,
setView,
cycleView,
setFavoritesOnly,
toggleFavoritesOnly,
} = homeSlice.actions;
export {
type HomeState,
setSort,
setSortDirection,
toggleSortDirection,
setView,
cycleView,
setFavoritesOnly,
toggleFavoritesOnly,
};
export default homeSlice.reducer;

View File

@@ -11,13 +11,16 @@ import {
} from 'redux-persist'; } from 'redux-persist';
import { createRealmPersistStorage } from '@bankify/redux-persist-realm'; import { createRealmPersistStorage } from '@bankify/redux-persist-realm';
import settingsReducer from './settings'; import settingsReducer from './settings';
import homeReducer from './home';
const rootReducer = combineReducers({ const rootReducer = combineReducers({
settings: settingsReducer, settings: settingsReducer,
home: homeReducer,
}); });
interface RootState { interface RootState {
settings: ReturnType<typeof settingsReducer>; settings: ReturnType<typeof settingsReducer>;
home: ReturnType<typeof homeReducer>;
} }
const persistConfig = { const persistConfig = {
@@ -46,3 +49,13 @@ export {
updateNoMedia, updateNoMedia,
validateSettings, validateSettings,
} from './settings'; } from './settings';
export {
type HomeState,
setSort,
setSortDirection,
toggleSortDirection,
setView,
cycleView,
setFavoritesOnly,
toggleFavoritesOnly,
} from './home';

View File

@@ -8,8 +8,8 @@ enum SORT {
} }
enum SORT_DIRECTION { enum SORT_DIRECTION {
ASCENDING = 'Ascending', ASCENDING = 0,
DESCENDING = 'Descending', DESCENDING = 1,
} }
export { SORT, SORT_DIRECTION }; export { SORT, SORT_DIRECTION };

View File

@@ -1,4 +1,4 @@
import { SORT, SORT_DIRECTION } from '../types'; import { SORT, SORT_DIRECTION, VIEW } from '../types';
const getSortIcon = (sort: SORT, sortDirection: SORT_DIRECTION) => { const getSortIcon = (sort: SORT, sortDirection: SORT_DIRECTION) => {
let sortIcon = ''; let sortIcon = '';
@@ -35,4 +35,18 @@ const getSortIcon = (sort: SORT, sortDirection: SORT_DIRECTION) => {
return sortIcon; return sortIcon;
}; };
export { getSortIcon }; const getViewIcon = (view: VIEW) => {
switch (view) {
case VIEW.MASONRY: {
return 'view-dashboard';
}
case VIEW.GRID: {
return 'view-grid';
}
case VIEW.LIST: {
return 'view-list';
}
}
};
export { getSortIcon, getViewIcon };

View File

@@ -1,3 +1,3 @@
export { packageName, appName, escapedAppName, noOp } from './constants';
export { isPermissionForPath, clearPermissions } from './permissions'; export { isPermissionForPath, clearPermissions } from './permissions';
export { getSortIcon } from './sort'; export { getSortIcon, getViewIcon } from './icon';
export { getViewIcon, getNextView } from './view';

View File

@@ -1,31 +0,0 @@
import { VIEW } from '../types';
const getViewIcon = (view: VIEW) => {
switch (view) {
case VIEW.MASONRY: {
return 'view-dashboard';
}
case VIEW.GRID: {
return 'view-grid';
}
case VIEW.LIST: {
return 'view-list';
}
}
};
const getNextView = (view: VIEW) => {
switch (view) {
case VIEW.MASONRY: {
return VIEW.GRID;
}
case VIEW.GRID: {
return VIEW.LIST;
}
case VIEW.LIST: {
return VIEW.MASONRY;
}
}
};
export { getViewIcon, getNextView };