Compare commits

..

No commits in common. "main" and "v0.5.5" have entirely different histories.
main ... v0.5.5

15 changed files with 134 additions and 252 deletions

View File

@ -1,27 +0,0 @@
name: Java Gradle Build
on:
pull_request
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up JDK 8
uses: actions/setup-java@v2
with:
java-version: '8'
distribution: 'temurin'
cache: gradle
- name: Build with Gradle
run: ./gradlew build
- name: Cleanup Gradle Cache
# Remove some files from the Gradle cache, so they aren't cached by GitHub Actions.
# Restoring these files from a GitHub Actions cache might cause problems for future builds.
run: |
rm -f ~/.gradle/caches/modules-2/modules-2.lock
rm -f ~/.gradle/caches/modules-2/gc.properties

View File

@ -1,9 +1,6 @@
name: Java Gradle Snapshot
on:
push:
branches:
- 'main'
on: ["push", "pull_request"]
jobs:
build:

View File

@ -21,7 +21,6 @@ import java.nio.file.StandardCopyOption
internal class DownloadTask private constructor(val metadata: IndexFile.File, val index: IndexFile, private val downloadSide: Side) : IOptionDetails {
var cachedFile: ManifestFile.File? = null
private set
private var err: Exception? = null
val exceptionDetails get() = err?.let { e -> ExceptionDetails(name, e) }
@ -29,30 +28,16 @@ internal class DownloadTask private constructor(val metadata: IndexFile.File, va
fun failed() = err != null
var alreadyUpToDate = false
private set
private var metadataRequired = true
private var invalidated = false
// If file is new or isOptional changed to true, the option needs to be presented again
private var newOptional = true
var completionStatus = CompletionStatus.INCOMPLETE
private set
enum class CompletionStatus {
INCOMPLETE,
DOWNLOADED,
ALREADY_EXISTS_CACHED,
ALREADY_EXISTS_VALIDATED,
SKIPPED_DISABLED,
SKIPPED_WRONG_SIDE,
DELETED_DISABLED,
DELETED_WRONG_SIDE;
}
val isOptional get() = metadata.linkedFile?.option?.optional ?: false
fun isNewOptional() = isOptional && newOptional
fun correctSide() = metadata.linkedFile?.side?.let { downloadSide.hasSide(it) } ?: true
fun correctSide() = metadata.linkedFile?.side?.hasSide(downloadSide) ?: true
override val name get() = metadata.name
@ -91,7 +76,6 @@ internal class DownloadTask private constructor(val metadata: IndexFile.File, va
if (currHash == cachedFile.hash) { // Already up to date
alreadyUpToDate = true
metadataRequired = false
completionStatus = CompletionStatus.ALREADY_EXISTS_CACHED
}
}
if (cachedFile.isOptional) {
@ -125,12 +109,12 @@ internal class DownloadTask private constructor(val metadata: IndexFile.File, va
cachedFile.optionValue = linkedFile.option.defaultValue
}
}
}
cachedFile.isOptional = isOptional
cachedFile.onlyOtherSide = !correctSide()
}
}
}
}
/**
* Check if the file in the destination location is already valid
@ -159,7 +143,6 @@ internal class DownloadTask private constructor(val metadata: IndexFile.File, va
fileSource.buffer().readAll(blackholeSink())
if (hash == fileSource.hash) {
alreadyUpToDate = true
completionStatus = CompletionStatus.ALREADY_EXISTS_VALIDATED
// Update the manifest file
cachedFile = (cachedFile ?: ManifestFile.File()).also {
@ -198,18 +181,10 @@ internal class DownloadTask private constructor(val metadata: IndexFile.File, va
if (it.cachedLocation != null) {
// Ensure wrong-side or optional false files are removed
try {
completionStatus = if (Files.deleteIfExists(it.cachedLocation!!.nioPath)) {
if (correctSide()) { CompletionStatus.DELETED_DISABLED } else { CompletionStatus.DELETED_WRONG_SIDE }
} else {
if (correctSide()) { CompletionStatus.SKIPPED_DISABLED } else { CompletionStatus.SKIPPED_WRONG_SIDE }
}
Files.deleteIfExists(it.cachedLocation!!.nioPath)
} catch (e: IOException) {
Log.warn("Failed to delete file", e)
}
} else {
completionStatus =
if (correctSide()) { CompletionStatus.SKIPPED_DISABLED }
else { CompletionStatus.SKIPPED_WRONG_SIDE }
}
it.cachedLocation = null
return
@ -309,8 +284,6 @@ internal class DownloadTask private constructor(val metadata: IndexFile.File, va
}
}
}
completionStatus = CompletionStatus.DOWNLOADED
}
companion object {

View File

@ -48,7 +48,6 @@ class LauncherUtils internal constructor(private val opts: UpdateManager.Options
val modLoaders = hashMapOf(
"net.minecraft" to "minecraft",
"net.minecraftforge" to "forge",
"net.neoforged" to "neoforge",
"net.fabricmc.fabric-loader" to "fabric",
"org.quiltmc.quilt-loader" to "quilt",
"com.mumfrey.liteloader" to "liteloader"
@ -60,7 +59,6 @@ class LauncherUtils internal constructor(private val opts: UpdateManager.Options
"org.lwjgl" to -1,
"org.lwjgl3" to -1,
"net.minecraftforge" to 5,
"net.neoforged" to 5,
"net.fabricmc.fabric-loader" to 10,
"org.quiltmc.quilt-loader" to 10,
"com.mumfrey.liteloader" to 10,

View File

@ -103,13 +103,10 @@ class Main(args: Array<String>) {
val manifestFile = ui.wrap("Invalid manifest file path") {
packFolder / (cmd.getOptionValue("meta-file") ?: "packwiz.json")
}
val timeout = ui.wrap("Invalid timeout value") {
cmd.getOptionValue("timeout")?.toLong() ?: 10
}
// Start update process!
try {
UpdateManager(UpdateManager.Options(packFile, manifestFile, packFolder, multimcFolder, side, timeout), ui)
UpdateManager(UpdateManager.Options(packFile, manifestFile, packFolder, multimcFolder, side), ui)
} catch (e: Exception) {
ui.showErrorAndExit("Update process failed", e)
}
@ -126,7 +123,6 @@ class Main(args: Array<String>) {
options.addOption(null, "pack-folder", true, "Folder to install the pack to (defaults to the JAR directory)")
options.addOption(null, "multimc-folder", true, "The MultiMC pack folder (defaults to the parent of the pack directory)")
options.addOption(null, "meta-file", true, "JSON file to store pack metadata, relative to the pack folder (defaults to packwiz.json)")
options.addOption("t", "timeout", true, "Seconds to wait before automatically launching when asking about optional mods (defaults to 10)")
}
// TODO: link these somehow so they're only defined once?

View File

@ -23,6 +23,7 @@ import link.infra.packwiz.installer.ui.IUserInterface.ExceptionListResult
import link.infra.packwiz.installer.ui.data.InstallProgress
import link.infra.packwiz.installer.util.Log
import okio.buffer
import java.io.FileWriter
import java.io.IOException
import java.io.InputStreamReader
import java.nio.charset.StandardCharsets
@ -47,8 +48,7 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
val manifestFile: PackwizFilePath,
val packFolder: PackwizFilePath,
val multimcFolder: PackwizFilePath,
val side: Side,
val timeout: Long,
val side: Side
)
// TODO: make this return a value based on results?
@ -127,11 +127,8 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
ui.submitProgress(InstallProgress("Checking local files..."))
// If the side changes, invalidate EVERYTHING (even when the index hasn't changed)
val invalidateAll = opts.side != manifest.cachedSide
val invalidatedUris: MutableList<PackwizFilePath> = ArrayList()
if (!invalidateAll) {
// Invalidation checking must be done here, as it must happen before pack/index hashes are checked
val invalidatedUris: MutableList<PackwizFilePath> = ArrayList()
for ((fileUri, file) in manifest.cachedFiles) {
// ignore onlyOtherSide files
if (file.onlyOtherSide) {
@ -160,13 +157,12 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
// todo: --force?
ui.submitProgress(InstallProgress("Modpack is already up to date!", 1, 1))
if (manifest.cachedFiles.any { it.value.isOptional }) {
ui.awaitOptionalButton(false, opts.timeout)
ui.awaitOptionalButton(false)
}
if (!ui.optionsButtonPressed) {
return
}
}
}
Log.info("Modpack name: ${pf.name}")
@ -181,7 +177,6 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
pf.index.hashFormat,
manifest,
invalidatedUris,
invalidateAll,
clientHolder
)
} catch (e1: Exception) {
@ -201,18 +196,17 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
manifest.cachedSide = opts.side
try {
Files.newBufferedWriter(opts.manifestFile.nioPath, StandardCharsets.UTF_8).use { writer -> gson.toJson(manifest, writer) }
FileWriter(opts.manifestFile.nioPath.toFile()).use { writer -> gson.toJson(manifest, writer) }
} catch (e: IOException) {
ui.showErrorAndExit("Failed to save local manifest file", e)
}
}
private fun processIndex(indexUri: PackwizPath<*>, indexHash: Hash<*>, hashFormat: HashFormat<*>, manifest: ManifestFile, invalidatedFiles: List<PackwizFilePath>, invalidateAll: Boolean, clientHolder: ClientHolder) {
if (!invalidateAll) {
private fun processIndex(indexUri: PackwizPath<*>, indexHash: Hash<*>, hashFormat: HashFormat<*>, manifest: ManifestFile, invalidatedFiles: List<PackwizFilePath>, clientHolder: ClientHolder) {
if (manifest.indexFileHash == indexHash && invalidatedFiles.isEmpty()) {
ui.submitProgress(InstallProgress("Modpack files are already up to date!", 1, 1))
if (manifest.cachedFiles.any { it.value.isOptional }) {
ui.awaitOptionalButton(false, opts.timeout)
ui.awaitOptionalButton(false)
}
if (!ui.optionsButtonPressed) {
return
@ -222,7 +216,6 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
return
}
}
}
manifest.indexFileHash = indexHash
val indexFileSource = try {
@ -247,17 +240,31 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
}
ui.submitProgress(InstallProgress("Checking local files..."))
// TODO: use kotlin filtering/FP rather than an iterator?
val it: MutableIterator<Map.Entry<PackwizFilePath, ManifestFile.File>> = manifest.cachedFiles.entries.iterator()
while (it.hasNext()) {
val (uri, file) = it.next()
if (file.cachedLocation != null) {
var alreadyDeleted = false
// Delete if option value has been set to false
if (file.isOptional && !file.optionValue) {
try {
Files.deleteIfExists(file.cachedLocation!!.nioPath)
} catch (e: IOException) {
Log.warn("Failed to delete optional disabled file", e)
}
// Set to null, as it doesn't exist anymore
file.cachedLocation = null
alreadyDeleted = true
}
if (indexFile.files.none { it.file.rebase(opts.packFolder) == uri }) { // File has been removed from the index
if (!alreadyDeleted) {
try {
Files.deleteIfExists(file.cachedLocation!!.nioPath)
} catch (e: IOException) {
Log.warn("Failed to delete file removed from index", e)
}
Log.info("Deleted ${file.cachedLocation!!.filename} (removed from pack)")
}
it.remove()
}
}
@ -274,6 +281,9 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
Log.warn("Index is empty!")
}
val tasks = createTasksFromIndex(indexFile, opts.side)
// If the side changes, invalidate EVERYTHING just in case
// Might not be needed, but done just to be safe
val invalidateAll = opts.side != manifest.cachedSide
if (invalidateAll) {
Log.info("Side changed, invalidating all mods")
}
@ -328,7 +338,7 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
if (!ui.optionsButtonPressed) {
// TODO: this is so ugly
ui.submitProgress(InstallProgress("Reconfigure optional mods?", 0,1))
ui.awaitOptionalButton(true, opts.timeout)
ui.awaitOptionalButton(true)
if (ui.cancelButtonPressed) {
showCancellationDialog()
return
@ -387,16 +397,7 @@ class UpdateManager internal constructor(private val opts: Options, val ui: IUse
val progress = if (exDetails != null) {
"Failed to download ${exDetails.name}: ${exDetails.exception.message}"
} else {
when (task.completionStatus) {
DownloadTask.CompletionStatus.INCOMPLETE -> "${task.name} pending (you should never see this...)"
DownloadTask.CompletionStatus.DOWNLOADED -> "Downloaded ${task.name}"
DownloadTask.CompletionStatus.ALREADY_EXISTS_CACHED -> "${task.name} already exists (cached)"
DownloadTask.CompletionStatus.ALREADY_EXISTS_VALIDATED -> "${task.name} already exists (validated)"
DownloadTask.CompletionStatus.SKIPPED_DISABLED -> "Skipped ${task.name} (disabled)"
DownloadTask.CompletionStatus.SKIPPED_WRONG_SIDE -> "Skipped ${task.name} (wrong side)"
DownloadTask.CompletionStatus.DELETED_DISABLED -> "Deleted ${task.name} (disabled)"
DownloadTask.CompletionStatus.DELETED_WRONG_SIDE -> "Deleted ${task.name} (wrong side)"
}
"Downloaded ${task.name}"
}
ui.submitProgress(InstallProgress(progress, i + 1, tasks.size))

View File

@ -49,15 +49,14 @@ private val APIKey = "JDJhJDEwJHNBWVhqblU1N0EzSmpzcmJYM3JVdk92UWk2NHBLS3BnQ2VpbG
@Throws(JsonSyntaxException::class, JsonIOException::class)
fun resolveCfMetadata(mods: List<IndexFile.File>, packFolder: PackwizFilePath, clientHolder: ClientHolder): List<ExceptionDetails> {
val failures = mutableListOf<ExceptionDetails>()
val fileIdMap = mutableMapOf<Int, List<IndexFile.File>>()
val fileIdMap = mutableMapOf<Int, IndexFile.File>()
for (mod in mods) {
if (!mod.linkedFile!!.update.contains("curseforge")) {
failures.add(ExceptionDetails(mod.linkedFile!!.name, Exception("Failed to resolve CurseForge metadata: no CurseForge update section")))
continue
}
val fileId = (mod.linkedFile!!.update["curseforge"] as CurseForgeUpdateData).fileId
fileIdMap[fileId] = (fileIdMap[fileId] ?: listOf()) + mod
fileIdMap[(mod.linkedFile!!.update["curseforge"] as CurseForgeUpdateData).fileId] = mod
}
val reqData = GetFilesRequest(fileIdMap.keys.toList())
@ -78,7 +77,7 @@ fun resolveCfMetadata(mods: List<IndexFile.File>, packFolder: PackwizFilePath, c
val resData = Gson().fromJson(res.body!!.charStream(), GetFilesResponse::class.java)
res.closeQuietly()
val manualDownloadMods = mutableMapOf<Int, List<Int>>()
val manualDownloadMods = mutableMapOf<Int, Pair<IndexFile.File, Int>>()
for (file in resData.data) {
if (!fileIdMap.contains(file.id)) {
failures.add(ExceptionDetails(file.id.toString(),
@ -86,14 +85,12 @@ fun resolveCfMetadata(mods: List<IndexFile.File>, packFolder: PackwizFilePath, c
continue
}
if (file.downloadUrl == null) {
manualDownloadMods[file.modId] = (manualDownloadMods[file.modId] ?: listOf()) + file.id
manualDownloadMods[file.modId] = Pair(fileIdMap[file.id]!!, file.id)
continue
}
try {
for (indexFile in fileIdMap[file.id]!!) {
indexFile.linkedFile!!.resolvedUpdateData["curseforge"] =
fileIdMap[file.id]!!.linkedFile!!.resolvedUpdateData["curseforge"] =
HttpUrlPath(file.downloadUrl!!.toHttpUrl())
}
} catch (e: IllegalArgumentException) {
failures.add(ExceptionDetails(file.id.toString(),
Exception("Failed to parse URL: ${file.downloadUrl} for ID ${file.id}, Project ID ${file.modId}", e)))
@ -102,13 +99,10 @@ fun resolveCfMetadata(mods: List<IndexFile.File>, packFolder: PackwizFilePath, c
// Some file types don't show up in the API at all! (e.g. shaderpacks)
// Add unresolved files to manualDownloadMods
for ((fileId, indexFiles) in fileIdMap) {
for (file in indexFiles) {
for ((fileId, file) in fileIdMap) {
if (file.linkedFile != null) {
if (file.linkedFile!!.resolvedUpdateData["curseforge"] == null) {
val projectId = (file.linkedFile!!.update["curseforge"] as CurseForgeUpdateData).projectId
manualDownloadMods[projectId] = (manualDownloadMods[projectId] ?: listOf()) + fileId
}
manualDownloadMods[(file.linkedFile!!.update["curseforge"] as CurseForgeUpdateData).projectId] = Pair(file, fileId)
}
}
}
@ -139,19 +133,9 @@ fun resolveCfMetadata(mods: List<IndexFile.File>, packFolder: PackwizFilePath, c
continue
}
for (fileId in manualDownloadMods[mod.id]!!) {
if (!fileIdMap.contains(fileId)) {
failures.add(ExceptionDetails(mod.name,
Exception("Failed to find file from result: file ID $fileId")))
continue
}
for (indexFile in fileIdMap[fileId]!!) {
var modUrl = "${mod.links?.websiteUrl}/files/${fileId}"
failures.add(ExceptionDetails(indexFile.name, Exception("This mod is excluded from the CurseForge API and must be downloaded manually.\n" +
"Please go to ${modUrl} and save this file to ${indexFile.destURI.rebase(packFolder).nioPath.absolute()}"), modUrl))
}
}
val modFile = manualDownloadMods[mod.id]!!
failures.add(ExceptionDetails(mod.name, Exception("This mod is excluded from the CurseForge API and must be downloaded manually.\n" +
"Please go to ${mod.links?.websiteUrl}/files/${modFile.second} and save this file to ${modFile.first.destURI.rebase(packFolder).nioPath.absolute()}")))
}
}

View File

@ -8,12 +8,9 @@ import java.net.SocketTimeoutException
import java.util.concurrent.TimeUnit
class ClientHolder {
// Tries 10s timeouts (default), then 15s timeouts, then 60s timeouts
private val retryTimes = arrayOf(15, 60)
// TODO: a button to increase timeouts temporarily when retrying? manual retry button?
val okHttpClient by lazy { OkHttpClient.Builder()
// Retry requests according to retryTimes list
// Retry requests up to 3 times, increasing the timeouts slightly if it failed
.addInterceptor {
val req = it.request()
@ -27,20 +24,20 @@ class ClientHolder {
}
var tryCount = 0
while (res == null && tryCount < retryTimes.size) {
Log.info("OkHttp connection to ${req.url} timed out; retrying... (${tryCount + 1}/${retryTimes.size})")
while (res == null && tryCount < 3) {
tryCount++
Log.info("OkHttp connection to ${req.url} timed out; retrying... ($tryCount/3)")
val longerTimeoutChain = it
.withConnectTimeout(retryTimes[tryCount], TimeUnit.SECONDS)
.withReadTimeout(retryTimes[tryCount], TimeUnit.SECONDS)
.withWriteTimeout(retryTimes[tryCount], TimeUnit.SECONDS)
.withConnectTimeout(10 * tryCount, TimeUnit.SECONDS)
.withReadTimeout(10 * tryCount, TimeUnit.SECONDS)
.withWriteTimeout(10 * tryCount, TimeUnit.SECONDS)
try {
res = longerTimeoutChain.proceed(req)
} catch (e: SocketTimeoutException) {
lastException = e
}
tryCount++
}
res ?: throw lastException!!

View File

@ -4,29 +4,42 @@ import cc.ekblad.toml.model.TomlValue
import cc.ekblad.toml.tomlMapper
import com.google.gson.annotations.SerializedName
enum class Side(sideName: String) {
enum class Side {
@SerializedName("client")
CLIENT("client"),
@SerializedName("server")
SERVER("server"),
@SerializedName("both")
@Suppress("unused")
BOTH("both") {
override fun hasSide(tSide: Side): Boolean {
return true
}
};
BOTH("both", arrayOf(CLIENT, SERVER));
private val sideName: String
private val depSides: Array<Side>?
init {
constructor(sideName: String) {
this.sideName = sideName.lowercase()
depSides = null
}
constructor(sideName: String, depSides: Array<Side>) {
this.sideName = sideName.lowercase()
this.depSides = depSides
}
override fun toString() = sideName
open fun hasSide(tSide: Side): Boolean {
return this == tSide || tSide == BOTH
fun hasSide(tSide: Side): Boolean {
if (this == tSide) {
return true
}
if (depSides != null) {
for (depSide in depSides) {
if (depSide == tSide) {
return true
}
}
}
return false
}
companion object {

View File

@ -23,12 +23,9 @@ interface IUserInterface {
fun showCancellationDialog(): CancellationResult = CancellationResult.QUIT
fun showUpdateConfirmationDialog(oldVersions: List<Pair<String, String?>>, newVersions: List<Pair<String, String?>>): UpdateConfirmationResult {
// Always update metadata when using the CLI
return UpdateConfirmationResult.UPDATE
}
fun showUpdateConfirmationDialog(oldVersions: List<Pair<String, String?>>, newVersions: List<Pair<String, String?>>): UpdateConfirmationResult = UpdateConfirmationResult.CANCELLED
fun awaitOptionalButton(showCancel: Boolean, timeout: Long)
fun awaitOptionalButton(showCancel: Boolean)
enum class ExceptionListResult {
CONTINUE, CANCEL, IGNORE

View File

@ -63,7 +63,7 @@ class CLIHandler : IUserInterface {
return ExceptionListResult.CANCEL
}
override fun awaitOptionalButton(showCancel: Boolean, timeout: Long) {
override fun awaitOptionalButton(showCancel: Boolean) {
// Do nothing
}
}

View File

@ -2,6 +2,5 @@ package link.infra.packwiz.installer.ui.data
data class ExceptionDetails(
val name: String,
val exception: Exception,
val modUrl: String? = null
val exception: Exception
)

View File

@ -1,6 +1,5 @@
package link.infra.packwiz.installer.ui.gui
import link.infra.packwiz.installer.util.Log
import link.infra.packwiz.installer.ui.IUserInterface
import link.infra.packwiz.installer.ui.data.ExceptionDetails
import java.awt.BorderLayout
@ -25,24 +24,6 @@ class ExceptionListWindow(eList: List<ExceptionDetails>, future: CompletableFutu
fun getExceptionAt(index: Int) = details[index].exception
}
private fun openUrl(url: String) {
try {
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
Desktop.getDesktop().browse(URI(url))
} else {
val process = Runtime.getRuntime().exec(arrayOf("xdg-open", url));
val exitValue = process.waitFor()
if (exitValue > 0) {
Log.warn("Failed to open $url: xdg-open exited with code $exitValue")
}
}
} catch (e: IOException) {
Log.warn("Failed to open $url", e)
} catch (e: URISyntaxException) {
Log.warn("Failed to open $url", e)
}
}
/**
* Create the dialog.
*/
@ -131,19 +112,6 @@ class ExceptionListWindow(eList: List<ExceptionDetails>, future: CompletableFutu
this@ExceptionListWindow.dispose()
}
})
val missingMods = eList.filter { it.modUrl != null }.map { it.modUrl!! }.toSet()
if (!missingMods.isEmpty()) {
add(JButton("Open missing mods").apply {
toolTipText = "Open missing mods in your browser"
addActionListener {
missingMods.forEach {
openUrl(it)
}
}
})
}
}, BorderLayout.EAST)
// Errored label
@ -154,8 +122,16 @@ class ExceptionListWindow(eList: List<ExceptionDetails>, future: CompletableFutu
// Left buttons
add(JPanel().apply {
add(JButton("Report issue").apply {
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
addActionListener {
openUrl("https://github.com/packwiz/packwiz-installer/issues/new")
try {
Desktop.getDesktop().browse(URI("https://github.com/packwiz/packwiz-installer/issues/new"))
} catch (e: IOException) {
// lol the button just won't work i guess
} catch (e: URISyntaxException) {}
}
} else {
isEnabled = false
}
})
}, BorderLayout.WEST)

