Skip to content

Commit d3152e2

Browse files
committed
feat(mods): add Modrinth-app like version switcher + more install button states
1 parent 5722d7b commit d3152e2

16 files changed

Lines changed: 898 additions & 10 deletions

app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/fragments/ModsSearchFragment.java

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -279,22 +279,79 @@ private static class ModsInstallApi extends CommonApi {
279279
/**
280280
* Override getModDetails to filter versions by the selected MC version.
281281
* Only versions matching the filter are shown in the version dropdown.
282+
* Also resolves which (if any) of the returned versions is already
283+
* installed in the current instance's mods folder, so the install
284+
* button can show Install / Installed / Update / Downgrade.
282285
*/
283286
@Override
284287
public ModDetail getModDetails(ModItem item) {
288+
ModDetail detail;
285289
if (item.apiSource == net.kdt.pojavlaunch.modloaders.modpacks.models.Constants.SOURCE_MODRINTH) {
286290
String filterVer = (mFilters.mcVersion != null && !mFilters.mcVersion.isEmpty())
287291
? mFilters.mcVersion : null;
288292
String filterLoader = (mFilters.modLoader != null && !mFilters.modLoader.isEmpty())
289293
? mFilters.modLoader : null;
290-
return mModrinthApi.getModDetails(item, filterVer, filterLoader);
291-
}
292-
if (item.apiSource == net.kdt.pojavlaunch.modloaders.modpacks.models.Constants.SOURCE_CURSEFORGE) {
294+
detail = mModrinthApi.getModDetails(item, filterVer, filterLoader);
295+
} else if (item.apiSource == net.kdt.pojavlaunch.modloaders.modpacks.models.Constants.SOURCE_CURSEFORGE) {
293296
String filterVer = (mFilters.mcVersion != null && !mFilters.mcVersion.isEmpty())
294297
? mFilters.mcVersion : null;
295-
return mCurseforgeApi.getModDetails(item, filterVer);
298+
detail = mCurseforgeApi.getModDetails(item, filterVer);
299+
} else {
300+
detail = super.getModDetails(item);
301+
}
302+
303+
if (detail != null && !detail.isModpack) {
304+
resolveInstalledVersionIndex(detail);
305+
}
306+
return detail;
307+
}
308+
309+
/**
310+
* Hashes every jar currently in the mods folder (enabled or disabled)
311+
* and matches against detail.versionHashes to find which version, if
312+
* any, is already installed. Sets detail.installedVersionIndex
313+
* accordingly (-1 if this mod isn't installed at all).
314+
*/
315+
private void resolveInstalledVersionIndex(ModDetail detail) {
316+
detail.installedVersionIndex = -1;
317+
if (detail.versionHashes == null || detail.versionHashes.length == 0) return;
318+
319+
File modsDir = getModsDir();
320+
File[] files = modsDir.listFiles(f -> f.isFile() &&
321+
(f.getName().endsWith(".jar") || f.getName().endsWith(".jar.disabled")));
322+
if (files == null || files.length == 0) return;
323+
324+
java.util.Set<String> installedHashes = new java.util.HashSet<>();
325+
for (File f : files) {
326+
String hash = sha1Hex(f);
327+
if (hash != null) installedHashes.add(hash);
328+
}
329+
if (installedHashes.isEmpty()) return;
330+
331+
for (int i = 0; i < detail.versionHashes.length; i++) {
332+
String hash = detail.versionHashes[i];
333+
if (hash != null && installedHashes.contains(hash.toLowerCase(java.util.Locale.ROOT))) {
334+
detail.installedVersionIndex = i;
335+
break;
336+
}
337+
}
338+
}
339+
340+
private static String sha1Hex(File file) {
341+
try {
342+
java.security.MessageDigest digest = java.security.MessageDigest.getInstance("SHA-1");
343+
byte[] buffer = new byte[8192];
344+
try (java.io.FileInputStream fis = new java.io.FileInputStream(file)) {
345+
int read;
346+
while ((read = fis.read(buffer)) != -1) digest.update(buffer, 0, read);
347+
}
348+
byte[] bytes = digest.digest();
349+
StringBuilder sb = new StringBuilder(bytes.length * 2);
350+
for (byte b : bytes) sb.append(String.format("%02x", b));
351+
return sb.toString();
352+
} catch (Exception e) {
353+
return null;
296354
}
297-
return super.getModDetails(item);
298355
}
299356

300357
@Override

0 commit comments

Comments
 (0)