mirror of
https://github.com/austinried/subtracks.git
synced 2026-02-11 07:12:44 +01:00
switch to jotai
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import React from 'react';
|
||||
import { Button, FlatList, Text, View } from 'react-native';
|
||||
import { useRecoilValue, useResetRecoilState } from 'recoil';
|
||||
import { FlatList, Text, View } from 'react-native';
|
||||
import { useAtomValue } from 'jotai/utils';
|
||||
import { Artist } from '../models/music';
|
||||
import { artistsState } from '../state/music';
|
||||
import { artistsAtom } from '../state/music';
|
||||
|
||||
const ArtistItem: React.FC<{ item: Artist } > = ({ item }) => (
|
||||
<View>
|
||||
@@ -15,7 +15,7 @@ const ArtistItem: React.FC<{ item: Artist } > = ({ item }) => (
|
||||
);
|
||||
|
||||
const List = () => {
|
||||
const artists = useRecoilValue(artistsState);
|
||||
const artists = useAtomValue(artistsAtom);
|
||||
|
||||
const renderItem: React.FC<{ item: Artist }> = ({ item }) => (
|
||||
<ArtistItem item={item} />
|
||||
@@ -30,24 +30,10 @@ const List = () => {
|
||||
);
|
||||
}
|
||||
|
||||
const ListPlusControls = () => {
|
||||
const resetArtists = useResetRecoilState(artistsState);
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Button
|
||||
title='Reset to default'
|
||||
onPress={resetArtists}
|
||||
/>
|
||||
<List />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const ArtistsList = () => (
|
||||
<View>
|
||||
<React.Suspense fallback={<Text>Loading...</Text>}>
|
||||
<ListPlusControls />
|
||||
<List />
|
||||
</React.Suspense>
|
||||
</View>
|
||||
)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useNavigation } from '@react-navigation/core';
|
||||
import { useAtom } from 'jotai';
|
||||
import md5 from 'md5';
|
||||
import React from 'react';
|
||||
import { Button, Text, View } from 'react-native';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { appSettingsState } from '../state/settings';
|
||||
import { appSettingsAtom } from '../state/settings';
|
||||
|
||||
const TestControls = () => {
|
||||
const navigation = useNavigation();
|
||||
@@ -19,7 +19,7 @@ const TestControls = () => {
|
||||
}
|
||||
|
||||
const ServerSettingsView = () => {
|
||||
const [appSettings, setAppSettings] = useRecoilState(appSettingsState);
|
||||
const [appSettings, setAppSettings] = useAtom(appSettingsAtom);
|
||||
|
||||
const bootstrapServer = () => {
|
||||
if (appSettings.servers.length !== 0) {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useAtomValue } from 'jotai/utils';
|
||||
import React, { useEffect } from 'react';
|
||||
import { FlatList, Text, View } from 'react-native';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import LinearGradient from 'react-native-linear-gradient';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { Album } from '../../models/music';
|
||||
import { albumsState, albumsUpdatingState, useUpdateAlbums } from '../../state/music';
|
||||
import { albumsAtom, albumsUpdatingAtom, useUpdateAlbums } from '../../state/music';
|
||||
import colors from '../../styles/colors';
|
||||
import textStyles from '../../styles/text';
|
||||
import TopTabContainer from '../common/TopTabContainer';
|
||||
@@ -89,8 +89,8 @@ const AlbumListRenderItem: React.FC<{ item: Album }> = ({ item }) => (
|
||||
);
|
||||
|
||||
const AlbumsList = () => {
|
||||
const albums = useRecoilValue(albumsState);
|
||||
const updating = useRecoilValue(albumsUpdatingState);
|
||||
const albums = useAtomValue(albumsAtom);
|
||||
const updating = useAtomValue(albumsUpdatingAtom);
|
||||
const updateAlbums = useUpdateAlbums();
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useAtomValue } from 'jotai/utils';
|
||||
import React, { useEffect } from 'react';
|
||||
import { FlatList, Image, Text, View } from 'react-native';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { Artist } from '../../models/music';
|
||||
import { artistsState, artistsUpdatingState, useUpdateArtists } from '../../state/music';
|
||||
import { artistsAtom, artistsUpdatingAtom, useUpdateArtists } from '../../state/music';
|
||||
import textStyles from '../../styles/text';
|
||||
import TopTabContainer from '../common/TopTabContainer';
|
||||
|
||||
@@ -28,8 +28,8 @@ const ArtistItem: React.FC<{ item: Artist } > = ({ item }) => (
|
||||
);
|
||||
|
||||
const ArtistsList = () => {
|
||||
const artists = useRecoilValue(artistsState);
|
||||
const updating = useRecoilValue(artistsUpdatingState);
|
||||
const artists = useAtomValue(artistsAtom);
|
||||
const updating = useAtomValue(artistsUpdatingAtom);
|
||||
const updateArtists = useUpdateArtists();
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,27 +1,21 @@
|
||||
import { atom, useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
import { atom, useAtom } from 'jotai';
|
||||
import { useAtomValue, useUpdateAtom } from 'jotai/utils';
|
||||
import { Album, Artist } from '../models/music';
|
||||
import { SubsonicApiClient } from '../subsonic/api';
|
||||
import { activeServer } from './settings';
|
||||
import { activeServerAtom } from './settings';
|
||||
|
||||
export const artistsState = atom<Artist[]>({
|
||||
key: 'artistsState',
|
||||
default: [],
|
||||
});
|
||||
|
||||
export const artistsUpdatingState = atom<boolean>({
|
||||
key: 'artistsUpdatingState',
|
||||
default: false,
|
||||
});
|
||||
export const artistsAtom = atom<Artist[]>([]);
|
||||
export const artistsUpdatingAtom = atom(false);
|
||||
|
||||
export const useUpdateArtists = () => {
|
||||
const server = useRecoilValue(activeServer);
|
||||
const server = useAtomValue(activeServerAtom);
|
||||
const [updating, setUpdating] = useAtom(artistsUpdatingAtom);
|
||||
const setArtists = useUpdateAtom(artistsAtom);
|
||||
|
||||
if (!server) {
|
||||
return () => Promise.resolve();
|
||||
}
|
||||
|
||||
const [updating, setUpdating] = useRecoilState(artistsUpdatingState);
|
||||
const setArtists = useSetRecoilState(artistsState);
|
||||
|
||||
return async () => {
|
||||
if (updating) {
|
||||
return;
|
||||
@@ -42,25 +36,18 @@ export const useUpdateArtists = () => {
|
||||
}
|
||||
}
|
||||
|
||||
export const albumsState = atom<Album[]>({
|
||||
key: 'albumsState',
|
||||
default: [],
|
||||
});
|
||||
|
||||
export const albumsUpdatingState = atom<boolean>({
|
||||
key: 'albumsUpdatingState',
|
||||
default: false,
|
||||
});
|
||||
export const albumsAtom = atom<Album[]>([]);
|
||||
export const albumsUpdatingAtom = atom(false);
|
||||
|
||||
export const useUpdateAlbums = () => {
|
||||
const server = useRecoilValue(activeServer);
|
||||
const server = useAtomValue(activeServerAtom);
|
||||
const [updating, setUpdating] = useAtom(albumsUpdatingAtom);
|
||||
const setAlbums = useUpdateAtom(albumsAtom);
|
||||
|
||||
if (!server) {
|
||||
return () => Promise.resolve();
|
||||
}
|
||||
|
||||
const [updating, setUpdating] = useRecoilState(albumsUpdatingState);
|
||||
const setAlbums = useSetRecoilState(albumsState);
|
||||
|
||||
return async () => {
|
||||
if (updating) {
|
||||
return;
|
||||
|
||||
@@ -1,28 +1,12 @@
|
||||
import { atom, DefaultValue, selector } from 'recoil';
|
||||
import { AppSettings, Server } from '../models/settings';
|
||||
import { getAppSettings, setAppSettings } from '../storage/settings';
|
||||
import { atom } from 'jotai';
|
||||
import { AppSettings } from '../models/settings';
|
||||
import atomWithAsyncStorage from '../storage/atomWithAsyncStorage';
|
||||
|
||||
export const appSettingsState = atom<AppSettings>({
|
||||
key: 'appSettingsState',
|
||||
default: selector({
|
||||
key: 'appSettingsState/default',
|
||||
get: () => getAppSettings(),
|
||||
}),
|
||||
effects_UNSTABLE: [
|
||||
({ onSet }) => {
|
||||
onSet((newValue) => {
|
||||
if (!(newValue instanceof DefaultValue)) {
|
||||
setAppSettings(newValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
],
|
||||
export const appSettingsAtom = atomWithAsyncStorage<AppSettings>('@appSettings', {
|
||||
servers: [],
|
||||
});
|
||||
|
||||
export const activeServer = selector<Server | undefined>({
|
||||
key: 'activeServer',
|
||||
get: ({get}) => {
|
||||
const appSettings = get(appSettingsState);
|
||||
return appSettings.servers.find(x => x.id == appSettings.activeServer);
|
||||
}
|
||||
export const activeServerAtom = atom((get) => {
|
||||
const appSettings = get(appSettingsAtom);
|
||||
return appSettings.servers.find(x => x.id == appSettings.activeServer);
|
||||
});
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
|
||||
export async function getItem(key: string): Promise<string | null> {
|
||||
export async function getItem(key: string): Promise<any | null> {
|
||||
try {
|
||||
return await AsyncStorage.getItem(key);
|
||||
const item = await AsyncStorage.getItem(key);
|
||||
return item ? JSON.parse(item) : null;
|
||||
} catch (e) {
|
||||
console.error(`getItem error (key: ${key})`, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function multiGet(keys: string[]): Promise<[string, string | null][]> {
|
||||
export async function multiGet(keys: string[]): Promise<[string, any | null][]> {
|
||||
try {
|
||||
return await AsyncStorage.multiGet(keys);
|
||||
const items = await AsyncStorage.multiGet(keys);
|
||||
return items.map(x => [x[0], x[1] ? JSON.parse(x[1]) : null]);
|
||||
} catch (e) {
|
||||
console.error(`multiGet error`, e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function setItem(key: string, item: string): Promise<void> {
|
||||
export async function setItem(key: string, item: any): Promise<void> {
|
||||
try {
|
||||
await AsyncStorage.setItem(key, item);
|
||||
await AsyncStorage.setItem(key, JSON.stringify(item));
|
||||
} catch (e) {
|
||||
console.error(`setItem error (key: ${key})`, e);
|
||||
}
|
||||
@@ -28,7 +30,7 @@ export async function setItem(key: string, item: string): Promise<void> {
|
||||
|
||||
export async function multiSet(items: string[][]): Promise<void> {
|
||||
try {
|
||||
await AsyncStorage.multiSet(items);
|
||||
await AsyncStorage.multiSet(items.map(x => [x[0], JSON.stringify(x[1])]));
|
||||
} catch (e) {
|
||||
console.error(`multiSet error`, e);
|
||||
}
|
||||
|
||||
10
src/storage/atomWithAsyncStorage.ts
Normal file
10
src/storage/atomWithAsyncStorage.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { atomWithStorage } from 'jotai/utils';
|
||||
import { getItem, setItem } from './asyncstorage';
|
||||
|
||||
export default <T>(key: string, defaultValue: T) => {
|
||||
return atomWithStorage<T>(key, defaultValue, {
|
||||
getItem: async () => await getItem(key) || defaultValue,
|
||||
setItem: setItem,
|
||||
delayInit: true,
|
||||
});
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { AppSettings } from '../models/settings';
|
||||
import { getItem, setItem } from './asyncstorage';
|
||||
|
||||
const appSettingsKey = '@appSettings';
|
||||
|
||||
export async function getAppSettings(): Promise<AppSettings> {
|
||||
const item = await getItem(appSettingsKey);
|
||||
return item ? JSON.parse(item) : {
|
||||
servers: [],
|
||||
};
|
||||
}
|
||||
|
||||
export async function setAppSettings(appSettings: AppSettings): Promise<void> {
|
||||
await setItem(appSettingsKey, JSON.stringify(appSettings));
|
||||
}
|
||||
Reference in New Issue
Block a user