diff --git a/core/src/com/unciv/ui/pickerscreens/ModManagementScreen.kt b/core/src/com/unciv/ui/pickerscreens/ModManagementScreen.kt index 04ca870a22..a0a0987151 100644 --- a/core/src/com/unciv/ui/pickerscreens/ModManagementScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/ModManagementScreen.kt @@ -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 + 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() diff --git a/core/src/com/unciv/ui/pickerscreens/PickerScreen.kt b/core/src/com/unciv/ui/pickerscreens/PickerScreen.kt index c83d89d7b2..91a38f8d10 100644 --- a/core/src/com/unciv/ui/pickerscreens/PickerScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/PickerScreen.kt @@ -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) } + } } \ No newline at end of file diff --git a/core/src/com/unciv/ui/worldscreen/mainmenu/DropBox.kt b/core/src/com/unciv/ui/worldscreen/mainmenu/DropBox.kt index 58656741c0..91ac821963 100644 --- a/core/src/com/unciv/ui/worldscreen/mainmenu/DropBox.kt +++ b/core/src/com/unciv/ui/worldscreen/mainmenu/DropBox.kt @@ -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/-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 { + 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() + } + + 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 diff --git a/tests/src/com/unciv/testing/BasicTests.kt b/tests/src/com/unciv/testing/BasicTests.kt index 6dc449eadc..b48aab6a23 100644 --- a/tests/src/com/unciv/testing/BasicTests.kt +++ b/tests/src/com/unciv/testing/BasicTests.kt @@ -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()) + } } \ No newline at end of file