View File

@ -7,13 +7,11 @@ import link.infra.packwiz.installer.ui.data.IOptionDetails
import link.infra.packwiz.installer.ui.data.InstallProgress
import link.infra.packwiz.installer.util.Log
import java.awt.EventQueue
import java.util.Timer
import java.util.concurrent.CompletableFuture
import java.util.concurrent.CountDownLatch
import javax.swing.JDialog
import javax.swing.JOptionPane
import javax.swing.UIManager
import kotlin.concurrent.timer
import kotlin.system.exitProcess
class GUIHandler : IUserInterface {
@ -222,28 +220,12 @@ class GUIHandler : IUserInterface {
return future.get()
}
override fun awaitOptionalButton(showCancel: Boolean, timeout: Long) {
override fun awaitOptionalButton(showCancel: Boolean) {
EventQueue.invokeAndWait {
frmPackwizlauncher.showOk(!showCancel)
}
visibleCountdownLatch.await()
var closeTimer: Timer? = null
if (timeout >= 0) {
var count = 0
closeTimer = timer("timeout", true, 0, 1000) {
if (count >= timeout) {
optionalSelectedLatch.countDown()
cancel()
} else {
frmPackwizlauncher.timeoutOk(timeout - count)
count += 1
}
};
}
optionalSelectedLatch.await()
closeTimer?.cancel()
EventQueue.invokeLater {
frmPackwizlauncher.hideOk()
}

View File

@ -121,8 +121,4 @@ class InstallWindow(private val handler: GUIHandler) : JFrame() {
}
buttonsPanel.revalidate()
}
fun timeoutOk(remaining: Long) {
btnOk.text = "Continue ($remaining)"
}
}