From 9f67eb20a14fa5faacf42889673de7d60ce56c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4ki?= Date: Wed, 13 Mar 2024 13:39:38 +0200 Subject: [PATCH] Add TsModsModule for Vuex The module will hold the list of all mods available on Thunderstore API for the current active game, and provide helpers related to that data. --- src/components/mixins/SplashMixin.vue | 2 +- src/components/mixins/UtilityMixin.vue | 2 +- src/components/navigation/NavigationMenu.vue | 2 +- src/components/views/DownloadModModal.vue | 2 +- src/components/views/OnlineModList.vue | 2 +- src/components/views/OnlineModView.vue | 4 +- src/pages/Manager.vue | 2 +- src/r2mm/data/ThunderstorePackages.ts | 3 + src/store/index.ts | 18 +----- src/store/modules/ModFilterModule.ts | 16 +---- src/store/modules/ProfileModule.ts | 8 +-- src/store/modules/TsModsModule.ts | 66 ++++++++++++++++++++ 12 files changed, 83 insertions(+), 44 deletions(-) create mode 100644 src/store/modules/TsModsModule.ts diff --git a/src/components/mixins/SplashMixin.vue b/src/components/mixins/SplashMixin.vue index 66bef26b..adf5e002 100644 --- a/src/components/mixins/SplashMixin.vue +++ b/src/components/mixins/SplashMixin.vue @@ -76,7 +76,7 @@ export default class SplashMixin extends Vue { if (response) { ThunderstorePackages.handlePackageApiResponse(response); - await this.$store.dispatch('updateThunderstoreModList', ThunderstorePackages.PACKAGES); + await this.$store.dispatch('tsMods/updateMods', ThunderstorePackages.PACKAGES); await this.moveToNextScreen(); } else { this.heroTitle = 'Failed to get mods from Thunderstore and cache'; diff --git a/src/components/mixins/UtilityMixin.vue b/src/components/mixins/UtilityMixin.vue index a8bb4478..7244a907 100644 --- a/src/components/mixins/UtilityMixin.vue +++ b/src/components/mixins/UtilityMixin.vue @@ -28,7 +28,7 @@ export default class UtilityMixin extends Vue { const response = await ThunderstorePackages.update(this.$store.state.activeGame); await ApiCacheUtils.storeLastRequest(response.data); - await this.$store.dispatch("updateThunderstoreModList", ThunderstorePackages.PACKAGES); + await this.$store.dispatch("tsMods/updateMods", ThunderstorePackages.PACKAGES); await this.$store.dispatch("profile/tryLoadModListFromDisk"); } diff --git a/src/components/navigation/NavigationMenu.vue b/src/components/navigation/NavigationMenu.vue index ade61a2d..9a2ae473 100644 --- a/src/components/navigation/NavigationMenu.vue +++ b/src/components/navigation/NavigationMenu.vue @@ -83,7 +83,7 @@ export default class NavigationMenu extends Vue { private LaunchMode = LaunchMode; get thunderstoreModCount() { - let mods: ThunderstoreMod[] = this.$store.state.thunderstoreModList || []; + let mods: ThunderstoreMod[] = this.$store.state.tsMods.mods; return this.$store.state.modFilters.showDeprecatedPackages ? mods.length diff --git a/src/components/views/DownloadModModal.vue b/src/components/views/DownloadModModal.vue index 54d06198..552b2c0c 100644 --- a/src/components/views/DownloadModModal.vue +++ b/src/components/views/DownloadModModal.vue @@ -202,7 +202,7 @@ let assignId = 0; } get thunderstorePackages(): ThunderstoreMod[] { - return this.$store.state.thunderstoreModList || []; + return this.$store.state.tsMods.mods; } @Watch('$store.state.modals.downloadModModalMod') diff --git a/src/components/views/OnlineModList.vue b/src/components/views/OnlineModList.vue index e3223189..74c53a4c 100644 --- a/src/components/views/OnlineModList.vue +++ b/src/components/views/OnlineModList.vue @@ -92,7 +92,7 @@ export default class OnlineModList extends Vue { } get deprecationMap(): Map { - return this.$store.state.deprecatedMods; + return this.$store.state.tsMods.deprecated; } isModDeprecated(key: any) { diff --git a/src/components/views/OnlineModView.vue b/src/components/views/OnlineModView.vue index d7c3d0e1..d84b9531 100644 --- a/src/components/views/OnlineModView.vue +++ b/src/components/views/OnlineModView.vue @@ -105,7 +105,7 @@ export default class OnlineModView extends Vue { } get thunderstoreModList(): ThunderstoreMod[] { - return this.$store.state.thunderstoreModList; + return this.$store.state.tsMods.mods; } getPaginationSize() { @@ -174,7 +174,7 @@ export default class OnlineModView extends Vue { @Watch("sortingDirectionModel") @Watch("sortingStyleModel") - @Watch("thunderstoreModList") + @Watch("tsMods.mods") sortThunderstoreModList() { const sortDescending = this.sortingDirectionModel == SortingDirection.STANDARD; const sortedList = [...this.thunderstoreModList]; diff --git a/src/pages/Manager.vue b/src/pages/Manager.vue index 5fc644fb..ac5c36cc 100644 --- a/src/pages/Manager.vue +++ b/src/pages/Manager.vue @@ -205,7 +205,7 @@ import CategoryFilterModal from '../components/modals/CategoryFilterModal.vue'; private contextProfile: Profile | null = null; get thunderstoreModList(): ThunderstoreMod[] { - return this.$store.state.thunderstoreModList || []; + return this.$store.state.tsMods.mods; } get localModList(): ManifestV2[] { diff --git a/src/r2mm/data/ThunderstorePackages.ts b/src/r2mm/data/ThunderstorePackages.ts index f61aa916..b3a03d3a 100644 --- a/src/r2mm/data/ThunderstorePackages.ts +++ b/src/r2mm/data/ThunderstorePackages.ts @@ -47,6 +47,9 @@ export default class ThunderstorePackages { } /** + * TODO: This doesn't really do what the dosctring below says: + * deprecated dependencies do NOT mark the dependant deprecated. + * * "Smart" package deprecation determination by keeping track of previously determine dependencies. * This ensures that we hit as few iterations as possible to speed up calculation time. * diff --git a/src/store/index.ts b/src/store/index.ts index 6c488e02..f46eefff 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -5,12 +5,11 @@ import ErrorModule from './modules/ErrorModule'; import ModalsModule from './modules/ModalsModule'; import ModFilterModule from './modules/ModFilterModule'; import ProfileModule from './modules/ProfileModule'; +import { TsModsModule } from './modules/TsModsModule'; import { FolderMigration } from '../migrations/FolderMigration'; import Game from '../model/game/Game'; import GameManager from '../model/game/GameManager'; import R2Error from '../model/errors/R2Error'; -import ThunderstoreMod from '../model/ThunderstoreMod'; -import ThunderstorePackages from '../r2mm/data/ThunderstorePackages'; import ManagerSettings from '../r2mm/manager/ManagerSettings'; Vue.use(Vuex); @@ -18,10 +17,8 @@ Vue.use(Vuex); export interface State { activeGame: Game; apiConnectionError: string; - deprecatedMods: Map; dismissedUpdateAll: boolean; isMigrationChecked: boolean; - thunderstoreModList: ThunderstoreMod[]; _settings: ManagerSettings | null; } @@ -35,20 +32,14 @@ type Context = ActionContext; export const store = { state: { activeGame: GameManager.defaultGame, - thunderstoreModList: [], dismissedUpdateAll: false, isMigrationChecked: false, apiConnectionError: "", - deprecatedMods: new Map(), // Access through getters to ensure the settings are loaded. _settings: null, }, actions: { - updateThunderstoreModList({ commit }: Context, modList: ThunderstoreMod[]) { - commit('setThunderstoreModList', modList); - commit('setDeprecatedMods', modList); - }, dismissUpdateAll({commit}: Context) { commit('dismissUpdateAll'); }, @@ -87,9 +78,6 @@ export const store = { setActiveGame(state: State, game: Game) { state.activeGame = game; }, - setThunderstoreModList(state: State, list: ThunderstoreMod[]) { - state.thunderstoreModList = list; - }, dismissUpdateAll(state: State) { state.dismissedUpdateAll = true; }, @@ -99,9 +87,6 @@ export const store = { setApiConnectionError(state: State, err: string) { state.apiConnectionError = err; }, - setDeprecatedMods(state: State) { - state.deprecatedMods = ThunderstorePackages.getDeprecatedPackageMap(); - }, setSettings(state: State, settings: ManagerSettings) { state._settings = settings; } @@ -130,6 +115,7 @@ export const store = { modals: ModalsModule, modFilters: ModFilterModule, profile: ProfileModule, + tsMods: TsModsModule, }, // enable strict mode (adds overhead!) diff --git a/src/store/modules/ModFilterModule.ts b/src/store/modules/ModFilterModule.ts index a37a2849..6f5400c2 100644 --- a/src/store/modules/ModFilterModule.ts +++ b/src/store/modules/ModFilterModule.ts @@ -24,20 +24,8 @@ export default { }), getters: >{ - allCategories (_state, _getters, rootState) { - const categories = Array.from( - new Set( - rootState.thunderstoreModList - .map((mod) => mod.getCategories()) - .flat() - ) - ); - categories.sort(); - return categories; - }, - - unselectedCategories (state, getters) { - const categories: string[] = getters.allCategories; + unselectedCategories (state, _getters, _rootState, rootGetters) { + const categories: string[] = rootGetters['tsMods/categories']; return categories.filter((c: string) => !state.selectedCategories.includes(c)); } }, diff --git a/src/store/modules/ProfileModule.ts b/src/store/modules/ProfileModule.ts index 9719100b..ec1d1333 100644 --- a/src/store/modules/ProfileModule.ts +++ b/src/store/modules/ProfileModule.ts @@ -9,7 +9,6 @@ import { SortLocalDisabledMods } from '../../model/real_enums/sort/SortLocalDisa import { SortNaming } from '../../model/real_enums/sort/SortNaming'; import ThunderstoreCombo from '../../model/ThunderstoreCombo'; import ConflictManagementProvider from '../../providers/generic/installing/ConflictManagementProvider'; -import ThunderstoreDownloaderProvider from '../../providers/ror2/downloading/ThunderstoreDownloaderProvider'; import ProfileInstallerProvider from '../../providers/ror2/installing/ProfileInstallerProvider'; import ManagerSettings from '../../r2mm/manager/ManagerSettings'; import ModListSort from '../../r2mm/mods/ModListSort'; @@ -77,11 +76,8 @@ export default { return getters.activeProfile.getProfileName(); }, - modsWithUpdates(state, _getters, rootState): ThunderstoreCombo[] { - return ThunderstoreDownloaderProvider.instance.getLatestOfAllToUpdate( - state.modList, - rootState.thunderstoreModList - ); + modsWithUpdates(state, _getters, _rootState, rootGetters): ThunderstoreCombo[] { + return rootGetters['tsMods/modsWithUpdates'](state.modList); }, visibleModList(state, _getters, rootState): ManifestV2[] { diff --git a/src/store/modules/TsModsModule.ts b/src/store/modules/TsModsModule.ts new file mode 100644 index 00000000..959b0e02 --- /dev/null +++ b/src/store/modules/TsModsModule.ts @@ -0,0 +1,66 @@ +import { ActionTree, GetterTree, MutationTree } from 'vuex'; + +import { State as RootState } from '../index'; +import ManifestV2 from '../../model/ManifestV2'; +import ThunderstoreMod from '../../model/ThunderstoreMod'; +import ThunderstoreDownloaderProvider from '../../providers/ror2/downloading/ThunderstoreDownloaderProvider'; +import ThunderstorePackages from '../../r2mm/data/ThunderstorePackages'; + + +interface State { + deprecated: Map; + mods: ThunderstoreMod[]; +} + +/** + * For dealing with mods listed in communities, i.e. available through + * the Thunderstore API. Mods received from the API are stored in + * IndexedDB (via Dexie). For performance they're also stored in memory + * by this Vuex store module. + */ +export const TsModsModule = { + namespaced: true, + + state: (): State => ({ + deprecated: new Map(), + /*** All mods available through API for the current active game */ + mods: [], + }), + + getters: >{ + /*** Categories used by any mod listed in the community */ + categories(state) { + const categories = Array.from( + new Set( + state.mods.map((mod) => mod.getCategories()).flat() + ) + ); + categories.sort(); + return categories; + }, + + /*** Which locally installed mods have updates in Thunderstore? */ + modsWithUpdates: (state) => (profileMods: ManifestV2[]) => { + return ThunderstoreDownloaderProvider.instance.getLatestOfAllToUpdate( + profileMods, + state.mods + ); + } + }, + + mutations: >{ + setMods(state, payload: ThunderstoreMod[]) { + state.mods = payload; + }, + updateDeprecated(state) { + state.deprecated = ThunderstorePackages.getDeprecatedPackageMap(); + } + }, + + actions: >{ + updateMods({commit}, modList: ThunderstoreMod[]) { + commit('setMods', modList); + commit('updateDeprecated'); + } + } +}