diff --git a/src/main/main.ts b/src/main/main.ts index 53becebf..b7c81243 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -1,17 +1,20 @@ +/* eslint-disable no-use-before-define */ +/* eslint-disable import/no-extraneous-dependencies */ +/* eslint-disable global-require */ +/* eslint-disable @typescript-eslint/no-var-requires */ import { app, BrowserWindow, dialog, ipcMain, shell } from 'electron'; -import Store from 'electron-store'; import { autoUpdater } from 'electron-updater'; import path from 'path'; -const DiscordRPC = require('discord-rpc'); import { OPEN_NEW_ISSUE_URL, SPONSOR_URL } from '../constants/utils'; -import { getAccessToken } from '../modules/anilist/anilistApi'; +import { fetchAccessToken } from '../modules/anilist/anilistApi'; import { clientData } from '../modules/clientData'; import isAppImage from '../modules/packaging/isAppImage'; import MenuBuilder from './menu'; import { resolveHtmlPath } from './util'; import { OS } from '../modules/os'; +import { STORE } from '../modules/storeVariables'; -const STORE = new Store(); +const DiscordRPC = require('../../release/app/node_modules/discord-rpc'); app.commandLine.appendSwitch('disable-features', 'OutOfBlinkCors'); @@ -91,8 +94,6 @@ const createWindow = async () => { mainWindow.show(); mainWindow.maximize(); - if (STORE.get('logged') !== true) STORE.set('logged', false); - autoUpdater.checkForUpdates(); } }); @@ -154,6 +155,7 @@ app.on('window-all-closed', () => { app .whenReady() + // eslint-disable-next-line promise/always-return .then(() => { createWindow(); app.on('activate', () => { @@ -179,7 +181,7 @@ const gotTheLock = app.requestSingleInstanceLock(); if (!gotTheLock) { app.quit(); } else { - app.on('second-instance', async (event, commandLine, workingDirectory) => { + app.on('second-instance', async (_, commandLine) => { // Someone tried to run a second instance, we should focus our window. if (mainWindow) { if (mainWindow.isMinimized()) mainWindow.restore(); @@ -235,11 +237,11 @@ app.on('open-url', async (event, url) => { async function handleLogin(code: any) { try { - const token = await getAccessToken(code); + const token = await fetchAccessToken(code); STORE.set('access_token', token); STORE.set('logged', true); } catch (error: any) { - console.log('login failed with error: ' + error.message); + console.log(`login failed with error: ${error.message}`); } } @@ -256,9 +258,9 @@ ipcMain.on('minimize-window', () => { mainWindow?.minimize(); }); -ipcMain.on('toggle-maximize-window', () => { - mainWindow?.isMaximized() ? mainWindow.unmaximize() : mainWindow?.maximize(); -}); +ipcMain.on('toggle-maximize-window', () => + mainWindow?.isMaximized() ? mainWindow.unmaximize() : mainWindow?.maximize(), +); ipcMain.on('close-window', () => { mainWindow?.close(); @@ -276,6 +278,7 @@ autoUpdater.on('update-available', (info) => { }); autoUpdater.on('update-downloaded', (info) => { + console.log('update downloaded', info); autoUpdater.quitAndInstall(); }); @@ -290,7 +293,24 @@ autoUpdater.on('error', (info) => { }); ipcMain.on('download-update', () => { - let pth = autoUpdater.downloadUpdate(); + autoUpdater.downloadUpdate(); +}); + +ipcMain.handle('getStore', () => { + const value = STORE.store; + console.log('store - get state', JSON.stringify(value)); + return value; +}); + +ipcMain.handle('getStoreValue', (_, key) => { + const value = STORE.get(key); + console.log('store - get', key, value); + return value; +}); + +ipcMain.handle('setStoreValue', (_, key, value) => { + console.log('store - set', key, value); + return STORE.set(key, value); }); /* DISCORD RPC */ diff --git a/src/main/menu.ts b/src/main/menu.ts index 39880679..ffcd6fe7 100644 --- a/src/main/menu.ts +++ b/src/main/menu.ts @@ -57,14 +57,14 @@ export default class MenuBuilder { label: 'Electron', submenu: [ { - label: 'About ElectronReact', + label: 'About akuse', selector: 'orderFrontStandardAboutPanel:', }, { type: 'separator' }, { label: 'Services', submenu: [] }, { type: 'separator' }, { - label: 'Hide ElectronReact', + label: 'Hide akuse', accelerator: 'Command+H', selector: 'hide:', }, diff --git a/src/modules/anilist/anilistApi.ts b/src/modules/anilist/anilistApi.ts index c801c12b..321a5aae 100644 --- a/src/modules/anilist/anilistApi.ts +++ b/src/modules/anilist/anilistApi.ts @@ -1,5 +1,3 @@ -import Store from 'electron-store'; - import { AnimeData, CurrentListAnime, @@ -12,8 +10,9 @@ import { clientData } from '../clientData'; import { getOptions, makeRequest } from '../requests'; import isAppImage from '../packaging/isAppImage'; import { app, ipcRenderer } from 'electron'; +import { STORAGE } from '../storage'; +import { access } from 'fs'; -const STORE: any = new Store(); const CLIENT_DATA: ClientData = clientData; const PAGES: number = 20; const METHOD: string = 'POST'; @@ -86,7 +85,7 @@ const MEDIA_DATA: string = ` * @param {*} code * @returns access token */ -export const getAccessToken = async (code: string): Promise => { +export const fetchAccessToken = async (code: string): Promise => { const url = 'https://anilist.co/api/v2/oauth/token'; const data = { @@ -110,7 +109,7 @@ export const getAccessToken = async (code: string): Promise => { * * @returns viewer id */ -export const getViewerId = async (): Promise => { +export const getViewerId = async (accessToken: string): Promise => { var query = ` query { Viewer { @@ -120,7 +119,7 @@ export const getViewerId = async (): Promise => { `; var headers = { - Authorization: 'Bearer ' + STORE.get('access_token'), + Authorization: 'Bearer ' + accessToken, 'Content-Type': 'application/json', Accept: 'application/json', }; @@ -137,7 +136,7 @@ export const getViewerId = async (): Promise => { * @param {*} viewerId * @returns object with viewer info */ -export const getViewerInfo = async (viewerId: number | null) => { +export const getViewerInfo = async (accessToken: string, viewerId: number | null) => { var query = ` query($userId : Int) { User(id: $userId, sort: ID) { @@ -151,7 +150,7 @@ export const getViewerInfo = async (viewerId: number | null) => { `; var headers = { - Authorization: 'Bearer ' + STORE.get('access_token'), + Authorization: 'Bearer ' + accessToken, 'Content-Type': 'application/json', Accept: 'application/json', }; @@ -174,6 +173,7 @@ export const getViewerInfo = async (viewerId: number | null) => { * @returns object with anime entries */ export const getViewerList = async ( + accessToken: string, viewerId: number, status: MediaListStatus, ): Promise => { @@ -197,7 +197,7 @@ export const getViewerList = async ( `; var headers = { - Authorization: 'Bearer ' + STORE.get('access_token'), + Authorization: 'Bearer ' + accessToken, 'Content-Type': 'application/json', Accept: 'application/json', }; @@ -216,7 +216,7 @@ export const getViewerList = async ( }; // NOT WORKING -export const getFollowingUsers = async (viewerId: any) => { +export const getFollowingUsers = async (accessToken: string, viewerId: any) => { var query = ` query($userId : Int) { User(id: $userId, sort: ID) { @@ -230,7 +230,7 @@ export const getFollowingUsers = async (viewerId: any) => { `; var headers = { - Authorization: 'Bearer ' + STORE.get('access_token'), + Authorization: 'Bearer ' + accessToken, 'Content-Type': 'application/json', Accept: 'application/json', }; @@ -249,7 +249,7 @@ export const getFollowingUsers = async (viewerId: any) => { * @param {*} animeId * @returns object with anime info */ -export const getAnimeInfo = async (animeId: any) => { +export const getAnimeInfo = async (accessToken: string, animeId: any) => { var query = ` query($id: Int) { Media(id: $id, type: ANIME) { @@ -259,7 +259,7 @@ export const getAnimeInfo = async (animeId: any) => { `; var headers = { - Authorization: 'Bearer ' + STORE.get('access_token'), + Authorization: 'Bearer ' + accessToken, 'Content-Type': 'application/json', Accept: 'application/json', }; @@ -282,6 +282,7 @@ export const getAnimeInfo = async (animeId: any) => { * @returns object with trending animes */ export const getTrendingAnime = async ( + accessToken: string, viewerId: number | null, ): Promise => { var query = ` @@ -301,7 +302,7 @@ export const getTrendingAnime = async ( if (viewerId) { var headers: any = { - Authorization: 'Bearer ' + STORE.get('access_token'), + Authorization: 'Bearer ' + accessToken, 'Content-Type': 'application/json', Accept: 'application/json', }; @@ -325,6 +326,7 @@ export const getTrendingAnime = async ( * @returns object with most popular animes */ export const getMostPopularAnime = async ( + accessToken: string, viewerId: number | null, ): Promise => { var query = ` @@ -344,7 +346,7 @@ export const getMostPopularAnime = async ( if (viewerId) { var headers: any = { - Authorization: 'Bearer ' + STORE.get('access_token'), + Authorization: 'Bearer ' + accessToken, 'Content-Type': 'application/json', Accept: 'application/json', }; @@ -366,7 +368,10 @@ export const getMostPopularAnime = async ( * * @returns object with next anime releases */ -export const getNextReleases = async (viewerId: number | null) => { +export const getNextReleases = async ( + accessToken: string, + viewerId: number | null, +) => { var query = ` { Page(page: 1, perPage: ${PAGES}) { @@ -384,7 +389,7 @@ export const getNextReleases = async (viewerId: number | null) => { if (viewerId) { var headers: any = { - Authorization: 'Bearer ' + STORE.get('access_token'), + Authorization: 'Bearer ' + accessToken, 'Content-Type': 'application/json', Accept: 'application/json', }; @@ -409,6 +414,7 @@ export const getNextReleases = async (viewerId: number | null) => { */ export const searchFilteredAnime = async ( args: string, + accessToken: string, viewerId: number | null, ): Promise => { var query = ` @@ -428,7 +434,7 @@ export const searchFilteredAnime = async ( if (viewerId) { var headers: any = { - Authorization: 'Bearer ' + STORE.get('access_token'), + Authorization: 'Bearer ' + accessToken, 'Content-Type': 'application/json', Accept: 'application/json', }; @@ -480,7 +486,11 @@ export const releasingAnimes = async () => { * @param {*} viewerId * @returns object with animes entries filtered by genre */ -export const getAnimesByGenre = async (genre: any, viewerId: number | null) => { +export const getAnimesByGenre = async ( + genre: any, + accessToken: string, + viewerId: number | null, +) => { var query = ` { Page(page: 1, perPage: ${PAGES}) { @@ -498,7 +508,7 @@ export const getAnimesByGenre = async (genre: any, viewerId: number | null) => { if (viewerId) { var headers: any = { - Authorization: 'Bearer ' + STORE.get('access_token'), + Authorization: 'Bearer ' + accessToken, 'Content-Type': 'application/json', Accept: 'application/json', }; @@ -550,6 +560,7 @@ export const getSearchedAnimes = async (input: any) => { /** * Updates a media entry list * + * @param accessToken * @param mediaId * @param status * @param scoreRaw @@ -557,6 +568,7 @@ export const getSearchedAnimes = async (input: any) => { * @returns media list entry id */ export const updateAnimeFromList = async ( + accessToken: string, mediaId: any, status?: any, scoreRaw?: any, @@ -572,7 +584,7 @@ export const updateAnimeFromList = async ( `; var headers = { - Authorization: 'Bearer ' + STORE.get('access_token'), + Authorization: 'Bearer ' + accessToken, 'Content-Type': 'application/json', Accept: 'application/json', }; @@ -599,7 +611,7 @@ export const updateAnimeFromList = async ( } }; -export const deleteAnimeFromList = async (id: any): Promise => { +export const deleteAnimeFromList = async (accessToken: string, id: any): Promise => { try { var query = ` mutation($id: Int){ @@ -612,7 +624,7 @@ export const deleteAnimeFromList = async (id: any): Promise => { console.log('delte: ', id); var headers = { - Authorization: 'Bearer ' + STORE.get('access_token'), + Authorization: 'Bearer ' + accessToken, 'Content-Type': 'application/json', Accept: 'application/json', }; @@ -636,6 +648,7 @@ export const deleteAnimeFromList = async (id: any): Promise => { * @param {*} progress */ export const updateAnimeProgress = async ( + accessToken: string, mediaId: number, progress: number, ) => { @@ -649,7 +662,7 @@ export const updateAnimeProgress = async ( `; var headers = { - Authorization: 'Bearer ' + STORE.get('access_token'), + Authorization: 'Bearer ' + accessToken, 'Content-Type': 'application/json', Accept: 'application/json', }; diff --git a/src/modules/providers/api.ts b/src/modules/providers/api.ts index 280db501..13159403 100644 --- a/src/modules/providers/api.ts +++ b/src/modules/providers/api.ts @@ -1,13 +1,11 @@ import { IVideo } from '@consumet/extensions'; -import Store from 'electron-store'; import { ListAnimeData } from '../../types/anilistAPITypes'; import { animeCustomTitles } from '../animeCustomTitles'; import { getParsedAnimeTitles } from '../utils'; import { getEpisodeUrl as animeunity } from './animeunity'; import { getEpisodeUrl as gogoanime } from './gogoanime'; - -const STORE = new Store(); +import { STORAGE } from '../storage'; /** * Gets the episode url and isM3U8 flag, with stored language and dubbed @@ -20,11 +18,11 @@ export const getUniversalEpisodeUrl = async ( listAnimeData: ListAnimeData, episode: number, ): Promise => { - const lang = (await STORE.get('source_flag')) as string; - const dubbed = (await STORE.get('dubbed')) as boolean; + const lang = await STORAGE.getSourceFlag(); + const dubbed = await STORAGE.getDubbed(); const customTitle = - animeCustomTitles[STORE.get('source_flag') as string][ + animeCustomTitles[lang][ listAnimeData.media?.id! ]; diff --git a/src/modules/storage.ts b/src/modules/storage.ts new file mode 100644 index 00000000..c6f3385f --- /dev/null +++ b/src/modules/storage.ts @@ -0,0 +1,75 @@ +// only use on renderer side + +import { ipcRenderer } from 'electron'; +import { LanguageOptions, StoreKeys, StoreType } from './storeVariables'; + +const getStore = async (): Promise => { + const store: StoreType = await ipcRenderer.invoke('getStore'); + return store; +}; + +const getLogged = async (): Promise => { + const logged = await ipcRenderer.invoke('getStoreValue', 'logged'); + return logged; +}; + +const getAccessToken = async (): Promise => { + const token = await ipcRenderer.invoke('getStoreValue', 'access_token'); + return token; +}; + +const getUpdateProgress = async (): Promise => { + const progress = await ipcRenderer.invoke('getStoreValue', 'update_progress'); + return progress; +}; + +const getDubbed = async (): Promise => { + const dubbed = await ipcRenderer.invoke('getStoreValue', 'dubbed'); + return dubbed; +}; + +const getSourceFlag = async (): Promise => { + const sourceFlag = await ipcRenderer.invoke('getStoreValue', 'source_flag'); + return sourceFlag; +}; + +const getIntroSkipTime = async (): Promise => { + const introSkipTime = await ipcRenderer.invoke( + 'getStoreValue', + 'intro_skip_time', + ); + return introSkipTime; +}; + +const getShowDuration = async (): Promise => { + const showDuration = await ipcRenderer.invoke( + 'getStoreValue', + 'show_duration', + ); + return showDuration; +}; + +const getTrailerVolumeOn = async (): Promise => { + const trailerVolumeOn = await ipcRenderer.invoke( + 'getStoreValue', + 'trailer_volume_on', + ); + return trailerVolumeOn; +}; + +const set = async (key: StoreKeys, value: any): Promise => { + await ipcRenderer.invoke('setStoreValue', key, value); +}; + +export const STORAGE = { + getStore, + set, + getLogged, + getAccessToken, + getUpdateProgress, + getDubbed, + getSourceFlag, + getIntroSkipTime, + getShowDuration, + getTrailerVolumeOn, +}; diff --git a/src/modules/storeVariables.ts b/src/modules/storeVariables.ts index 485ad454..60e67ca4 100644 --- a/src/modules/storeVariables.ts +++ b/src/modules/storeVariables.ts @@ -1,25 +1,67 @@ import Store from 'electron-store'; -const STORE = new Store(); -export const setDefaultStoreVariables = () => { - if (!STORE.has('update_progress')) STORE.set('update_progress', false); - if (!STORE.has('dubbed')) STORE.set('dubbed', false); - if (!STORE.has('source_flag')) STORE.set('source_flag', 'US'); - if (!STORE.has('intro_skip_time')) STORE.set('intro_skip_time', 85); - if (!STORE.has('show_duration')) STORE.set('show_duration', true); - if (!STORE.has('trailer_volume_on')) STORE.set('trailer_volume_on', false); -} +export type StoreKeys = + | 'logged' + | 'access_token' + | 'update_progress' + | 'dubbed' + | 'source_flag' + | 'intro_skip_time' + | 'show_duration' + | 'trailer_volume_on'; -export const getSourceFlag = async (): Promise<'IT' | 'US' | null> => { - switch (STORE.get('source_flag')) { - case 'US': { - return 'US'; - } - case 'IT': { - return 'IT'; - } - default: { - return null; - } - } +export type StorageContextType = { + logged: boolean; + accessToken: string; + updateProgress: boolean; + watchDubbed: boolean; + selectedLanguage: string; + skipTime: number; + showDuration: boolean; + trailerVolumeOn: boolean; + updateStorage: (key: StoreKeys, value: any) => Promise; }; + +export type LanguageOptions = 'IT' | 'US'; + +export const STORE_SCHEMA: Record = { + logged: { + type: 'boolean', + default: false, + }, + access_token: { + type: 'string', + default: '', + }, + update_progress: { + type: 'boolean', + default: false, + }, + dubbed: { + type: 'boolean', + default: false, + }, + source_flag: { + type: 'string', + default: 'US', + }, + intro_skip_time: { + type: 'number', + default: 85, + }, + show_duration: { + type: 'boolean', + default: true, + }, + trailer_volume_on: { + type: 'boolean', + default: false, + }, +}; + +// one store to rule them all. Use STORE in the main proccess and call STORAGE on the renderer side +export type StoreType = Record; +export const STORE: Store = new Store({ + // NOTE Not ready to use this yet as it will break the app + // schema: STORE_SCHEMA, +}); diff --git a/src/modules/utils.ts b/src/modules/utils.ts index 7a86b6c4..4ea09584 100644 --- a/src/modules/utils.ts +++ b/src/modules/utils.ts @@ -1,10 +1,7 @@ -import Store from 'electron-store'; - import { AnimeData, ListAnimeData } from '../types/anilistAPITypes'; import { Media, MediaFormat, MediaStatus } from '../types/anilistGraphQLTypes'; import { animeCustomTitles } from '../modules/animeCustomTitles'; -const STORE = new Store(); const MONTHS = { '1': 'January', '2': 'February', @@ -321,10 +318,6 @@ export const parseAirdate = (airdate: string) => export const getParsedAnimeTitles = (animeEntry: Media): string[] => { var animeTitles = getTitlesAndSynonyms(animeEntry); - // const customTitle = - // animeCustomTitles[STORE.get('source_flag') as string][animeEntry?.id!]; - // if (customTitle) animeTitles.unshift(customTitle); - animeTitles.forEach((title) => { if (title.includes('Season ')) animeTitles.push(title.replace('Season ', '')); diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index fd9eaa36..b5e11dcf 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -1,13 +1,13 @@ -import '..//styles/components.css'; +import '../styles/components.css'; import '../styles/animations.css'; import '../styles/style.css'; import 'react-loading-skeleton/dist/skeleton.css'; -import Store from 'electron-store'; -import { createContext, useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { SkeletonTheme } from 'react-loading-skeleton'; -import { MemoryRouter, Route, Routes } from 'react-router-dom'; +import { Route, Routes, useLocation } from 'react-router-dom'; +import { ipcRenderer } from 'electron'; import { getMostPopularAnime, getNextReleases, @@ -24,33 +24,26 @@ import Tab2 from './tabs/Tab2'; import Tab3 from './tabs/Tab3'; import Tab4 from './tabs/Tab4'; -import { setDefaultStoreVariables } from '../modules/storeVariables'; -import { ipcRenderer } from 'electron'; import AutoUpdateModal from './components/modals/AutoUpdateModal'; import WindowControls from './WindowControls'; import { OS } from '../modules/os'; +import { useStorageContext } from './contexts/storage'; +import { useUIContext } from './contexts/ui'; -ipcRenderer.on('console-log', (event, toPrint) => { +ipcRenderer.on('console-log', (_event, toPrint) => { console.log(toPrint); }); -const store = new Store(); -export const AuthContext = createContext(false); -export const ViewerIdContext = createContext(null); - export default function App() { - const [logged, setLogged] = useState(store.get('logged') as boolean); - const [viewerId, setViewerId] = useState(null); + const { pathname } = useLocation(); + const { logged, accessToken } = useStorageContext(); + const { viewerId, setViewerId, hasListUpdated, setHasListUpdated } = + useUIContext(); const [showUpdateModal, setShowUpdateModal] = useState(false); - setDefaultStoreVariables(); - - ipcRenderer.on('auto-update', async () => { - setShowUpdateModal(true); - }); - // tab1 const [userInfo, setUserInfo] = useState(); + const [animeLoaded, setAnimeLoaded] = useState(false); const [currentListAnime, setCurrentListAnime] = useState< ListAnimeData[] | undefined >(undefined); @@ -65,7 +58,6 @@ export default function App() { >(undefined); // tab2 - const [tab2Click, setTab2Click] = useState(false); const [planningListAnime, setPlanningListAnimeListAnime] = useState< ListAnimeData[] | undefined >(undefined); @@ -84,34 +76,47 @@ export default function App() { const style = getComputedStyle(document.body); - const fetchTab1AnimeData = async () => { - try { - var id = null; - if (logged) { - id = await getViewerId(); - setViewerId(id); - - setUserInfo(await getViewerInfo(id)); - const current = await getViewerList(id, 'CURRENT'); - const rewatching = await getViewerList(id, 'REPEATING'); - setCurrentListAnime(current.concat(rewatching)); + const fetchTab1AnimeData = useCallback( + async (loggedIn: boolean) => { + try { + let id = null; + if (loggedIn) { + id = await getViewerId(accessToken); + setViewerId(id); + + const info = await getViewerInfo(accessToken, id); + setUserInfo(info); + const current = await getViewerList(accessToken, id, 'CURRENT'); + const rewatching = await getViewerList(accessToken, id, 'REPEATING'); + setCurrentListAnime(current.concat(rewatching)); + } + + if (!animeLoaded) { + setTrendingAnime( + animeDataToListAnimeData(await getTrendingAnime(accessToken, id)), + ); + setMostPopularAnime( + animeDataToListAnimeData( + await getMostPopularAnime(accessToken, id), + ), + ); + setNextReleasesAnime( + animeDataToListAnimeData(await getNextReleases(accessToken, id)), + ); + setAnimeLoaded(true); + } + } catch (error) { + console.log(`Tab1 error: ${error}`); } + }, + [accessToken, animeLoaded], + ); - setTrendingAnime(animeDataToListAnimeData(await getTrendingAnime(id))); - setMostPopularAnime( - animeDataToListAnimeData(await getMostPopularAnime(id)), - ); - setNextReleasesAnime(animeDataToListAnimeData(await getNextReleases(id))); - } catch (error) { - console.log('Tab1 error: ' + error); - } - }; - - const fetchTab2AnimeData = async () => { + const fetchTab2AnimeData = useCallback(async () => { try { if (viewerId) { setPlanningListAnimeListAnime( - await getViewerList(viewerId, 'PLANNING'), + await getViewerList(accessToken, viewerId, 'PLANNING'), ); // setCompletedListAnimeListAnime( // await getViewerList(viewerId, 'COMPLETED'), @@ -123,73 +128,86 @@ export default function App() { // ); } } catch (error) { - console.log('Tab2 error: ' + error); + console.log(`Tab2 error: ${error}`); } - }; + }, [accessToken, viewerId]); useEffect(() => { - fetchTab1AnimeData(); - }, []); + if (pathname === '/') { + void fetchTab1AnimeData(logged); + } + }, [logged, pathname]); + + useEffect(() => { + if (pathname === '/tab2') { + void fetchTab2AnimeData(); + } + }, [pathname]); useEffect(() => { - if (tab2Click) { - fetchTab2AnimeData(); + if (hasListUpdated) { + void fetchTab1AnimeData(logged); + void fetchTab2AnimeData(); + setHasListUpdated(false); } - }, [tab2Click, viewerId]); + }, [hasListUpdated, logged, pathname]); + + useEffect(() => { + ipcRenderer.on('auto-update', () => { + setShowUpdateModal(true); + }); + + return () => { + ipcRenderer.removeListener('auto-update', () => { + setShowUpdateModal(true); + }); + }; + }, []); return ( - - - - { - setShowUpdateModal(false); - }} - /> - - {!OS.isMac && } - - - - } + + { + setShowUpdateModal(false); + }} + /> + {!OS.isMac && } + + + + } + /> + {logged && ( + - {logged && ( - { - !tab2Click && setTab2Click(true); - }} - /> - } - /> - )} - } /> - } /> - - - - - + } + /> + )} + } /> + } /> + + ); } diff --git a/src/renderer/MainNavbar.tsx b/src/renderer/MainNavbar.tsx index 1c2ec7e5..5064447a 100644 --- a/src/renderer/MainNavbar.tsx +++ b/src/renderer/MainNavbar.tsx @@ -16,9 +16,9 @@ import { useContext, useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import isAppImage from '../modules/packaging/isAppImage'; -import { AuthContext } from './App'; import AuthCodeModal from './components/modals/AuthCodeModal'; import UserModal from './components/modals/UserModal'; +import { useStorageContext } from './contexts/storage'; const Li: React.FC<{ text: string; @@ -55,7 +55,7 @@ const LiLink: React.FC<{ }; const MainNavbar: React.FC<{ avatar?: string }> = ({ avatar }) => { - const logged = useContext(AuthContext); + const {logged} = useStorageContext(); const [activeTab, setActiveTab] = useState(1); const [showUserModal, setShowUserModal] = useState(false); @@ -66,6 +66,12 @@ const MainNavbar: React.FC<{ avatar?: string }> = ({ avatar }) => { ipcRenderer.invoke('get-is-packaged').then((packaged) => { setIsPackaged(packaged); }); + + return () => { + ipcRenderer.removeListener('get-is-packaged', (packaged) => { + setIsPackaged(packaged); + }); + } }, []); return ( diff --git a/src/renderer/components/AnimeEntry.tsx b/src/renderer/components/AnimeEntry.tsx index 1829339c..fe502b18 100644 --- a/src/renderer/components/AnimeEntry.tsx +++ b/src/renderer/components/AnimeEntry.tsx @@ -1,9 +1,9 @@ import './styles/AnimeEntry.css'; import { faCalendar, faCircleDot } from '@fortawesome/free-regular-svg-icons'; -import { faHourglass1, faTv } from '@fortawesome/free-solid-svg-icons'; +import { faTv } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import { getAvailableEpisodes, @@ -14,7 +14,6 @@ import { import { ListAnimeData } from '../../types/anilistAPITypes'; import AnimeModal from './modals/AnimeModal'; import Skeleton from 'react-loading-skeleton'; -import { AnimeModalWatchButtons } from './modals/AnimeModalElements'; const StatusDot: React.FC<{ listAnimeData?: ListAnimeData | undefined; diff --git a/src/renderer/components/AnimeSection.tsx b/src/renderer/components/AnimeSection.tsx index ba1f327c..db2e02c7 100644 --- a/src/renderer/components/AnimeSection.tsx +++ b/src/renderer/components/AnimeSection.tsx @@ -73,7 +73,7 @@ const AnimeSection: React.FC = ({ title, animeData }) => { )}
- {(animeData ? animeData : Array(20).fill(undefined)).map( + {(animeData?.length ? animeData : Array(20).fill(undefined)).map( (listAnimeData, index) => ( ), diff --git a/src/renderer/components/UserNavbar.tsx b/src/renderer/components/UserNavbar.tsx index f590b3fe..c6add88b 100644 --- a/src/renderer/components/UserNavbar.tsx +++ b/src/renderer/components/UserNavbar.tsx @@ -7,8 +7,7 @@ import { } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { ipcRenderer } from 'electron'; -import { useContext } from 'react'; -import { AuthContext } from '../App'; +import { useStorageContext } from '../contexts/storage'; interface LiProps { text: string; @@ -32,8 +31,7 @@ interface UserNavbarProps { } const UserNavbar: React.FC = ({ avatar }) => { - const logged = useContext(AuthContext); - + const { logged } = useStorageContext(); return (