diff --git a/src/components/NovelCover.js b/src/components/NovelCover.tsx similarity index 70% rename from src/components/NovelCover.js rename to src/components/NovelCover.tsx index 3d2d8ade7..9af62de3a 100644 --- a/src/components/NovelCover.js +++ b/src/components/NovelCover.tsx @@ -6,7 +6,6 @@ import { useWindowDimensions, Pressable, } from 'react-native'; -import color from 'color'; import { LinearGradient } from 'expo-linear-gradient'; import FastImage from 'react-native-fast-image'; @@ -16,8 +15,22 @@ import { useDeviceOrientation } from '@hooks/useDeviceOrientation'; import { coverPlaceholderColor } from '../theme/colors'; import { useLibrarySettings } from '@hooks/useSettings'; import { DisplayModes } from '@screens/library/constants/constants'; +import { LibraryNovelInfo } from '@database/types'; +import { SourceNovelItem } from 'src/sources/types'; +import { ThemeColors } from '@theme/types'; +import SourceScreenSkeletonLoading from '@screens/browse/loadingAnimation/SourceScreenSkeletonLoading'; -const NovelCover = ({ +interface NovelCoverProps { + item: LibraryNovelInfo; + onPress: () => void; + libraryStatus?: boolean; + theme: ThemeColors; + isSelected?: boolean; + onLongPress: (novelId: number) => void; + selectedNovels?: Array; +} + +const NovelCover: React.FC = ({ item, onPress, libraryStatus, @@ -44,6 +57,7 @@ const NovelCover = ({ const coverHeight = useMemo( () => (window.width / numColumns) * (4 / 3), + // eslint-disable-next-line react-hooks/exhaustive-deps [numColumns], ); @@ -51,19 +65,19 @@ const NovelCover = ({ const uri = item.novelCover; - return displayMode !== DisplayModes.List ? ( + return item.sourceId < 0 ? ( + + ) : displayMode !== DisplayModes.List ? ( @@ -152,14 +166,17 @@ const NovelCover = ({ export default memo(NovelCover); -const ComfortableTitle = ({ theme, novelName }) => ( +const ComfortableTitle: React.FC<{ theme: ThemeColors; novelName: string }> = ({ + theme, + novelName, +}) => ( @@ -167,46 +184,47 @@ const ComfortableTitle = ({ theme, novelName }) => ( ); -const CompactTitle = ({ novelName }) => ( +const CompactTitle: React.FC<{ novelName: string }> = ({ novelName }) => ( - + {novelName} ); -const InLibraryBadge = ({ theme }) => ( +const InLibraryBadge: React.FC<{ theme: ThemeColors }> = ({ theme }) => ( In library ); -const UnreadBadge = ({ +interface BadgeProps { + chaptersDownloaded: number; + chaptersUnread: number; + theme: ThemeColors; +} +interface UnreadBadgeProps extends BadgeProps { + showDownloadBadges: boolean; +} +interface DownloadBadgeProps extends BadgeProps { + showUnreadBadges: boolean; +} + +const UnreadBadge: React.FC = ({ chaptersDownloaded, chaptersUnread, showDownloadBadges, @@ -215,13 +233,8 @@ const UnreadBadge = ({ ); -const DownloadBadge = ({ +const DownloadBadge: React.FC = ({ chaptersDownloaded, showUnreadBadges, chaptersUnread, @@ -241,13 +254,8 @@ const DownloadBadge = ({ ; -const NovelList: React.FC< - FlatListProps -> = props => { +interface NovelListProps + extends FlatListProps { + inSource?: boolean; +} + +const NovelList: React.FC = props => { const { displayMode = DisplayModes.Comfortable, novelsPerRow = 3 } = useLibrarySettings(); @@ -37,7 +40,20 @@ const NovelList: React.FC< } }, [isListView, orientation, novelsPerRow]); - const keyExtractor = useCallback(item => item.sourceId + item.novelUrl, []); + const keyExtractor = useCallback( + (item: SourceNovelItem) => item.sourceId + item.novelUrl, + [], + ); + var extendedNovelList: Array = + props?.data as Array; + if (props.data?.length && props.inSource) { + let remainder = numColumns - (props.data?.length % numColumns); + let extension = []; + if (remainder !== 0 && remainder !== numColumns) { + extension.push({ sourceId: -remainder, novelName: '', novelUrl: '' }); + } + extendedNovelList = [...props.data, ...extension]; + } return ( ); }; diff --git a/src/screens/BrowseSourceScreen/BrowseSourceScreen.tsx b/src/screens/BrowseSourceScreen/BrowseSourceScreen.tsx index 005c7a213..d60b4c766 100644 --- a/src/screens/BrowseSourceScreen/BrowseSourceScreen.tsx +++ b/src/screens/BrowseSourceScreen/BrowseSourceScreen.tsx @@ -77,11 +77,14 @@ const BrowseSourceScreen: React.FC = ({ route }) => { }; const handleOpenWebView = async () => { - navigate('WebviewScreen', { - sourceId, - name: sourceName, - url: sourceUrl, - }); + navigate( + 'WebviewScreen' as never, + { + sourceId, + name: sourceName, + url: sourceUrl, + } as never, + ); }; const { library, setLibrary } = useLibraryNovels(); @@ -127,12 +130,13 @@ const BrowseSourceScreen: React.FC = ({ route }) => { ) : ( { const inLibrary = novelInLibrary(item.novelUrl); return ( navigateToNovel(item)} @@ -169,6 +173,7 @@ const BrowseSourceScreen: React.FC = ({ route }) => { fetchNextPage(); } }} + onEndReachedThreshold={1.5} ListFooterComponent={ hasNextPage && !searchText ? ( diff --git a/src/screens/BrowseSourceScreen/useBrowseSource.ts b/src/screens/BrowseSourceScreen/useBrowseSource.ts index 01e99d672..fa41e9118 100644 --- a/src/screens/BrowseSourceScreen/useBrowseSource.ts +++ b/src/screens/BrowseSourceScreen/useBrowseSource.ts @@ -70,7 +70,7 @@ export const useBrowseSource = ( const clearFilters = useCallback(() => setSelectedFilters(undefined), []); - const setFilters = (filters: SelectedFilter) => { + const setFilters = (filters?: SelectedFilter) => { setIsLoading(true); setCurrentPage(1); fetchNovels(1, filters); diff --git a/src/screens/browse/loadingAnimation/LoadingNovel.tsx b/src/screens/browse/loadingAnimation/LoadingNovel.tsx index 2eab72a78..2bc87bc69 100644 --- a/src/screens/browse/loadingAnimation/LoadingNovel.tsx +++ b/src/screens/browse/loadingAnimation/LoadingNovel.tsx @@ -100,7 +100,7 @@ const createStyleSheet = (pictureHeight: number, pictureWidth: number) => { borderRadius: 4, }, listLoadingContainer: { - marginHorizontal: 12, + marginHorizontal: 8, marginVertical: 8, flexDirection: 'row', alignItems: 'center', diff --git a/src/screens/browse/loadingAnimation/SourceScreenSkeletonLoading.tsx b/src/screens/browse/loadingAnimation/SourceScreenSkeletonLoading.tsx index cf876ae37..e82021898 100644 --- a/src/screens/browse/loadingAnimation/SourceScreenSkeletonLoading.tsx +++ b/src/screens/browse/loadingAnimation/SourceScreenSkeletonLoading.tsx @@ -9,9 +9,13 @@ import { useDeviceOrientation } from '@hooks/useDeviceOrientation'; interface Props { theme: ThemeColors; + completeRow?: number; } -const SourceScreenSkeletonLoading: React.FC = ({ theme }) => { +const SourceScreenSkeletonLoading: React.FC = ({ + theme, + completeRow, +}) => { const [highlightColor, backgroundColor] = getLoadingColors(theme); const { displayMode = DisplayModes.Comfortable, novelsPerRow = 3 } = @@ -62,6 +66,16 @@ const SourceScreenSkeletonLoading: React.FC = ({ theme }) => { ); }; let items: Array = []; + + if (completeRow) { + for (let i = -1; i >= completeRow; i--) { + items.push(i); + } + return ( + {items.map(renderLoadingNovel)} + ); + } + if (displayMode === DisplayModes.List) { items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; } else { @@ -69,7 +83,12 @@ const SourceScreenSkeletonLoading: React.FC = ({ theme }) => { items.push(i); } } - return {items.map(renderLoading)}; + + return ( + + {items.map(renderLoading)} + + ); }; const createStyleSheet = () => { @@ -82,9 +101,17 @@ const createStyleSheet = () => { overflow: 'visible', }, row: { + flexDirection: 'row', + // justifyContent: 'space-around', + paddingHorizontal: 1, + }, + completeRow: { flexDirection: 'row', justifyContent: 'space-around', paddingHorizontal: 1, + marginBottom: 8, + position: 'absolute', + right: 0, }, }); };