diff --git a/scripts/build.ts b/scripts/build.ts index a8d6a09..22f583a 100644 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -79,6 +79,7 @@ export default async function build(dev = Dev, log = true) { .trim(), ), __DEV__: String(dev), + // __BUILD_DEFAULT_PLUGIN_REPOSITORY_URL__: ..., // See types/build.d.ts for what these flags do __BUILD_FLAG_DEBUG_MODULE_LOOKUPS__: String(dev), diff --git a/src/plugins/start/settings.plugins/index.ts b/src/plugins/start/settings.plugins/index.ts index b2ab46a..13a450d 100644 --- a/src/plugins/start/settings.plugins/index.ts +++ b/src/plugins/start/settings.plugins/index.ts @@ -4,6 +4,7 @@ import { refreshSettingsNavigator, refreshSettingsOverviewScreen, } from '@revenge-mod/discord/modules/settings' +import { JsonStorageUpdateMode } from '@revenge-mod/json-storage' import { InternalPluginFlags, isPluginStartedLate, @@ -16,11 +17,14 @@ import { } from '@revenge-mod/plugins/_/repositories' import { lookupGeneratedIconComponent } from '@revenge-mod/utils/discord' import pluginSettings from '../settings' +import { addDefaultRepoIfNeeded } from './repos' +import type { JsonStorage } from '@revenge-mod/json-storage' import type { PluginApi } from '@revenge-mod/plugins/types' export interface Storage { autoUpdate: boolean lastUpdateCheck?: number + defaultRepoRestored?: boolean } const OUTDATED_THRESHOLD = 24 * 60 * 60 * 1000 // 1 day @@ -65,32 +69,8 @@ registerInternalPlugin<{ jsonStorage: Storage }>( } const settings = await api.jsonStorage.get() - if (!settings.autoUpdate) return - if ( - settings.lastUpdateCheck !== undefined && - Date.now() - settings.lastUpdateCheck <= OUTDATED_THRESHOLD - ) - return - - setTimeout(async () => { - try { - const { errors } = await refreshAllRepos() - await updateAllPlugins() - - if (!errors.length) - await api.jsonStorage.set({ - lastUpdateCheck: Date.now(), - }) - } catch (e) { - ToastActionCreators.open({ - key: 'PLUGIN_UPDATE_CHECK_FAILED', - content: 'Failed to check for plugin updates', - IconComponent: CircleXIconComponent, - }) - - api.logger.warn('Failed to check for plugin updates', e) - } - }, AUTO_UPDATE_CHECK_DELAY) + autoUpdateService(settings) + defaultRepoRestoreService(settings, api.jsonStorage) }, stop({ cleanup }) { cleanup(refreshSettingsOverviewScreen, refreshSettingsNavigator) @@ -100,5 +80,47 @@ registerInternalPlugin<{ jsonStorage: Storage }>( InternalPluginFlags.Internal | InternalPluginFlags.Essential, ) +function autoUpdateService(settings: Storage) { + if (!settings.autoUpdate) return + if ( + settings.lastUpdateCheck !== undefined && + Date.now() - settings.lastUpdateCheck <= OUTDATED_THRESHOLD + ) + return + + setTimeout(async () => { + try { + const { errors } = await refreshAllRepos() + await updateAllPlugins() + + if (!errors.length) + await api.jsonStorage.set({ + lastUpdateCheck: Date.now(), + }) + } catch (e) { + ToastActionCreators.open({ + key: 'PLUGIN_UPDATE_CHECK_FAILED', + content: 'Failed to check for plugin updates', + IconComponent: CircleXIconComponent, + }) + + api.logger.warn('Failed to check for plugin updates', e) + } + }, AUTO_UPDATE_CHECK_DELAY) +} + +// TODO: Add UI for this? +function defaultRepoRestoreService( + settings: Storage, + storage: JsonStorage, +) { + if (!settings.defaultRepoRestored) addDefaultRepoIfNeeded() + storage.subscribe((update, mode) => { + // If user cleared storage, restore the default repo if needed + if (mode === JsonStorageUpdateMode.Load && !update.defaultRepoRestored) + addDefaultRepoIfNeeded() + }) +} + // Exposed for the Advanced settings screen (auto-update toggle) export let api: PluginApi<{ jsonStorage: Storage }> diff --git a/src/plugins/start/settings.plugins/repos.ts b/src/plugins/start/settings.plugins/repos.ts new file mode 100644 index 0000000..b82d102 --- /dev/null +++ b/src/plugins/start/settings.plugins/repos.ts @@ -0,0 +1,29 @@ +import { + listRepos, + refreshRepo, + setRepos, +} from '@revenge-mod/plugins/_/repositories' +import { noop } from '@revenge-mod/utils/callback' +import type { Repo, RepoConfigEntry } from '@revenge-mod/plugins/_/repositories' + +export async function addDefaultRepoIfNeeded() { + if (!__BUILD_DEFAULT_PLUGIN_REPOSITORY_URL__) return + + const repos = await listRepos() + if ( + repos.some(repo => repo.url === __BUILD_DEFAULT_PLUGIN_REPOSITORY_URL__) + ) + return + + const userRepos = toConfig(repos.filter(repo => !repo.internal)) + await setRepos([ + { url: __BUILD_DEFAULT_PLUGIN_REPOSITORY_URL__, enabled: true }, + ...userRepos, + ]) + + await refreshRepo(__BUILD_DEFAULT_PLUGIN_REPOSITORY_URL__).catch(noop) +} + +export function toConfig(list: Repo[]): RepoConfigEntry[] { + return list.map(({ url, enabled }) => ({ url, enabled })) +} diff --git a/src/plugins/start/settings.plugins/screens/RevengePluginsAdvancedSettingScreen.tsx b/src/plugins/start/settings.plugins/screens/RevengePluginsAdvancedSettingScreen.tsx index 30c57e9..78b20eb 100644 --- a/src/plugins/start/settings.plugins/screens/RevengePluginsAdvancedSettingScreen.tsx +++ b/src/plugins/start/settings.plugins/screens/RevengePluginsAdvancedSettingScreen.tsx @@ -19,6 +19,7 @@ import { lookupGeneratedIconComponent } from '@revenge-mod/utils/discord' import { useCallback, useEffect, useState } from 'react' import { ScrollView, View } from 'react-native' import { api } from '..' +import { toConfig } from '../repos' import { formatBytes, messageOf, showErrorToast } from '../utils/repos' import type { DownloadProgressEvent, @@ -44,10 +45,6 @@ const UpIconComponent = lookupGeneratedIconComponent('ArrowSmallUpIcon')! const DownIconComponent = lookupGeneratedIconComponent('ArrowSmallDownIcon')! const TrashIconComponent = lookupGeneratedIconComponent('TrashIcon')! -function toConfig(list: Repo[]): RepoConfigEntry[] { - return list.map(({ url, enabled }) => ({ url, enabled })) -} - function repoSubLabel(repo: Repo, state?: RepoStateEvent['state']) { if (state === 'refreshing') return `${repo.url} (refreshing...)` if (state === 'error') return `${repo.url} (refresh failed)` @@ -206,6 +203,8 @@ export default function RevengePluginsAdvancedSettingScreen() { const removeRepo = useCallback( async (repo: Repo) => { + // TODO: Add warning for default repo removal, user can clear "Plugin Settings" data to restore the default repo + await commit(toConfig(userRepos.filter(r => r.url !== repo.url))) // Plugins installed from the removed repository turn Sideloaded diff --git a/types/build.d.ts b/types/build.d.ts index 9c65464..54c3aa7 100644 --- a/types/build.d.ts +++ b/types/build.d.ts @@ -4,6 +4,7 @@ declare global { const __DEV__: boolean const __BUILD_DISCORD_SERVER_URL__: string const __BUILD_SOURCE_REPOSITORY_URL__: string + const __BUILD_DEFAULT_PLUGIN_REPOSITORY_URL__: string | undefined const __BUILD_LICENSE_URL__: string const __BUILD_COMMIT__: string const __BUILD_BRANCH__: string