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)
This commit is contained in:
yairm210 2022-01-19 19:20:34 +02:00
parent 682d65f02e
commit ab0ff2e33e

View File

@ -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<String> = mutableSetOf()
val duplicates: MutableList<Cell<Actor>> = 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<String, ModUIData>, scroll: ScrollPane) {
private fun syncSelected(modName: String, button: Button, modNameToData: HashMap<String, ModUIData>, 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<String>::class.java, blockedModsFile)
}
val modsToHideNames = run {
val modsToHideNames by lazy {
val regex = Regex(""".*/([^/]+)/?$""")
modsToHideAsUrl.map { url ->
regex.replace(url) { it.groups[1]!!.value }.replace('-', ' ')