From ab0ff2e33ee8c0b975552beda55360e0ab7ca9b6 Mon Sep 17 00:00:00 2001 From: yairm210 Date: Wed, 19 Jan 2022 19:20:34 +0200 Subject: [PATCH] Made some of this stuff more readable I came to the mod management screen to add a functionality to download the latest version of an installed mod by adding a 'download latest version' button to its action menu. I did not expect the code to be this intractable. I've been reading and writing Kotlin daily for the past 5 years now, and even I struggle to understand what's going on here. (also instead of adding button and counting duplicate entries just to remove them from both UI and count, just - don't add them to begin with) --- .../ui/pickerscreens/ModManagementScreen.kt | 86 +++++++++---------- 1 file changed, 39 insertions(+), 47 deletions(-) diff --git a/core/src/com/unciv/ui/pickerscreens/ModManagementScreen.kt b/core/src/com/unciv/ui/pickerscreens/ModManagementScreen.kt index 9950ed6c49..aca57d5c38 100644 --- a/core/src/com/unciv/ui/pickerscreens/ModManagementScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/ModManagementScreen.kt @@ -21,7 +21,6 @@ import com.unciv.ui.utils.UncivDateFormat.parseDate import com.unciv.ui.worldscreen.mainmenu.Github import java.util.* import kotlin.collections.HashMap -import kotlin.concurrent.thread import kotlin.math.max /** @@ -218,28 +217,35 @@ class ModManagementScreen( if (stopBackgroundTasks) return@postCrashHandlingRunnable repo.name = repo.name.replace('-', ' ') + if (onlineModInfo.containsKey(repo.name)) + continue // we already got this mod in a previous download, since one has been added in between + + downloadModCount++ // this should appear BEFORE the 'hide' since we use this to compare to the total amount of mods downloaded + // Mods we have manually decided to remove for instability are removed here // If at some later point these mods are updated, we should definitely remove // this piece of code. This is a band-aid, not a full solution. if (repo.html_url in modsToHideAsUrl) continue - val existingMod = RulesetCache.values.firstOrNull { it.name == repo.name } - val isUpdated = existingMod?.modOptions?.let { + val installedMod = RulesetCache.values.firstOrNull { it.name == repo.name } + val isUpdatedVersionOfInstalledMod = installedMod?.modOptions?.let { it.lastUpdated != "" && it.lastUpdated != repo.updated_at } == true - if (existingMod != null) { - if (isUpdated) { - installedModInfo[repo.name]?.state?.isUpdated = true + if (installedMod != null) { + + if (isUpdatedVersionOfInstalledMod) { + installedModInfo[repo.name]!!.state.isUpdated = true } - if (existingMod.modOptions.author.isEmpty()) { + + if (installedMod.modOptions.author.isEmpty()) { rewriteModOptions(repo, Gdx.files.local("mods").child(repo.name)) - existingMod.modOptions.author = repo.owner.login - existingMod.modOptions.modSize = repo.size + installedMod.modOptions.author = repo.owner.login + installedMod.modOptions.modSize = repo.size } } - val mod = ModUIData(repo, isUpdated) + val mod = ModUIData(repo, isUpdatedVersionOfInstalledMod) onlineModInfo[repo.name] = mod mod.button.onClick { onlineButtonAction(repo, mod.button) } @@ -249,28 +255,11 @@ class ModManagementScreen( mod.y = onlineScrollCurrentY mod.height = cell.prefHeight onlineScrollCurrentY += cell.padBottom + cell.prefHeight + cell.padTop - downloadModCount++ } // Now the tasks after the 'page' of search results has been fully processed + // The search has reached the last page! if (repoSearch.items.size < amountPerPage) { - // The search has reached the last page! - // Check: due to time passing between github calls it is not impossible we get a mod twice - val checkedMods: MutableSet = mutableSetOf() - val duplicates: MutableList> = mutableListOf() - downloadTable.cells.forEach { - cell-> - cell.actor?.name?.apply { - if (checkedMods.contains(this)) { - duplicates.add(cell) - } else checkedMods.add(this) - } - } - duplicates.forEach { - it.setActor(null) - downloadTable.cells.removeValue(it, true) - } - downloadModCount -= duplicates.size // Check: It is also not impossible we missed a mod - just inform user if (repoSearch.total_count > downloadModCount || repoSearch.incomplete_results) { val retryLabel = "Online query result is incomplete".toLabel(Color.RED) @@ -297,13 +286,13 @@ class ModManagementScreen( } } - private fun syncOnlineSelected(name: String, button: Button) { - syncSelected(name, button, installedModInfo, scrollInstalledMods) + private fun syncOnlineSelected(modName: String, button: Button) { + syncSelected(modName, button, installedModInfo, scrollInstalledMods) } - private fun syncInstalledSelected(name: String, button: Button) { - syncSelected(name, button, onlineModInfo, scrollOnlineMods) + private fun syncInstalledSelected(modName: String, button: Button) { + syncSelected(modName, button, onlineModInfo, scrollOnlineMods) } - private fun syncSelected(name: String, button: Button, index: HashMap, scroll: ScrollPane) { + private fun syncSelected(modName: String, button: Button, modNameToData: HashMap, scroll: ScrollPane) { // manage selection color for user selection lastSelectedButton?.color = Color.WHITE button.color = Color.BLUE @@ -312,7 +301,7 @@ class ModManagementScreen( lastSyncMarkedButton?.color = Color.WHITE lastSyncMarkedButton = null // look for sync-able same mod in other list - val pos = index[name] ?: return + val pos = modNameToData[modName] ?: return // scroll into view scroll.scrollY = (pos.y + (pos.height - scroll.height) / 2).coerceIn(0f, scroll.maxY) // and color it so it's easier to find. ROYAL and SLATE too dark. @@ -464,7 +453,7 @@ class ModManagementScreen( /** Rebuild the right-hand column for clicks on installed mods * Display single mod metadata, offer additional actions (delete is elsewhere) */ - private fun refreshModActions(mod: Ruleset) { + private fun refreshInstalledModActions(mod: Ruleset) { modActionTable.clear() // show mod information first addModInfoToActionTable(mod.name, mod.modOptions) @@ -482,23 +471,26 @@ class ModManagementScreen( visualMods.remove(mod.name) game.settings.save() ImageGetter.setNewRuleset(ImageGetter.ruleset) - refreshModActions(mod) + refreshInstalledModActions(mod) if (optionsManager.sortInstalled == SortType.Status) refreshInstalledModTable() } modActionTable.add(visualCheckBox).row() } + /* + + */ + /** Rebuild the left-hand column containing all installed mods */ internal fun refreshInstalledModTable() { // pre-init if not already done - important: keep the ModUIData instances later on or // at least the button references otherwise sync will not work if (installedModInfo.isEmpty()) { for (mod in RulesetCache.values.asSequence().filter { it.name != "" }) { - ModUIData(mod).run { - state.isVisual = mod.name in game.settings.visualMods - installedModInfo[mod.name] = this - } + val modUIData = ModUIData(mod) + modUIData.state.isVisual = mod.name in game.settings.visualMods + installedModInfo[mod.name] = modUIData } } @@ -529,7 +521,7 @@ class ModManagementScreen( private fun installedButtonAction(mod: ModUIData) { syncInstalledSelected(mod.name, mod.button) - refreshModActions(mod.ruleset!!) + refreshInstalledModActions(mod.ruleset!!) rightSideButton.setText("Delete [${mod.name}]".tr()) rightSideButton.isEnabled = true showModDescription(mod.name) @@ -587,11 +579,11 @@ class ModManagementScreen( } private fun showModDescription(modName: String) { - val online = onlineModInfo[modName]?.description ?: "" - val installed = installedModInfo[modName]?.description ?: "" - val separator = if (online.isEmpty() || installed.isEmpty()) "" else "\n" + val onlineModDescription = onlineModInfo[modName]?.description ?: "" // shows github info + val installedModDescription = installedModInfo[modName]?.description ?: "" // shows ruleset info + val separator = if (onlineModDescription.isEmpty() || installedModDescription.isEmpty()) "" else "\n" deprecationCell.setActor(if (modName in modsToHideNames) deprecationLabel else null) - modDescriptionLabel.setText(online + separator + installed) + modDescriptionLabel.setText(onlineModDescription + separator + installedModDescription) } override fun resize(width: Int, height: Int) { @@ -602,11 +594,11 @@ class ModManagementScreen( } companion object { - val modsToHideAsUrl = run { + val modsToHideAsUrl by lazy { val blockedModsFile = Gdx.files.internal("jsons/ManuallyBlockedMods.json") JsonParser().getFromJson(Array::class.java, blockedModsFile) } - val modsToHideNames = run { + val modsToHideNames by lazy { val regex = Regex(""".*/([^/]+)/?$""") modsToHideAsUrl.map { url -> regex.replace(url) { it.groups[1]!!.value }.replace('-', ' ')