Skip to content

Commit

Permalink
Normalized trackers refactor (+AniList) (#631)
Browse files Browse the repository at this point in the history
* Begin AniList support

Mostly functional. Many large, sweeping changes to the data model used, so it may be worth looking into migrating the existing data structures. Otherwise it's a bad time for people already using MAL to track.

Much of the data model is documented with JSDoc, mostly for my sanity. I've never used JSDoc before so idk how correct these defs are 🤷

MAL has been mostly migrated over to the new format. There's a few straggling bits that seem to reference the old code that need to be cleared out.

Things to do:

* Status selector needs to respect AniList values/options when AL is in use
* Rating selector should respect the user's chosen rating format
* AniList option in the Discover section

* Use new MAL revalidator

* Clean up tracker creation/getting

* Generalize name for tracker cards file

* Normalize user list status

* Initialize trackers at app start

Fixes issues where things are initialized in the wrong order

* Tracker specific score implementations

MAL is effectively unchanged
AL supports all available formats. The UI leaves a bit to be desired, but it's functional.

* AniList browsing in discover

* Move AniList on top in settings for abc consistency

* Update tracker notifier when finishing chapter

* Migrate new tracker changes to TS

Additional cleanup pass

* Tracker data migration

* Fix AniList top novels info display
  • Loading branch information
TehNut authored May 14, 2023
1 parent daf4032 commit 135712c
Show file tree
Hide file tree
Showing 31 changed files with 1,132 additions and 377 deletions.
5 changes: 5 additions & 0 deletions App.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ import AppErrorBoundary from '@components/AppErrorBoundary/AppErrorBoundary';
import Main from './src/navigators/Main';
import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';

// Initialize trackers
import './src/services/Trackers/index';
import './src/services/Trackers/aniList';
import './src/services/Trackers/myAnimeList';

Notifications.setNotificationHandler({
handleNotification: async () => {
return {
Expand Down
Binary file added assets/anilist.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/navigators/Main.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import SourceNovels from '../screens/browse/SourceNovels';
import MigrateNovel from '../screens/browse/migration/MigrationNovels';

import MalTopNovels from '../screens/browse/discover/MalTopNovels';
import AniListTopNovels from '../screens/browse/discover/AniListTopNovels';
import NewUpdateDialog from '../components/NewUpdateDialog';
import BrowseSettings from '../screens/browse/BrowseSettings';
import { useAppDispatch } from '@redux/hooks';
Expand Down Expand Up @@ -67,6 +68,7 @@ const MainNavigator = () => {
<Stack.Screen name="MoreStack" component={MoreStack} />
<Stack.Screen name="SourceScreen" component={BrowseSourceScreen} />
<Stack.Screen name="BrowseMal" component={MalTopNovels} />
<Stack.Screen name="BrowseAL" component={AniListTopNovels} />
<Stack.Screen name="BrowseSettings" component={BrowseSettings} />
<Stack.Screen
name="GlobalSearchScreen"
Expand Down
41 changes: 41 additions & 0 deletions src/redux/migrate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { createMigrate } from 'redux-persist';
import { malToNormalized } from '../services/Trackers/myAnimeList';

export default createMigrate({
// Migrates old tracker data to new format
0: migrateTrackerDataToNormalized,
});

function migrateTrackerDataToNormalized(state: any): any {
// Migrate `tracker`
let tracker = state.tracker;
if (tracker) {
tracker = {
name: tracker.name,
auth: {
accessToken: tracker.access_token,
refreshToken: tracker.refresh_token,
expiresAt: tracker.expires_in,
meta: undefined,
},
};
}
state.tracker = tracker;

// Migrate `trackedNovels`
const trackedNovels = state.trackedNovels.map((oldNovel: any) => {
return {
novelId: oldNovel.novelId,
id: oldNovel.id,
totalChapters: oldNovel.num_chapters,
userData: {
progress: oldNovel.my_list_status.num_chapters_read,
score: oldNovel.my_list_status.score,
status: malToNormalized[oldNovel.my_list_status.status],
},
};
});
state.trackedNovels = trackedNovels;

return state;
}
2 changes: 2 additions & 0 deletions src/redux/settings/settingsSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ interface SettingsState {
browse: {
onlyShowPinnedSources: boolean;
showMyAnimeList: boolean;
showAniList: boolean;
searchAllSources: boolean;
};
}
Expand All @@ -37,6 +38,7 @@ const initialState: SettingsState = {
browse: {
onlyShowPinnedSources: false,
showMyAnimeList: true,
showAniList: true,
searchAllSources: false,
},
};
Expand Down
1 change: 1 addition & 0 deletions src/redux/settings/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export interface BrowseSettingsMap {
onlyShowPinnedSources: 'string';
searchAllSources: 'string';
showMyAnimeList: 'string';
showAniList: 'string';
}
3 changes: 3 additions & 0 deletions src/redux/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import AsyncStorage from '@react-native-async-storage/async-storage';
import { combineReducers, configureStore } from '@reduxjs/toolkit';
import { persistStore, persistReducer } from 'redux-persist';

import migrate from './migrate';
import settingsReducer from './settings/settings.reducer';
import settingsReducerV2 from './settings/settingsSlice';
import sourceReducerV2 from './source/sourcesSlice';
Expand All @@ -14,7 +15,9 @@ import downloadsReducer from './downloads/downloads.reducer';
const persistConfig = {
key: 'root',
storage: AsyncStorage,
version: 0,
blacklist: ['novelReducer'],
migrate,
};

const reducers = combineReducers({
Expand Down
58 changes: 34 additions & 24 deletions src/redux/tracker/tracker.actions.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { findListItem, updateItem } from '../../services/Trackers/myAnimeList';
import {
REMOVE_TRACKER,
SET_TRACKER,
Expand All @@ -8,49 +7,60 @@ import {
UPDATE_CHAPTERS_READ,
} from './tracker.types';

import { updateMalChaptersRead } from '../../services/Trackers/myAnimeList';
import { getTracker } from '../../services/Trackers';

export const setTracker = res => async dispatch => {
export const setTracker = (tracker, res) => async dispatch => {
dispatch({
type: SET_TRACKER,
payload: res,
payload: { name: tracker, ...res },
});
};

export const removeTracker = () => async dispatch => {
dispatch({ type: REMOVE_TRACKER });
};

export const trackNovel = (trackObj, accessToken) => async dispatch => {
let res = await findListItem(trackObj.id, accessToken);
trackObj.num_chapters = res.num_chapters;
trackObj.my_list_status = {
num_chapters_read: res.my_list_status.num_chapters_read,
score: res.my_list_status.score,
status: res.my_list_status.status,
/**
* @param {string} trackerName
* @param {number} internalId
* @param {Omit<import('../../services/Trackers').SearchResult, "coverImage" | "title">} novel
* @param {import('../../services/Trackers').AuthenticationResult} authentication
*/
export const trackNovel =
(trackerName, internalId, novel, auth) => async dispatch => {
const tracker = getTracker(trackerName);
const userData = await tracker.getUserListEntry(novel.id, auth);
dispatch({
type: TRACK_NOVEL,
payload: { novelId: internalId, ...novel, userData },
});
};

dispatch({ type: TRACK_NOVEL, payload: trackObj });
};

export const updateTracker = (malId, accessToken, body) => async dispatch => {
let res = await updateItem(malId, accessToken, body);

dispatch({ type: UPDATE_TRACKER, payload: { malId, ...res } });
};
export const updateTracker =
(trackerName, trackerId, auth, body) => async dispatch => {
const tracker = getTracker(trackerName);
const res = await tracker.updateUserListEntry(trackerId, body, auth);
dispatch({
type: UPDATE_TRACKER,
payload: { trackerId, ...res },
});
};

export const untrackNovel = id => async dispatch => {
dispatch({ type: UNTRACK_NOVEL, payload: id });
};

export const updateChaptersRead =
(malId, accessToken, chaptersRead) => async dispatch => {
let res = await updateMalChaptersRead(malId, accessToken, {
num_chapters_read: chaptersRead,
});
(trackerName, trackerId, auth, chaptersRead) => async dispatch => {
const tracker = getTracker(trackerName);
const res = await tracker.updateUserListEntry(
trackerId,
{ progress: chaptersRead },
auth,
);

dispatch({
type: UPDATE_CHAPTERS_READ,
payload: { malId, chaptersRead: res },
payload: { trackerId, progress: res.progress },
});
};
17 changes: 9 additions & 8 deletions src/redux/tracker/tracker.reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const trackerReducer = (state = initialState, action) => {
case SET_TRACKER:
return {
...state,
tracker: { ...payload, name: 'MyAnimeList' },
tracker: payload,
};
case REMOVE_TRACKER:
return {
Expand All @@ -39,11 +39,12 @@ const trackerReducer = (state = initialState, action) => {
return {
...state,
trackedNovels: state.trackedNovels.map(novel =>
novel.id === payload.malId
novel.id === payload.trackerId
? {
...novel,
my_list_status: {
num_chapters_read: payload.num_chapters_read,
userData: {
...novel.userData,
progress: payload.progress,
status: payload.status,
score: payload.score,
},
Expand All @@ -60,12 +61,12 @@ const trackerReducer = (state = initialState, action) => {
return {
...state,
trackedNovels: state.trackedNovels.map(novel =>
novel.id === payload.malId
novel.id === payload.trackerId
? {
...novel,
my_list_status: {
...novel.my_list_status,
num_chapters_read: payload.chaptersRead,
userData: {
...novel.userData,
progress: payload.progress,
},
}
: novel,
Expand Down
26 changes: 22 additions & 4 deletions src/screens/browse/BrowseScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { useSearch } from '../../hooks';
import SourceCard from './components/SourceCard/SourceCard';
import { getString } from '../../../strings/translations';
import { Source } from '../../sources/types';
import MalCard from './discover/MalCard/MalCard';
import TrackerCard from './discover/TrackerCard';

const BrowseScreen = () => {
const { navigate } = useNavigation();
Expand All @@ -47,8 +47,11 @@ const BrowseScreen = () => {
lastUsed,
} = useSourcesReducer();

const { showMyAnimeList = true, onlyShowPinnedSources = false } =
useBrowseSettings();
const {
showMyAnimeList = true,
showAniList = true,
onlyShowPinnedSources = false,
} = useBrowseSettings();

useEffect(() => {
dispatch(getSourcesAction());
Expand Down Expand Up @@ -165,7 +168,22 @@ const BrowseScreen = () => {
>
{getString('browseScreen.discover')}
</Text>
{showMyAnimeList && <MalCard theme={theme} />}
{showAniList && (
<TrackerCard
theme={theme}
icon={require('../../../assets/anilist.png')}
navTarget="BrowseAL"
trackerName="AniList"
/>
)}
{showMyAnimeList && (
<TrackerCard
theme={theme}
icon={require('../../../assets/mal.png')}
navTarget="BrowseMal"
trackerName="MyAnimeList"
/>
)}
</>
) : null
}
Expand Down
14 changes: 14 additions & 0 deletions src/screens/browse/BrowseSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const BrowseSettings = () => {
const {
searchAllSources = false,
showMyAnimeList = true,
showAniList = true,
onlyShowPinnedSources = false,
} = useBrowseSettings();

Expand Down Expand Up @@ -66,6 +67,19 @@ const BrowseSettings = () => {
<List.SubHeader theme={theme}>
{getString('browseScreen.discover')}
</List.SubHeader>
<SwitchItem
label="Show AniList"
value={showAniList}
onPress={() =>
dispatch(
setBrowseSettings({
key: 'showAniList',
value: !showAniList,
}),
)
}
theme={theme}
/>
<SwitchItem
label="Show MyAnimeList"
value={showMyAnimeList}
Expand Down
Loading

0 comments on commit 135712c

Please sign in to comment.