Files
lnreader/src/screens/Library/Library.js
T
Rajarshee Chatterjee 7c4da7f761 Refactor (#82)
2021-10-02 15:21:56 +05:30

302 lines
8.4 KiB
JavaScript

import React, {useState, useCallback, useRef, useEffect} from 'react';
import {
StyleSheet,
Text,
View,
RefreshControl,
ActivityIndicator,
Pressable,
} from 'react-native';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import {useFocusEffect} from '@react-navigation/native';
import {useSelector, useDispatch} from 'react-redux';
import * as Haptics from 'expo-haptics';
import {Searchbar} from '../../components/Searchbar/Searchbar';
import NovelList from '../../components/NovelList';
import NovelCover from '../../components/NovelCover';
import EmptyView from '../../components/EmptyView';
import {
getLibraryAction,
searchLibraryAction,
} from '../../redux/library/library.actions';
import {updateLibraryAction} from '../../redux/updates/updates.actions';
import {useSettings, useTheme} from '../../hooks/reduxHooks';
import {setNovel} from '../../redux/novel/novel.actions';
import {Portal} from 'react-native-paper';
import LibraryBottomSheet from './components/LibraryBottomSheet';
import {Actionbar} from '../../components/Actionbar/Actionbar';
import {
markAllChaptersRead,
markAllChaptersUnread,
} from '../../database/queries/ChapterQueries';
import {unfollowNovel} from '../../database/queries/NovelQueries';
const LibraryScreen = ({navigation}) => {
const theme = useTheme();
const dispatch = useDispatch();
const settings = useSettings();
const {
showNumberOfNovels,
incognitoMode = false,
updateLibraryOnLaunch = false,
downloadedOnlyMode = false,
} = settings;
const libraryBottomSheetRef = useRef(null);
const {
loading,
novels,
filters: {sort, filter},
} = useSelector(state => state.libraryReducer);
const [refreshing, setRefreshing] = useState(false);
const [searchText, setSearchText] = useState('');
useFocusEffect(
useCallback(() => {
setSearchText('');
dispatch(getLibraryAction(sort, filter));
}, [getLibraryAction, sort, filter]),
);
useEffect(() => {
updateLibraryOnLaunch && dispatch(updateLibraryAction());
}, []);
const onRefresh = () => {
setRefreshing(true);
dispatch(updateLibraryAction());
setRefreshing(false);
};
const clearSearchbar = () => {
dispatch(getLibraryAction(sort, filter));
setSearchText('');
};
const onChangeText = text => {
setSearchText(text);
dispatch(searchLibraryAction(text, sort, filter));
};
/**
* Selected Novels
*/
const [selectedNovels, setSelectedNovels] = useState([]);
const selectNovel = novelId => {
if (selectedNovels.indexOf(novelId) === -1) {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
setSelectedNovels(prevState => [...prevState, novelId]);
} else {
setSelectedNovels(prevState => prevState.filter(id => id !== novelId));
}
};
const renderItem = ({item}) => (
<NovelCover
item={item}
onPress={() => {
navigation.navigate('Novel', item);
dispatch(setNovel(item));
}}
theme={theme}
onLongPress={selectNovel}
isSelected={selectedNovels.indexOf(item.novelId) === -1 ? false : true}
selectedNovels={selectedNovels}
/>
);
const refreshControl = () => (
<RefreshControl
refreshing={refreshing}
onRefresh={onRefresh}
colors={['white']}
progressBackgroundColor={theme.colorAccent}
/>
);
const listEmptyComponent = () =>
searchText === '' && (
<EmptyView
icon="Σ(ಠ_ಠ)"
description="Your library is empty. Add series to your library from Browse."
/>
);
return (
<>
<View
style={[styles.container, {backgroundColor: theme.colorPrimaryDark}]}
>
<Searchbar
placeholder={
selectedNovels.length === 0
? `Search Library ${
showNumberOfNovels ? '(' + novels.length + ')' : ''
}`
: `${selectedNovels.length} selected`
}
searchText={searchText}
clearSearchbar={clearSearchbar}
onChangeText={onChangeText}
backAction={selectedNovels.length > 0 ? 'close' : 'magnify'}
onBackAction={() =>
selectedNovels.length > 0 && setSelectedNovels([])
}
actions={[
{
icon: 'filter-variant',
onPress: () => libraryBottomSheetRef.current.show(),
color:
filter || downloadedOnlyMode
? theme.filterColor
: theme.textColorPrimary,
},
]}
theme={theme}
/>
{incognitoMode && (
<View
style={{
backgroundColor: theme.searchBarColor,
paddingVertical: 6,
alignItems: 'center',
marginVertical: 8,
elevation: 2,
flexDirection: 'row',
justifyContent: 'center',
}}
>
<MaterialCommunityIcons
name="incognito"
color={theme.textColorSecondary}
size={18}
/>
<Text
style={{
color: theme.textColorSecondary,
marginLeft: 8,
}}
>
Incognito mode
</Text>
</View>
)}
{downloadedOnlyMode && (
<View
style={{
backgroundColor: theme.searchBarColor,
paddingVertical: 6,
alignItems: 'center',
marginVertical: 4,
elevation: 2,
flexDirection: 'row',
justifyContent: 'center',
}}
>
<MaterialCommunityIcons
name="cloud-off-outline"
color={theme.textColorSecondary}
size={18}
/>
<Text
style={{
color: theme.textColorSecondary,
marginLeft: 8,
}}
>
Downloaded only
</Text>
</View>
)}
{loading ? (
<ActivityIndicator size="small" color={theme.colorAccent} />
) : (
<>
{searchText !== '' && (
<Pressable
onPress={() =>
navigation.navigate('GlobalSearch', {
novelName: searchText,
})
}
android_ripple={{color: theme.colorAccent}}
style={styles.emptySearch}
>
<Text style={{color: theme.colorAccent}}>
{`Search for "${searchText}" globally`}
</Text>
</Pressable>
)}
<NovelList
data={novels}
renderItem={renderItem}
refreshControl={refreshControl()}
ListEmptyComponent={listEmptyComponent}
/>
<Actionbar
active={selectedNovels.length > 0}
theme={theme}
actions={[
{
icon: 'check',
onPress: () => {
selectedNovels.map(id => markAllChaptersRead(id)),
setSelectedNovels([]);
dispatch(getLibraryAction(sort, filter));
},
},
{
icon: 'check-outline',
onPress: () => {
selectedNovels.map(id => markAllChaptersUnread(id));
setSelectedNovels([]);
dispatch(getLibraryAction(sort, filter));
},
},
{
icon: 'delete-outline',
onPress: () => {
selectedNovels.map(id => unfollowNovel(id));
setSelectedNovels([]);
dispatch(getLibraryAction(sort, filter));
},
},
]}
/>
<Portal>
<LibraryBottomSheet
bottomSheetRef={libraryBottomSheetRef}
theme={theme}
dispatch={dispatch}
sort={sort}
filter={filter}
downloadedOnlyMode={downloadedOnlyMode}
/>
</Portal>
</>
)}
</View>
</>
);
};
export default LibraryScreen;
const styles = StyleSheet.create({
container: {
flex: 1,
},
emptySearch: {
alignItems: 'center',
paddingVertical: 8,
borderRadius: 4,
},
});