aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--App.tsx22
-rw-r--r--android/app/src/main/AndroidManifest.xml5
-rw-r--r--src/AppView.tsx (renamed from src/View.tsx)7
-rw-r--r--src/components/AppMenu.tsx5
-rw-r--r--src/components/Favorites.tsx4
-rw-r--r--src/hooks/useFavorites.ts64
6 files changed, 44 insertions, 63 deletions
diff --git a/App.tsx b/App.tsx
index dd4cdd8..76ea9f1 100644
--- a/App.tsx
+++ b/App.tsx
@@ -1,18 +1,20 @@
-import React from 'react';
-import {SafeAreaView} from 'react-native';
+import React, {Suspense} from 'react';
+import {SafeAreaView, View} from 'react-native';
import {GestureHandlerRootView} from 'react-native-gesture-handler';
-import {View} from './src/View';
+import {AppView} from './src/AppView';
import {Provider as JotaiProvider} from 'jotai';
const App: React.FC = () => {
return (
- <JotaiProvider>
- <GestureHandlerRootView>
- <SafeAreaView className="flex flex-1 bg-black text-slate-200">
- <View />
- </SafeAreaView>
- </GestureHandlerRootView>
- </JotaiProvider>
+ <Suspense fallback={<View className="flex flex-1 bg-black" />}>
+ <JotaiProvider>
+ <GestureHandlerRootView>
+ <SafeAreaView className="flex flex-1 bg-black text-slate-200">
+ <AppView />
+ </SafeAreaView>
+ </GestureHandlerRootView>
+ </JotaiProvider>
+ </Suspense>
);
};
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 2a2071e..e8b319e 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
-
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
@@ -19,8 +18,8 @@
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
diff --git a/src/View.tsx b/src/AppView.tsx
index 110e3fe..cca64f6 100644
--- a/src/View.tsx
+++ b/src/AppView.tsx
@@ -3,17 +3,14 @@ import Swiper from 'react-native-swiper';
import {AppList} from './screens/AppList';
import {Home} from './screens/Home';
import {useInstalledApps} from './hooks/useInstalledApps';
-import {useFavorites} from './hooks/useFavorites';
-export const View: React.FC = React.memo(() => {
+export const AppView: React.FC = React.memo(() => {
const {refreshApps} = useInstalledApps();
- const {refreshFavorites} = useFavorites();
const [screenIndex, setScreenIndex] = useState(0);
useEffect(() => {
refreshApps();
- refreshFavorites();
- }, [screenIndex, refreshApps, refreshFavorites]);
+ }, [screenIndex, refreshApps]);
return (
<Swiper
diff --git a/src/components/AppMenu.tsx b/src/components/AppMenu.tsx
index 4c994ab..8938bb9 100644
--- a/src/components/AppMenu.tsx
+++ b/src/components/AppMenu.tsx
@@ -63,7 +63,10 @@ export const AppMenu: React.FC<React.PropsWithChildren<{app: AppDetail}>> = ({
return (
<>
- <TouchableNativeFeedback onPress={openApp} onLongPress={openContextMenu}>
+ <TouchableNativeFeedback
+ onPress={openApp}
+ onLongPress={openContextMenu}
+ delayPressIn={100}>
{children}
</TouchableNativeFeedback>
diff --git a/src/components/Favorites.tsx b/src/components/Favorites.tsx
index ed81a6b..4c8dc37 100644
--- a/src/components/Favorites.tsx
+++ b/src/components/Favorites.tsx
@@ -1,4 +1,4 @@
-import React, {useCallback, useEffect, useMemo} from 'react';
+import React, {useCallback, useMemo} from 'react';
import {Text, TouchableOpacity, View} from 'react-native';
import {AppDetail} from 'react-native-launcher-kit/typescript/Interfaces/InstalledApps';
import {useFavorites} from '../hooks/useFavorites';
@@ -39,7 +39,7 @@ export const Favorites: React.FC<{active: boolean}> = (_) => {
const onDragEnd = useCallback(
({data}: DragEndParams<AppDetail>) => {
- setFavorites(data.map((app) => app.packageName));
+ setFavorites(() => data.map((app) => app.packageName));
},
[setFavorites],
);
diff --git a/src/hooks/useFavorites.ts b/src/hooks/useFavorites.ts
index 24684aa..fa96211 100644
--- a/src/hooks/useFavorites.ts
+++ b/src/hooks/useFavorites.ts
@@ -1,55 +1,37 @@
-import {useAsyncStorage} from '@react-native-async-storage/async-storage';
+import AsyncStorage from '@react-native-async-storage/async-storage/src/AsyncStorage';
import {useStableCallback} from './useStableCallback';
-import {atom, useAtom} from 'jotai';
+import {useAtom} from 'jotai';
+import {createJSONStorage, atomWithStorage} from 'jotai/utils';
-const favoriteAppNamesAtom = atom<string[]>([]);
+const jsonStorage = createJSONStorage<string[]>(() => AsyncStorage);
+const favoriteAppNamesAtom = atomWithStorage<string[]>(
+ 'favorites',
+ [],
+ jsonStorage,
+);
-const serialize = (packageNames: string[]) => JSON.stringify(packageNames);
-
-const deserialize = (packageNames: string): string[] => {
- try {
- const apps = JSON.parse(packageNames);
- if (!Array.isArray(apps)) return [];
- return apps;
- } catch (err) {
- console.error(err);
- return [];
- }
-};
+const serialize = (packageNames: string[]) => packageNames.join(',');
export const useFavorites = () => {
- const favoritesStorage = useAsyncStorage('favorites');
const [favoriteAppNames, setFavoriteAppNames] = useAtom(favoriteAppNamesAtom);
- const getFavoriteAppNames = useStableCallback(async (): Promise<string[]> => {
- const result = await favoritesStorage.getItem();
- return deserialize(result ?? 'null');
- });
-
- const setFavoritesState = useStableCallback((packageNames: string[]) => {
- const newNames = [...new Set(packageNames)];
- if (serialize(newNames) === serialize(favoriteAppNames)) return newNames;
-
- setFavoriteAppNames(newNames);
- return newNames;
- });
-
- const setFavorites = useStableCallback(async (packageNames: string[]) => {
- const newNames = setFavoritesState(packageNames);
- await favoritesStorage.setItem(serialize(newNames));
- });
+ const setFavorites = useStableCallback(
+ async (
+ updater: (packageNames: string[]) => Promise<string[]> | string[],
+ ) => {
+ const newNames = [...new Set(await updater(favoriteAppNames))];
+ if (serialize(newNames) === serialize(favoriteAppNames)) return newNames;
- const refreshFavorites = useStableCallback(async () => {
- getFavoriteAppNames().then(setFavoritesState);
- });
+ setFavoriteAppNames(newNames);
+ return newNames;
+ },
+ );
const addToFavorites = useStableCallback(async (packageName: string) => {
- const names = await getFavoriteAppNames();
- setFavorites([...names, packageName]);
+ setFavorites((names) => [...names, packageName]);
});
const removeFromFavorites = useStableCallback(async (packageName: string) => {
- const names = await getFavoriteAppNames();
- setFavorites(names.filter((name) => name !== packageName));
+ setFavorites((names) => names.filter((name) => name !== packageName));
});
const isFavorite = useStableCallback((packageName: string) =>
@@ -59,9 +41,7 @@ export const useFavorites = () => {
return {
addToFavorites,
favoriteAppNames,
- getFavoriteAppNames,
isFavorite,
- refreshFavorites,
removeFromFavorites,
setFavorites,
};