Mod management screen takes its list of mods from the Github API!

This commit is contained in:
Yair Morgenstern 2020-08-26 15:57:15 +03:00
parent 0074ebfdb5
commit 36f5d22a80
4 changed files with 95 additions and 33 deletions

View File

@ -4,19 +4,18 @@ import com.badlogic.gdx.Gdx
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextArea
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener
import com.unciv.MainMenuScreen
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.RulesetCache
import com.unciv.models.translations.tr
import com.unciv.ui.utils.*
import com.unciv.ui.worldscreen.mainmenu.Zip
import com.unciv.ui.worldscreen.mainmenu.Github
import kotlin.concurrent.thread
class ModManagementScreen: PickerScreen() {
val modTable = Table().apply { defaults().pad(10f) }
val downloadTable = Table()
val downloadTable = Table().apply { defaults().pad(10f) }
init {
setDefaultCloseAction(MainMenuScreen())
@ -24,8 +23,32 @@ class ModManagementScreen: PickerScreen() {
topTable.add(modTable).pad(10f)
downloadTable.add(getDownloadButton()).row()
thread {
val repoList: ArrayList<Github.Repo>
try {
repoList = Github.tryGetGithubReposWithTopic()
} catch (ex: Exception) {
ResponsePopup("Could not download mod list", this)
return@thread
}
for (repo in repoList) {
repo.name = repo.name.replace('-',' ')
val downloadButton = repo.name.toTextButton()
downloadButton.onClick {
descriptionLabel.setText(repo.description + "\n" + "[${repo.stargazers_count}] Stars".tr())
removeRightSideClickListeners()
rightSideButton.enable()
rightSideButton.setText("Download [${repo.name}]".tr())
rightSideButton.onClick { downloadMod(repo.svn_url) }
}
downloadTable.add(downloadButton).row()
}
}
downloadTable.add(getDownloadButton())
topTable.add(downloadTable)
}
@ -37,24 +60,9 @@ class ModManagementScreen: PickerScreen() {
popup.add(textArea).width(stage.width/2).row()
val downloadButton = "Download".toTextButton()
downloadButton.onClick {
thread { // to avoid ANRs - we've learnt our lesson from previous download-related actions
try {
downloadButton.setText("Downloading...")
downloadButton.disable()
Zip.downloadAndExtract(textArea.text+"/archive/master.zip",
Gdx.files.local("mods"))
Gdx.app.postRunnable {
RulesetCache.loadRulesets()
refresh()
popup.close()
}
} catch (ex:Exception){
Gdx.app.postRunnable {
ResponsePopup("Could not download mod", this)
popup.close()
}
}
}
downloadButton.setText("Downloading...")
downloadButton.disable()
downloadMod(textArea.text) { popup.close() }
}
popup.add(downloadButton).row()
popup.addCloseButton()
@ -63,6 +71,27 @@ class ModManagementScreen: PickerScreen() {
return downloadButton
}
fun downloadMod(gitRepoUrl:String, postAction:()->Unit={}){
thread { // to avoid ANRs - we've learnt our lesson from previous download-related actions
try {
Github.downloadAndExtract(gitRepoUrl+"/archive/master.zip",
Gdx.files.local("mods"))
Gdx.app.postRunnable {
ResponsePopup("Downloaded!", this)
RulesetCache.loadRulesets()
refresh()
}
} catch (ex:Exception){
Gdx.app.postRunnable {
ResponsePopup("Could not download mod", this)
}
}
finally {
postAction()
}
}
}
fun refresh(){
modTable.clear()
val currentMods = RulesetCache.values.filter { it.name != "" }
@ -71,8 +100,7 @@ class ModManagementScreen: PickerScreen() {
rightSideButton.setText("Delete [${mod.name}]".tr())
rightSideButton.enable()
descriptionLabel.setText(mod.getSummary())
rightSideButton.listeners.filter { it != rightSideButton.clickListener }
.forEach { rightSideButton.removeListener(it) }
removeRightSideClickListeners()
rightSideButton.onClick {
YesNoPopup("Are you SURE you want to delete this mod?",
{ deleteMod(mod) }, this).open()

View File

@ -62,4 +62,9 @@ open class PickerScreen : CameraStageBaseScreen() {
if(UncivGame.Current.worldScreen.isPlayersTurn) rightSideButton.enable()
rightSideButton.setText(rightButtonText)
}
fun removeRightSideClickListeners(){
rightSideButton.listeners.filter { it != rightSideButton.clickListener }
.forEach { rightSideButton.removeListener(it) }
}
}

View File

@ -4,6 +4,7 @@ import com.badlogic.gdx.files.FileHandle
import com.unciv.logic.GameInfo
import com.unciv.logic.GameSaver
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.metadata.GameSettings
import com.unciv.ui.saves.Gzip
import java.io.*
import java.net.HttpURLConnection
@ -132,11 +133,12 @@ class OnlineMultiplayer {
}
}
object Zip {
fun downloadUrl(url:String): InputStream? {
with(URL(url).openConnection() as HttpURLConnection) {
// requestMethod = "POST" // default is GET
object Github {
// Consider merging this with the Dropbox function
fun download(url: String, action: (HttpURLConnection) -> Unit = {}): InputStream? {
with(URL(url).openConnection() as HttpURLConnection)
{
action(this)
doOutput = true
@ -153,17 +155,17 @@ object Zip {
// This took a long time to get just right, so if you're changing this, TEST IT THOROUGHLY on both Desktop and Phone
fun downloadAndExtract(url:String, folderFileHandle:FileHandle) {
val inputStream = downloadUrl(url)
val inputStream = download(url)
if (inputStream == null) return
//DropBox.downloadFile(dropboxFileLocation)
val tempZipFileHandle = folderFileHandle.child("tempZip.zip")
tempZipFileHandle.write(inputStream, false)
val unzipDestination = tempZipFileHandle.sibling("tempZip") // folder, not file
extractFolder(tempZipFileHandle, unzipDestination)
Zip.extractFolder(tempZipFileHandle, unzipDestination)
val innerFolder = unzipDestination.list().first() // tempZip/<repoName>-master/
val finalDestination = folderFileHandle.child(innerFolder.name().replace("-master",""))
val finalDestinationName = innerFolder.name().replace("-master","").replace('-',' ')
val finalDestination = folderFileHandle.child(finalDestinationName)
finalDestination.mkdirs() // If we don't create this as a directory, it will think this is a file and nothing will work.
for(innerFileOrFolder in innerFolder.list()){
innerFileOrFolder.moveTo(finalDestination)
@ -173,6 +175,27 @@ object Zip {
unzipDestination.deleteDirectory()
}
fun tryGetGithubReposWithTopic(): ArrayList<Repo> {
val inputStream = download("https://api.github.com/search/repositories?q=topic:unciv-mod")
if (inputStream == null) return ArrayList()
return GameSaver.json().fromJson(RepoSearch::class.java, inputStream!!.bufferedReader().readText()).items
}
class RepoSearch{
var items=ArrayList<Repo>()
}
class Repo {
var name = ""
var description = ""
var svn_url = ""
var stargazers_count = 0
}
}
object Zip {
// I went through a lot of similar answers that didn't work until I got to this gem by NeilMonday
// (with mild changes to fit the FileHandles)
// https://stackoverflow.com/questions/981578/how-to-unzip-files-recursively-in-java

View File

@ -12,6 +12,7 @@ import com.unciv.models.ruleset.unit.BaseUnit
import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
import com.unciv.models.translations.tr
import com.unciv.ui.worldscreen.mainmenu.Http
import com.unciv.ui.worldscreen.mainmenu.Zip
import org.junit.Assert
import org.junit.Before
@ -89,4 +90,9 @@ class BasicTests {
// Zip.downloadAndExtract("/Mods/Reasoures.zip", FileHandle("""C:\Users\LENOVO\Downloads"""))
// Zip.downloadAndExtract("https://github.com/yairm210/Unciv-IV-mod/archive/master.zip", FileHandle("""C:\Users\LENOVO\Downloads"""))
// }
@Test // This should NOT run as part of the test suite!
fun tryGetGithubTopicInfo(){
println(Http.tryGetGithubTopic())
}
}