Fix app logics (#1001)
* fix: DocumentPicker apis * fix: retry on browse source screen * fix: set categories logic * fix: dont fire noti when pausing downloading
This commit is contained in:
@@ -35,6 +35,7 @@ export const getCategoriesWithCount = async (
|
||||
',',
|
||||
)}) GROUP BY categoryId
|
||||
) as NC ON Category.id = NC.categoryId
|
||||
WHERE Category.id != 2
|
||||
ORDER BY sort
|
||||
`;
|
||||
|
||||
|
||||
@@ -270,11 +270,11 @@ export const updateNovelInfo = async (info: NovelInfo) => {
|
||||
|
||||
export const pickCustomNovelCover = async (novel: NovelInfo) => {
|
||||
const image = await DocumentPicker.getDocumentAsync({ type: 'image/*' });
|
||||
if (image.type === 'success' && image.uri) {
|
||||
if (image.assets && image.assets[0]) {
|
||||
const novelDir =
|
||||
NovelDownloadFolder + '/' + novel.pluginId + '/' + novel.id;
|
||||
let novelCoverUri = 'file://' + novelDir + '/cover.png';
|
||||
RNFS.copyFile(image.uri, novelCoverUri);
|
||||
RNFS.copyFile(image.assets[0].uri, novelCoverUri);
|
||||
novelCoverUri += '?' + Date.now();
|
||||
db.transaction(tx => {
|
||||
tx.executeSql(
|
||||
@@ -309,20 +309,32 @@ export const updateNovelCategories = async (
|
||||
categoryIds: number[],
|
||||
): Promise<void> => {
|
||||
let queries: string[] = [];
|
||||
// not allow others have local id;
|
||||
categoryIds = categoryIds.filter(id => id !== 2);
|
||||
queries.push(
|
||||
`DELETE FROM NovelCategory WHERE novelId IN (${novelIds.join(
|
||||
',',
|
||||
)}) AND categoryId != 2`,
|
||||
);
|
||||
novelIds.forEach(novelId => {
|
||||
categoryIds.forEach(categoryId =>
|
||||
// if no category is selected => set to the default category
|
||||
if (categoryIds.length) {
|
||||
novelIds.forEach(novelId => {
|
||||
categoryIds.forEach(categoryId =>
|
||||
queries.push(
|
||||
`INSERT INTO NovelCategory (novelId, categoryId) VALUES (${novelId}, ${categoryId})`,
|
||||
),
|
||||
);
|
||||
});
|
||||
} else {
|
||||
novelIds.forEach(novelId => {
|
||||
// hacky: insert local novel category -> failed -> ignored
|
||||
queries.push(
|
||||
`INSERT INTO NovelCategory (novelId, categoryId) VALUES (${novelId}, ${categoryId})`,
|
||||
),
|
||||
);
|
||||
});
|
||||
`INSERT OR IGNORE INTO NovelCategory (novelId, categoryId)
|
||||
VALUES (
|
||||
${novelId},
|
||||
IFNULL((SELECT categoryId FROM NovelCategory WHERE novelId = ${novelId}), (SELECT id FROM Category WHERE sort = 1))
|
||||
)`,
|
||||
);
|
||||
});
|
||||
}
|
||||
db.transaction(tx => {
|
||||
queries.forEach(query => {
|
||||
tx.executeSql(query);
|
||||
|
||||
@@ -27,7 +27,7 @@ const downloadChapterAction = async (taskData?: TaskData) => {
|
||||
try {
|
||||
MMKVStorage.set(BACKGROUND_ACTION, BackgoundAction.DOWNLOAD_CHAPTER);
|
||||
let queue = getMMKVObject<DownloadData[]>(DOWNLOAD_QUEUE) || [];
|
||||
while (queue.length > 0) {
|
||||
while (queue.length > 0 && BackgroundService.isRunning()) {
|
||||
const { novel, chapter } = queue[0];
|
||||
await BackgroundService.updateNotification({
|
||||
taskTitle: getString('downloadScreen.downloadingNovel', {
|
||||
@@ -63,13 +63,15 @@ const downloadChapterAction = async (taskData?: TaskData) => {
|
||||
}
|
||||
} finally {
|
||||
MMKVStorage.delete(BACKGROUND_ACTION);
|
||||
await Notifications.scheduleNotificationAsync({
|
||||
content: {
|
||||
title: getString('downloadScreen.downloader'),
|
||||
body: getString('downloadScreen.completed'),
|
||||
},
|
||||
trigger: null,
|
||||
});
|
||||
if (getMMKVObject<DownloadData[]>(DOWNLOAD_QUEUE)?.length === 0) {
|
||||
await Notifications.scheduleNotificationAsync({
|
||||
content: {
|
||||
title: getString('downloadScreen.downloader'),
|
||||
body: getString('downloadScreen.completed'),
|
||||
},
|
||||
trigger: null,
|
||||
});
|
||||
}
|
||||
BackgroundService.stop();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useEffect, useRef } from 'react';
|
||||
import React, { useCallback, useRef } from 'react';
|
||||
|
||||
import { FAB } from 'react-native-paper';
|
||||
import { Container, ErrorScreenV2, SearchbarV2 } from '@components/index';
|
||||
@@ -7,7 +7,7 @@ import NovelCover from '@components/NovelCover';
|
||||
import { BottomSheetModal } from '@gorhom/bottom-sheet';
|
||||
import FilterBottomSheet from './components/FilterBottomSheet';
|
||||
|
||||
import { usePreviousRouteName, useSearch } from '@hooks';
|
||||
import { useSearch } from '@hooks';
|
||||
import { useTheme } from '@hooks/persisted';
|
||||
import { useBrowseSource, useSearchSource } from './useBrowseSource';
|
||||
|
||||
@@ -23,8 +23,6 @@ import { BrowseSourceScreenProps } from '@navigators/types';
|
||||
|
||||
const BrowseSourceScreen = ({ route, navigation }: BrowseSourceScreenProps) => {
|
||||
const theme = useTheme();
|
||||
const previousScreen = usePreviousRouteName();
|
||||
|
||||
const { pluginId, pluginName, site, showLatestNovels } = route.params;
|
||||
|
||||
const {
|
||||
@@ -62,12 +60,6 @@ const BrowseSourceScreen = ({ route, navigation }: BrowseSourceScreenProps) => {
|
||||
clearSearchResults();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (previousScreen === 'WebviewScreen') {
|
||||
refetchNovels();
|
||||
}
|
||||
}, [previousScreen]);
|
||||
|
||||
const handleOpenWebView = async () => {
|
||||
navigation.navigate('WebviewScreen', {
|
||||
name: pluginName,
|
||||
@@ -111,6 +103,19 @@ const BrowseSourceScreen = ({ route, navigation }: BrowseSourceScreenProps) => {
|
||||
) : errorMessage || novelList.length === 0 ? (
|
||||
<ErrorScreenV2
|
||||
error={errorMessage || getString('sourceScreen.noResultsFound')}
|
||||
actions={[
|
||||
{
|
||||
iconName: 'refresh',
|
||||
title: getString('common.retry'),
|
||||
onPress: () => {
|
||||
if (searchText) {
|
||||
searchSource(searchText);
|
||||
} else {
|
||||
refetchNovels();
|
||||
}
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
) : (
|
||||
<NovelList
|
||||
|
||||
@@ -44,7 +44,10 @@ export const useBrowseSource = (
|
||||
setHasNextPage(false);
|
||||
}
|
||||
})
|
||||
.catch(error => setError(error.message));
|
||||
.catch(error => {
|
||||
setError(error.message);
|
||||
setHasNextPage(false);
|
||||
});
|
||||
setFilterValues(plugin.filters);
|
||||
} catch (err: unknown) {
|
||||
setError(`${err}`);
|
||||
@@ -74,8 +77,11 @@ export const useBrowseSource = (
|
||||
}, [fetchNovels, currentPage]);
|
||||
|
||||
const refetchNovels = () => {
|
||||
setError('');
|
||||
setIsLoading(true);
|
||||
setNovels([]);
|
||||
setCurrentPage(1);
|
||||
fetchNovels(1);
|
||||
fetchNovels(1, selectedFilters);
|
||||
};
|
||||
|
||||
const clearFilters = useCallback(
|
||||
@@ -113,6 +119,7 @@ export const useSearchSource = (pluginId: string) => {
|
||||
|
||||
const searchSource = (searchTerm: string) => {
|
||||
setSearchResults([]);
|
||||
setHasNextSearchPage(true);
|
||||
setCurrentPage(1);
|
||||
setSearchText(searchTerm);
|
||||
setIsSearching(true);
|
||||
@@ -137,6 +144,7 @@ export const useSearchSource = (pluginId: string) => {
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
setSearchError(`${err}`);
|
||||
setHasNextSearchPage(false);
|
||||
} finally {
|
||||
setIsSearching(false);
|
||||
}
|
||||
|
||||
@@ -113,20 +113,18 @@ const SetCategoryModal: React.FC<SetCategoryModalProps> = ({
|
||||
closeModal();
|
||||
}}
|
||||
/>
|
||||
{selectedCategories.length ? (
|
||||
<Button
|
||||
title={getString('common.ok')}
|
||||
onPress={async () => {
|
||||
await updateNovelCategories(
|
||||
novelIds,
|
||||
selectedCategories.map(category => category.id),
|
||||
);
|
||||
closeModal();
|
||||
setSelectedCategories([]);
|
||||
onSuccess?.();
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
<Button
|
||||
title={getString('common.ok')}
|
||||
onPress={async () => {
|
||||
await updateNovelCategories(
|
||||
novelIds,
|
||||
selectedCategories.map(category => category.id),
|
||||
);
|
||||
closeModal();
|
||||
setSelectedCategories([]);
|
||||
onSuccess?.();
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</Modal>
|
||||
</Portal>
|
||||
|
||||
@@ -43,9 +43,9 @@ const CustomFileModal: React.FC<CustomFileModal> = ({
|
||||
type: mimeType,
|
||||
});
|
||||
|
||||
if (file.type === 'success') {
|
||||
if (file.assets) {
|
||||
const content = await StorageAccessFramework.readAsStringAsync(
|
||||
file.uri,
|
||||
file.assets[0].uri,
|
||||
);
|
||||
|
||||
onSave(content.trim());
|
||||
|
||||
@@ -67,8 +67,8 @@ export const restoreBackup = async (filePath?: string) => {
|
||||
});
|
||||
let novelsString = '';
|
||||
|
||||
if (backup.type === 'success') {
|
||||
novelsString = await RNFS.readFile(backup.uri);
|
||||
if (backup.assets && backup.assets[0]) {
|
||||
novelsString = await RNFS.readFile(backup.assets[0].uri);
|
||||
} else if (filePath) {
|
||||
if (!(await RNFS.exists(filePath))) {
|
||||
showToast(getString('backupScreen.legacy.noErrorNovel'));
|
||||
|
||||
Reference in New Issue
Block a user