Fix and improve real time autofix while typing on multipleServer URL (#6772)

Sometime `TextField.cursorPosition` becomes greater than `TextField.text.length` for unknown reasons
In those cases we need to bring the cursor down to its maximum possible position which is `TextField.text.length`
Otherwise we will get `java.lang.StringIndexOutOfBoundsException` thrown from `kotlin.text.substring`
Not knowing the reason why it happens, I followed the libGDX implementation from here:
e03b757cae/gdx/src/com/badlogic/gdx/scenes/scene2d/ui/TextField.java (L689)
And it seems to have fixed the errors we were getting
This commit is contained in:
Md. Touhidur Rahman 2022-05-16 03:40:55 +06:00 committed by GitHub
parent b5a2aa59b6
commit 96780be1d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -43,6 +43,7 @@ import com.unciv.ui.worldscreen.WorldScreen
import java.util.UUID
import kotlin.math.floor
import kotlin.text.Regex
import kotlin.text.substring
import com.badlogic.gdx.utils.Array as GdxArray
/**
@ -275,6 +276,7 @@ class OptionsPopup(
if (settings.multiplayerServer != Constants.dropboxMultiplayerServer) settings.multiplayerServer
else "https://..."
val multiplayerServerTextField = TextField(textToShowForMultiplayerAddress, BaseScreen.skin)
multiplayerServerTextField.setTextFieldFilter { _, c -> c !in " \r\n\t\\" }
multiplayerServerTextField.programmaticChangeEvents = true
val serverIpTable = Table()
@ -282,10 +284,15 @@ class OptionsPopup(
multiplayerServerTextField.text = Gdx.app.clipboard.contents
}).row()
multiplayerServerTextField.onChange {
multiplayerServerTextField.text = formatMultiplayerUrlInput(multiplayerServerTextField.text)
settings.multiplayerServer = multiplayerServerTextField.text
settings.save()
connectionToServerButton.isEnabled = multiplayerServerTextField.text != Constants.dropboxMultiplayerServer
if (connectionToServerButton.isEnabled) {
fixTextFieldUrlOnType(multiplayerServerTextField)
// we can't trim on 'fixTextFieldUrlOnType' for reasons
settings.multiplayerServer = multiplayerServerTextField.text.trimEnd('/')
} else {
settings.multiplayerServer = multiplayerServerTextField.text
}
settings.save()
}
serverIpTable.add(multiplayerServerTextField).minWidth(screen.stage.width / 2).growX()
add(serverIpTable).fillX().row()
@ -962,20 +969,38 @@ class OptionsPopup(
add(checkbox).colspan(2).left().row()
}
private fun formatMultiplayerUrlInput(input: String): String {
var result : String
private fun fixTextFieldUrlOnType(TextField: TextField) {
var text: String = TextField.text
var cursor: Int = minOf(TextField.cursorPosition, text.length)
// remove all whitespaces
result = Regex("\\s+").replace(input, "")
// if text is 'http:' or 'https:' auto append '//'
if (Regex("^https?:$").containsMatchIn(text)) {
TextField.appendText("//")
return
}
val textBeforeCursor: String = text.substring(0, cursor)
// replace multiple slash with a single one
result = Regex("/{2,}").replace(result, "/")
val multipleSlashes = Regex("/{2,}")
text = multipleSlashes.replace(text, "/")
// remove trailing slash, reinstate protocol & return
// all the formatting above makes "https://" -> "http:/"
// also people might leave a slash at end my mistake
// so we need to fix those before returning
return result.trimEnd('/').replaceFirst(":/", "://")
// calculate updated cursor
cursor = multipleSlashes.replace(textBeforeCursor, "/").length
// operations above makes 'https://' -> 'https:/'
// fix that if available and update cursor
val i: Int = text.indexOf(":/")
if (i > -1) {
text = text.replaceRange(i..i+1, "://")
if (cursor > i + 1) ++cursor
}
// update TextField
if (text != TextField.text) {
TextField.text = text
TextField.cursorPosition = cursor
}
}
//endregion