Skip to content

Commit 865b8c6

Browse files
committed
Show progress of each step in the profile import modal
Initially progress was based purely on downloading the mods. It was recently changed so that extracting the downloaded mod to cache is allocated 20% of the progress of processing the mod in this step. However, this still leaves users hanging on 100% completion while the mods from the cache and configs from the imported profile zip are copied to the profile folder. These steps now have their own progress indicators.
1 parent 0356a35 commit 865b8c6

File tree

2 files changed

+39
-15
lines changed

2 files changed

+39
-15
lines changed

src/components/profiles-modals/ImportProfileModal.vue

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import OnlineModList from "../views/OnlineModList.vue";
2020
})
2121
export default class ImportProfileModal extends mixins(ProfilesMixin) {
2222
private importUpdateSelection: "IMPORT" | "UPDATE" | null = null;
23-
private percentageImported: number = 0;
23+
private importPhaseDescription: string = 'Downloading mods: 0%';
2424
private profileImportCode: string = '';
2525
private listenerId: number = 0;
2626
private newProfileName: string = '';
@@ -163,8 +163,10 @@ export default class ImportProfileModal extends mixins(ProfilesMixin) {
163163
}
164164
165165
this.activeStep = 'PROFILE_IS_BEING_IMPORTED';
166-
this.percentageImported = 0;
167-
const progressCallback = (progress: number) => this.percentageImported = Math.floor(progress);
166+
this.importPhaseDescription = 'Downloading mods: 0%';
167+
const progressCallback = (progress: number|string) => typeof progress === "number"
168+
? this.importPhaseDescription = `Downloading mods: ${Math.floor(progress)}%`
169+
: this.importPhaseDescription = progress;
168170
const community = this.$store.state.activeGame.internalFolderName;
169171
const settings = this.$store.getters['settings'];
170172
const ignoreCache = settings.getContext().global.ignoreCache;
@@ -173,7 +175,7 @@ export default class ImportProfileModal extends mixins(ProfilesMixin) {
173175
try {
174176
const comboList = await ProfileUtils.exportModsToCombos(mods, community);
175177
await ThunderstoreDownloaderProvider.instance.downloadImportedMods(comboList, ignoreCache, progressCallback);
176-
await ProfileUtils.populateImportedProfile(comboList, mods, targetProfileName, isUpdate, zipPath);
178+
await ProfileUtils.populateImportedProfile(comboList, mods, targetProfileName, isUpdate, zipPath, progressCallback);
177179
} catch (e) {
178180
this.closeModal();
179181
this.$store.commit('error/handleError', R2Error.fromThrownValue(e));
@@ -359,11 +361,14 @@ export default class ImportProfileModal extends mixins(ProfilesMixin) {
359361

360362
<ModalCard v-else-if="activeStep === 'PROFILE_IS_BEING_IMPORTED'" key="PROFILE_IS_BEING_IMPORTED" :is-active="isOpen" :canClose="false">
361363
<template v-slot:header>
362-
<h2 class="modal-title">{{percentageImported}}% imported</h2>
364+
<h2 class="modal-title">{{importPhaseDescription}}</h2>
363365
</template>
364366
<template v-slot:footer>
365-
<p>This may take a while, as mods are being downloaded.<br>
366-
Please do not close {{appName}}.</p>
367+
<p>
368+
This may take a while, as files are being downloaded, extracted, and copied.
369+
<br><br>
370+
Please do not close {{appName}}.
371+
</p>
367372
</template>
368373
</ModalCard>
369374
</template>

src/utils/ProfileUtils.ts

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,14 @@ export async function exportModsToCombos(exportMods: ExportMod[], community: str
4444
return combos;
4545
}
4646

47-
export async function extractImportedProfileConfigs(file: string, profileName: string) {
48-
const entries = await ZipProvider.instance.getEntries(file);
49-
for (const entry of entries) {
47+
async function extractImportedProfileConfigs(
48+
file: string,
49+
profileName: string,
50+
progressCallback: (status: string) => void
51+
) {
52+
const zipEntries = await ZipProvider.instance.getEntries(file);
53+
54+
for (const [index, entry] of zipEntries.entries()) {
5055
if (entry.entryName.startsWith('config/') || entry.entryName.startsWith("config\\")) {
5156
await ZipProvider.instance.extractEntryTo(
5257
file,
@@ -67,13 +72,21 @@ export async function extractImportedProfileConfigs(file: string, profileName: s
6772
)
6873
)
6974
}
75+
76+
const progress = Math.floor((index/zipEntries.length) * 100);
77+
progressCallback(`Copying configs to profile: ${progress}%`);
7078
}
7179
}
7280

73-
export async function installModsToProfile(comboList: ThunderstoreCombo[], modList: ExportMod[], profile: ImmutableProfile) {
81+
async function installModsToProfile(
82+
comboList: ThunderstoreCombo[],
83+
modList: ExportMod[],
84+
profile: ImmutableProfile,
85+
progressCallback: (status: string) => void
86+
) {
7487
const disabledMods = modList.filter((m) => !m.isEnabled()).map((m) => m.getName());
7588

76-
for (const comboMod of comboList) {
89+
for (const [index, comboMod] of comboList.entries()) {
7790
const manifestMod: ManifestV2 = new ManifestV2().fromThunderstoreMod(comboMod.getMod(), comboMod.getVersion());
7891

7992
const installError: R2Error | null = await ProfileInstallerProvider.instance.installMod(manifestMod, profile);
@@ -94,6 +107,9 @@ export async function installModsToProfile(comboList: ThunderstoreCombo[], modLi
94107
modToDisable.disable();
95108
});
96109
}
110+
111+
const progress = Math.floor((index/comboList.length) * 100);
112+
progressCallback(`Copying mods to profile: ${progress}%`);
97113
}
98114
}
99115

@@ -127,18 +143,21 @@ export async function populateImportedProfile(
127143
exportModList: ExportMod[],
128144
profileName: string,
129145
isUpdate: boolean,
130-
zipPath: string
146+
zipPath: string,
147+
progressCallback: (status: string) => void
131148
) {
132149
const profile = new ImmutableProfile(isUpdate ? '_profile_update' : profileName);
133150

134151
if (isUpdate) {
152+
progressCallback('Cleaning up...');
135153
await FileUtils.recursiveRemoveDirectoryIfExists(profile.getProfilePath());
136154
}
137155

138-
await installModsToProfile(comboList, exportModList, profile);
139-
await extractImportedProfileConfigs(zipPath, profile.getProfileName());
156+
await installModsToProfile(comboList, exportModList, profile, progressCallback);
157+
await extractImportedProfileConfigs(zipPath, profile.getProfileName(), progressCallback);
140158

141159
if (isUpdate) {
160+
progressCallback('Applying changes to updated profile...');
142161
const targetProfile = new ImmutableProfile(profileName);
143162
await FileUtils.recursiveRemoveDirectoryIfExists(targetProfile.getProfilePath());
144163
await FsProvider.instance.rename(profile.getProfilePath(), targetProfile.getProfilePath());

0 commit comments

Comments
 (0)