From 202feb1f411474753015ecf7a10ef5179695a7ec Mon Sep 17 00:00:00 2001 From: nyagami Date: Sun, 10 Mar 2024 00:23:34 +0700 Subject: [PATCH] Fix chapters logic & Rework Plugins management (UI) (#993) * fix: not download/remove local chapters * fix: deleteChapters callback * remove plugin id: no sense fot user * rework plugin management --- src/hooks/persisted/useNovel.ts | 2 +- src/hooks/persisted/usePlugins.ts | 45 +- src/screens/browse/BrowseScreen.tsx | 101 +--- src/screens/browse/components/BrowseTabs.tsx | 430 ++++++++++++++++++ src/screens/browse/components/PluginCard.tsx | 177 ------- .../browse/components/PluginSection.tsx | 135 ------ src/screens/novel/NovelScreen.tsx | 4 +- 7 files changed, 463 insertions(+), 431 deletions(-) create mode 100644 src/screens/browse/components/BrowseTabs.tsx delete mode 100644 src/screens/browse/components/PluginCard.tsx delete mode 100644 src/screens/browse/components/PluginSection.tsx diff --git a/src/hooks/persisted/useNovel.ts b/src/hooks/persisted/useNovel.ts index cb00f6bcb..df59a6f2f 100644 --- a/src/hooks/persisted/useNovel.ts +++ b/src/hooks/persisted/useNovel.ts @@ -312,7 +312,7 @@ export const useNovel = (novelPath: string, pluginId: string) => { }); } }, - [novel], + [novel, chapters], ); const getNovel = useCallback(async () => { diff --git a/src/hooks/persisted/usePlugins.ts b/src/hooks/persisted/usePlugins.ts index b522fb16b..0455db005 100644 --- a/src/hooks/persisted/usePlugins.ts +++ b/src/hooks/persisted/usePlugins.ts @@ -130,35 +130,34 @@ export default function usePlugins() { }; const uninstallPlugin = (plugin: PluginItem) => { - return _uninstall(plugin).then(() => { - if (lastUsedPlugin?.id === plugin.id) { - MMKVStorage.delete(LAST_USED_PLUGIN); - } - const installedPlugins = - getMMKVObject(INSTALLED_PLUGINS) || []; - const availablePlugins = - getMMKVObject(AVAILABLE_PLUGINS) || ({} as PluginsMap); + if (lastUsedPlugin?.id === plugin.id) { + MMKVStorage.delete(LAST_USED_PLUGIN); + } + const installedPlugins = + getMMKVObject(INSTALLED_PLUGINS) || []; + const availablePlugins = + getMMKVObject(AVAILABLE_PLUGINS) || ({} as PluginsMap); - // safe - if (!availablePlugins[plugin.lang]?.some(_plg => _plg.id === plugin.id)) { - availablePlugins[plugin.lang] = [ - ...(availablePlugins[plugin.lang] || []), - plugin, - ]; - setMMKVObject(AVAILABLE_PLUGINS, availablePlugins); - } - setMMKVObject( - INSTALLED_PLUGINS, - installedPlugins.filter(plg => plg.id !== plugin.id), - ); - filterPlugins(languagesFilter); - }); + // safe + if (!availablePlugins[plugin.lang]?.some(_plg => _plg.id === plugin.id)) { + availablePlugins[plugin.lang] = [ + ...(availablePlugins[plugin.lang] || []), + plugin, + ]; + setMMKVObject(AVAILABLE_PLUGINS, availablePlugins); + } + setMMKVObject( + INSTALLED_PLUGINS, + installedPlugins.filter(plg => plg.id !== plugin.id), + ); + filterPlugins(languagesFilter); + return _uninstall(plugin).then(() => {}); }; const updatePlugin = (plugin: PluginItem) => { return _update(plugin).then(_plg => { if (plugin.version === _plg?.version) { - throw new Error(getString('browseScreen.tryAgain')); + throw new Error('No update found!'); } if (_plg) { const installedPlugins = diff --git a/src/screens/browse/BrowseScreen.tsx b/src/screens/browse/BrowseScreen.tsx index 92a722992..279b2c562 100644 --- a/src/screens/browse/BrowseScreen.tsx +++ b/src/screens/browse/BrowseScreen.tsx @@ -4,41 +4,17 @@ import { TabView, TabBar } from 'react-native-tab-view'; import color from 'color'; import { useSearch } from '@hooks'; -import { useBrowseSettings, usePlugins, useTheme } from '@hooks/persisted'; +import { usePlugins, useTheme } from '@hooks/persisted'; import { getString } from '@strings/translations'; -import { Language } from '@utils/constants/languages'; import { EmptyView, SearchbarV2 } from '@components'; import { BrowseScreenProps } from '@navigators/types'; -import { PluginsMap } from '@hooks/persisted/usePlugins'; -import PluginSection from './components/PluginSection'; +import { AvailableTab, InstalledTab } from './components/BrowseTabs'; const BrowseScreen = ({ navigation }: BrowseScreenProps) => { const theme = useTheme(); const { searchText, setSearchText, clearSearchbar } = useSearch(); - const { - filteredAvailablePlugins, - filteredInstalledPlugins, - languagesFilter, - lastUsedPlugin, - } = usePlugins(); - - const searchedInstalledPlugins = useMemo(() => { - return filteredInstalledPlugins.filter(plg => - plg.name.toLocaleLowerCase().includes(searchText.toLocaleLowerCase()), - ); - }, [searchText, filteredInstalledPlugins]); - - const searchedAvailablePlugins = useMemo(() => { - return languagesFilter.reduce((pre, cur) => { - pre[cur] = filteredAvailablePlugins[cur]?.filter(plg => - plg.name.toLocaleLowerCase().includes(searchText.toLocaleLowerCase()), - ); - return pre; - }, {} as PluginsMap); - }, [searchText, filteredAvailablePlugins]); - - const { showMyAnimeList, showAniList } = useBrowseSettings(); + const { languagesFilter } = usePlugins(); const searchbarActions = useMemo( () => [ @@ -58,58 +34,6 @@ const BrowseScreen = ({ navigation }: BrowseScreenProps) => { [], ); - const availableSections = useMemo(() => { - const list = []; - if (searchText) { - list.push({ - header: getString('common.searchResults'), - data: [], - }); - languagesFilter.forEach(lang => { - const plugins = searchedAvailablePlugins[lang as Language]; - if (plugins?.length) { - list.push({ - header: lang, - data: plugins, - }); - } - }); - } else { - languagesFilter.forEach(lang => { - const plugins = filteredAvailablePlugins[lang as Language]; - if (plugins?.length) { - list.push({ - header: lang, - data: plugins, - }); - } - }); - } - return list; - }, [searchedAvailablePlugins]); - - const installedSections = useMemo(() => { - const list = []; - if (searchText) { - list.push({ - header: getString('common.searchResults'), - data: searchedInstalledPlugins, - }); - } else if (filteredInstalledPlugins.length) { - if (lastUsedPlugin) { - list.push({ - header: getString('browseScreen.lastUsed'), - data: [lastUsedPlugin], - }); - } - list.push({ - header: getString('browseScreen.installedPlugins'), - data: filteredInstalledPlugins, - }); - } - return list; - }, [lastUsedPlugin, searchedInstalledPlugins]); - const [index, setIndex] = React.useState(0); const [routes] = React.useState([ { key: 'installedRoute', title: getString('browseScreen.installed') }, @@ -141,23 +65,13 @@ const BrowseScreen = ({ navigation }: BrowseScreenProps) => { } switch (route.key) { case 'availableRoute': - return ( - - ); + return ; default: return ( - ); } @@ -182,6 +96,7 @@ const BrowseScreen = ({ navigation }: BrowseScreenProps) => { android_ripple={{ color: theme.rippleColor }} /> )} + swipeEnabled={false} /> ); diff --git a/src/screens/browse/components/BrowseTabs.tsx b/src/screens/browse/components/BrowseTabs.tsx new file mode 100644 index 000000000..61b17d599 --- /dev/null +++ b/src/screens/browse/components/BrowseTabs.tsx @@ -0,0 +1,430 @@ +import React, { useCallback, useMemo, useState } from 'react'; +import { + Pressable, + Image, + View, + Text, + StyleSheet, + SectionList, + RefreshControl, + ListRenderItem, +} from 'react-native'; +import { useBrowseSettings, usePlugins } from '@hooks/persisted'; +import { PluginItem } from '@plugins/types'; +import { + FlashList, + ListRenderItem as FlashListRenderItem, + ListRenderItemInfo, +} from '@shopify/flash-list'; +import { coverPlaceholderColor } from '@theme/colors'; +import { ThemeColors } from '@theme/types'; +import { Swipeable } from 'react-native-gesture-handler'; +import { languages } from '@utils/constants/languages'; +import { getString } from '@strings/translations'; +import { BrowseScreenProps } from '@navigators/types'; +import { Button, IconButtonV2 } from '@components'; +import TrackerCard from '../discover/TrackerCard'; +import { showToast } from '@utils/showToast'; +import Animated, { + useAnimatedStyle, + useSharedValue, + withTiming, +} from 'react-native-reanimated'; + +interface AvailableTabProps { + searchText: string; + theme: ThemeColors; +} + +interface InstalledTabProps { + navigation: BrowseScreenProps['navigation']; + theme: ThemeColors; + searchText: string; +} + +export function InstalledTab({ + navigation, + theme, + searchText, +}: InstalledTabProps) { + const { + filteredInstalledPlugins, + lastUsedPlugin, + setLastUsedPlugin, + uninstallPlugin, + updatePlugin, + } = usePlugins(); + const { showMyAnimeList, showAniList } = useBrowseSettings(); + const navigateToSource = useCallback( + (plugin: PluginItem, showLatestNovels?: boolean) => { + navigation.navigate('SourceScreen', { + pluginId: plugin.id, + pluginName: plugin.name, + site: plugin.site, + showLatestNovels, + }); + setLastUsedPlugin(plugin); + }, + [], + ); + + const searchedPlugins = useMemo(() => { + if (searchText) { + return filteredInstalledPlugins.filter(plg => + plg.name.toLocaleLowerCase().includes(searchText.toLocaleLowerCase()), + ); + } else { + return filteredInstalledPlugins; + } + }, [searchText, filteredInstalledPlugins]); + + const renderItem: FlashListRenderItem = ({ item }) => { + return ( + { + return ( + + { + ref.close(); + updatePlugin(item) + .then(version => + showToast( + getString('browseScreen.updatedTo', { version }), + ), + ) + .catch((error: Error) => showToast(error.message)); + }} + theme={theme} + /> + { + ref.close(); + navigation.navigate('WebviewScreen', { + name: item.name, + url: item.site, + pluginId: item.id, + }); + }} + theme={theme} + /> + + ); + }} + renderRightActions={(progress, dragX, ref) => ( + + { + ref.close(); + uninstallPlugin(item).then(() => + showToast( + getString('browseScreen.uninstalledPlugin', { + name: item.name, + }), + ), + ); + }} + theme={theme} + /> + + )} + > + navigateToSource(item)} + > + + + + + {item.name} + + + {`${languages[item.lang]} - ${item.version}`} + + + +