From 6824f2c99256931639ba556eb5cb22d907391258 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Fri, 6 Dec 2024 10:23:06 +0600 Subject: [PATCH] preparations for events generating --- tgbotapi.webapps/.templates/generator.kts | 21 ++- .../dev/inmo/tgbotapi/webapps/EventType.kt | 2 +- .../inmo/tgbotapi/webapps/RequestStatus.kt | 9 + .../webapps/args/ArgBiometricAuthRequested.kt | 4 + .../args/ArgBiometricTokenNullableObject.kt | 5 + .../webapps/args/ArgDataNullableObject.kt | 5 + .../tgbotapi/webapps/args/ArgDataObject.kt | 5 + .../tgbotapi/webapps/args/ArgErrorObject.kt | 32 ++++ .../webapps/args/ArgIsAuthenticatedObject.kt | 5 + .../webapps/args/ArgIsUpdatedObject.kt | 5 + .../webapps/args/ArgLocationDataObject.kt | 7 + .../tgbotapi/webapps/args/ArgStatusObject.kt | 26 +++ .../tgbotapi/webapps/events/EventsList.json | 172 ++++++++++++++++++ .../webapps/events/events_generator.main.kts | 111 ++++++++++- .../webapps/popup/PopupClosedEventArg.kt | 6 + 15 files changed, 405 insertions(+), 10 deletions(-) create mode 100644 tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgBiometricAuthRequested.kt create mode 100644 tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgBiometricTokenNullableObject.kt create mode 100644 tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgDataNullableObject.kt create mode 100644 tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgDataObject.kt create mode 100644 tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgErrorObject.kt create mode 100644 tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgIsAuthenticatedObject.kt create mode 100644 tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgIsUpdatedObject.kt create mode 100644 tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgLocationDataObject.kt create mode 100644 tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgStatusObject.kt create mode 100644 tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/popup/PopupClosedEventArg.kt diff --git a/tgbotapi.webapps/.templates/generator.kts b/tgbotapi.webapps/.templates/generator.kts index 5fc31d86a1..621f1478f5 100755 --- a/tgbotapi.webapps/.templates/generator.kts +++ b/tgbotapi.webapps/.templates/generator.kts @@ -101,15 +101,23 @@ fun readEnvs(content: String, presets: Map?): Map + if (sourceArg.startsWith("\"") && sourceArg.endsWith("\"")) { + sourceArg.removePrefix("\"").removeSuffix("\"") + } else { + sourceArg + } +} + fun readParameters() { var i = 0 - while (i < args.size) { - val arg = args[i] + while (i < realArgs.size) { + val arg = realArgs[i] when (arg) { "--env", "-e" -> { i++ - envFile = File(args[i]) + envFile = File(realArgs[i]) } "--skip", "-s" -> { @@ -118,17 +126,17 @@ fun readParameters() { "--extensions", "-ex" -> { i++ - extensions = args[i].split(",") + extensions = realArgs[i].split(",") } "--outputFolder", "-o" -> { i++ - outputFolder = File(args[i]) + outputFolder = File(realArgs[i]) } "--args", "-a" -> { i++ - val subarg = args[i] + val subarg = realArgs[i] val key = subarg.takeWhile { it != '=' } val value = subarg.dropWhile { it != '=' }.removePrefix("=") commandLineArgs[key] = value @@ -164,6 +172,7 @@ fun readParameters() { Runtime.getRuntime().exit(0) } else -> { + println(arg) val potentialFile = File(arg) println("Potential file/folder as template: ${potentialFile.absolutePath}") runCatching { diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/EventType.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/EventType.kt index 3bc56e0d6b..615d956341 100644 --- a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/EventType.kt +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/EventType.kt @@ -14,4 +14,4 @@ sealed class EventType(val typeName: String) { data object WriteAccessRequested : EventType("writeAccessRequested") data object ContactRequested : EventType("contactRequested") data object ScanQRPopupClosed : EventType("scanQrPopupClosed") -} +} \ No newline at end of file diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/RequestStatus.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/RequestStatus.kt index 189b9c1411..56a3ad14a4 100644 --- a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/RequestStatus.kt +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/RequestStatus.kt @@ -11,4 +11,13 @@ inline val RequestStatus.isAllowed: Boolean get() = status == "allowed" inline val RequestStatus.isSent: Boolean + get() = status == "sent" + +inline val dev.inmo.tgbotapi.webapps.args.ArgStatusObject.isCancelled: Boolean + get() = status == "cancelled" + +inline val dev.inmo.tgbotapi.webapps.args.ArgStatusObject.isAllowed: Boolean + get() = status == "allowed" + +inline val dev.inmo.tgbotapi.webapps.args.ArgStatusObject.isSent: Boolean get() = status == "sent" \ No newline at end of file diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgBiometricAuthRequested.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgBiometricAuthRequested.kt new file mode 100644 index 0000000000..7d06214ecf --- /dev/null +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgBiometricAuthRequested.kt @@ -0,0 +1,4 @@ +package dev.inmo.tgbotapi.webapps.args + +interface ArgBiometricAuthRequested : ArgBiometricTokenNullableObject, ArgIsAuthenticatedObject { +} \ No newline at end of file diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgBiometricTokenNullableObject.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgBiometricTokenNullableObject.kt new file mode 100644 index 0000000000..b1b39df81b --- /dev/null +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgBiometricTokenNullableObject.kt @@ -0,0 +1,5 @@ +package dev.inmo.tgbotapi.webapps.args + +external interface ArgBiometricTokenNullableObject { + val biometricToken: String? +} \ No newline at end of file diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgDataNullableObject.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgDataNullableObject.kt new file mode 100644 index 0000000000..206cb74f62 --- /dev/null +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgDataNullableObject.kt @@ -0,0 +1,5 @@ +package dev.inmo.tgbotapi.webapps.args + +external interface ArgDataNullableObject { + val data: String? +} \ No newline at end of file diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgDataObject.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgDataObject.kt new file mode 100644 index 0000000000..cf45b19e8b --- /dev/null +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgDataObject.kt @@ -0,0 +1,5 @@ +package dev.inmo.tgbotapi.webapps.args + +external interface ArgDataObject : ArgDataNullableObject { + override val data: String +} \ No newline at end of file diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgErrorObject.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgErrorObject.kt new file mode 100644 index 0000000000..d1b7757198 --- /dev/null +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgErrorObject.kt @@ -0,0 +1,32 @@ +package dev.inmo.tgbotapi.webapps.args + +interface ArgErrorObject { + val error: String +} + +val ArgErrorObject.isUnsupported + get() = error.uppercase() == "UNSUPPORTED" + +val ArgErrorObject.isAlreadyFullscreen + get() = error.uppercase() == "ALREADY_FULLSCREEN" + +val ArgErrorObject.isAMessageExpired + get() = error.uppercase() == "MESSAGE_EXPIRED" + +val ArgErrorObject.isMessageSendFailed + get() = error.uppercase() == "MESSAGE_SEND_FAILED" + +val ArgErrorObject.isUserDeclined + get() = error.uppercase() == "USER_DECLINED" + +val ArgErrorObject.isSuggestedEmojiInvalid + get() = error.uppercase() == "SUGGESTED_EMOJI_INVALID" + +val ArgErrorObject.isDurationInvalid + get() = error.uppercase() == "DURATION_INVALID" + +val ArgErrorObject.isServerError + get() = error.uppercase() == "SERVER_ERROR" + +val ArgErrorObject.isUnknownError + get() = error.uppercase() == "UNKNOWN_ERROR" diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgIsAuthenticatedObject.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgIsAuthenticatedObject.kt new file mode 100644 index 0000000000..876ffb99c8 --- /dev/null +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgIsAuthenticatedObject.kt @@ -0,0 +1,5 @@ +package dev.inmo.tgbotapi.webapps.args + +interface ArgIsAuthenticatedObject { + val isAuthenticated: Boolean +} \ No newline at end of file diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgIsUpdatedObject.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgIsUpdatedObject.kt new file mode 100644 index 0000000000..8688dfc2d7 --- /dev/null +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgIsUpdatedObject.kt @@ -0,0 +1,5 @@ +package dev.inmo.tgbotapi.webapps.args + +interface ArgIsUpdatedObject { + val isUpdated: Boolean +} \ No newline at end of file diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgLocationDataObject.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgLocationDataObject.kt new file mode 100644 index 0000000000..92b8d6740e --- /dev/null +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgLocationDataObject.kt @@ -0,0 +1,7 @@ +package dev.inmo.tgbotapi.webapps.args + +import dev.inmo.tgbotapi.webapps.location.LocationData + +interface ArgLocationDataObject { + val locationData: LocationData +} \ No newline at end of file diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgStatusObject.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgStatusObject.kt new file mode 100644 index 0000000000..785a17b46d --- /dev/null +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/args/ArgStatusObject.kt @@ -0,0 +1,26 @@ +package dev.inmo.tgbotapi.webapps.args + +external interface ArgStatusObject { + val status: String +} + +val ArgStatusObject.isUnsupported + get() = status.lowercase() == "unsupported" + +val ArgStatusObject.isUnknown + get() = status.lowercase() == "unknown" + +val ArgStatusObject.isAdded + get() = status.lowercase() == "added" + +val ArgStatusObject.isMissed + get() = status.lowercase() == "missed" + +val ArgStatusObject.isAllowed + get() = status.lowercase() == "allowed" + +val ArgStatusObject.isDownloading + get() = status.lowercase() == "downloading" + +val ArgStatusObject.isCancelled + get() = status.lowercase() == "cancelled" diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/events/EventsList.json b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/events/EventsList.json index 64e758825c..e541936352 100644 --- a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/events/EventsList.json +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/events/EventsList.json @@ -2,5 +2,177 @@ { "event_name": "activated", "callback_args": "" + }, + { + "event_name": "deactivated", + "callback_args": "" + }, + { + "event_name": "themeChanged", + "callback_args": "" + }, + { + "event_name": "viewportChanged", + "callback_args": "Boolean" + }, + { + "event_name": "safeAreaChanged", + "callback_args": "" + }, + { + "event_name": "contentSafeAreaChanged", + "callback_args": "" + }, + { + "event_name": "mainButtonClicked", + "callback_args": "" + }, + { + "event_name": "secondaryButtonClicked", + "callback_args": "" + }, + { + "event_name": "backButtonClicked", + "callback_args": "" + }, + { + "event_name": "settingsButtonClicked", + "callback_args": "" + }, + { + "event_name": "invoiceClosed", + "callback_args": "String, dev.inmo.tgbotapi.webapps.invoice.InvoiceStatus" + }, + { + "event_name": "popupClosed", + "callback_args": "dev.inmo.tgbotapi.webapps.popup.PopupClosedEventArg" + }, + { + "event_name": "qrTextReceived", + "callback_args": "dev.inmo.tgbotapi.webapps.args.ArgDataObject" + }, + { + "event_name": "scanQrPopupClosed", + "callback_args": "" + }, + { + "event_name": "clipboardTextReceived", + "callback_args": "dev.inmo.tgbotapi.webapps.args.ArgDataNullableObject" + }, + { + "event_name": "writeAccessRequested", + "callback_args": "dev.inmo.tgbotapi.webapps.args.ArgStatusObject" + }, + { + "event_name": "contactRequested", + "callback_args": "dev.inmo.tgbotapi.webapps.args.ArgStatusObject" + }, + { + "event_name": "biometricManagerUpdated", + "callback_args": "" + }, + { + "event_name": "biometricAuthRequested", + "callback_args": "dev.inmo.tgbotapi.webapps.args.ArgBiometricAuthRequested" + }, + { + "event_name": "biometricTokenUpdated", + "callback_args": "dev.inmo.tgbotapi.webapps.args.ArgIsUpdatedObject" + }, + { + "event_name": "fullscreenChanged", + "callback_args": "" + }, + { + "event_name": "fullscreenFailed", + "callback_args": "dev.inmo.tgbotapi.webapps.args.ArgErrorObject" + }, + { + "event_name": "homeScreenAdded", + "callback_args": "" + }, + { + "event_name": "homeScreenChecked", + "callback_args": "dev.inmo.tgbotapi.webapps.args.ArgStatusObject" + }, + { + "event_name": "accelerometerStarted", + "callback_args": "" + }, + { + "event_name": "accelerometerStopped", + "callback_args": "" + }, + { + "event_name": "accelerometerChanged", + "callback_args": "" + }, + { + "event_name": "accelerometerFailed", + "callback_args": "dev.inmo.tgbotapi.webapps.args.ArgErrorObject" + }, + { + "event_name": "deviceOrientationStarted", + "callback_args": "" + }, + { + "event_name": "deviceOrientationStopped", + "callback_args": "" + }, + { + "event_name": "deviceOrientationChanged", + "callback_args": "" + }, + { + "event_name": "deviceOrientationFailed", + "callback_args": "dev.inmo.tgbotapi.webapps.args.ArgErrorObject" + }, + { + "event_name": "gyroscopeStarted", + "callback_args": "" + }, + { + "event_name": "gyroscopeStopped", + "callback_args": "" + }, + { + "event_name": "gyroscopeChanged", + "callback_args": "" + }, + { + "event_name": "gyroscopeFailed", + "callback_args": "dev.inmo.tgbotapi.webapps.args.ArgErrorObject" + }, + { + "event_name": "locationManagerUpdated", + "callback_args": "" + }, + { + "event_name": "locationRequested", + "callback_args": "dev.inmo.tgbotapi.webapps.args.ArgLocationDataObject" + }, + { + "event_name": "shareMessageSent", + "callback_args": "" + }, + { + "event_name": "shareMessageFailed", + "callback_args": "dev.inmo.tgbotapi.webapps.args.ArgErrorObject" + }, + { + "event_name": "emojiStatusSet", + "callback_args": "" + }, + { + "event_name": "emojiStatusFailed", + "callback_args": "dev.inmo.tgbotapi.webapps.args.ArgErrorObject" + }, + { + "event_name": "emojiStatusAccessRequested", + "callback_args": "dev.inmo.tgbotapi.webapps.args.ArgStatusObject" + }, + { + "event_name": "fileDownloadRequested", + "callback_args": "dev.inmo.tgbotapi.webapps.args.ArgStatusObject" } ] diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/events/events_generator.main.kts b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/events/events_generator.main.kts index aa03ac628a..4d52630c7a 100755 --- a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/events/events_generator.main.kts +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/events/events_generator.main.kts @@ -3,18 +3,64 @@ import kotlinx.serialization.json.* import java.io.File +import java.io.InputStream import java.lang.Runtime +import java.lang.System val rootFolder = File("../../../../../../../../") val rfAbsolutePath = rootFolder.absolutePath +val currentFolder = File("./") +val cfAbsolutePath = currentFolder.absolutePath + +val realArgs = args.map { sourceArg -> + if (sourceArg.startsWith("\"") && sourceArg.endsWith("\"")) { + sourceArg.removePrefix("\"").removeSuffix("\"") + } else { + sourceArg + } +} + +var verboseMode: Boolean = false + +fun readParameters() { + var i = 0 + while (i < realArgs.size) { + val arg = realArgs[i] + + when (arg) { + "-v", "--verbose" -> { + verboseMode = true + } + } + + i++ + } +} fun generateEvent(eventName: String, callbacks: String) { val uppercaseEventName = eventName.take(1).uppercase() + eventName.drop(1) val subpackage = eventName.map { if (it.isUpperCase()) "_${it.lowercase()}" else it }.joinToString("") - val command = "${rfAbsolutePath}/.templates/generator.kts -s -a \"subpackage=$subpackage\" -a \"event_name=$eventName\" -a \"event_name_uppercase=$uppercaseEventName\" -a \"callback_args=$callbacks\" -o \"./\" -ex \"kt\" \"${rfAbsolutePath}/.templates/{{\$subpackage}}\"" + val command = "${rfAbsolutePath}/.templates/generator.kts -s -a \"subpackage=$subpackage\" -a \"event_name=$eventName\" -a \"event_name_uppercase=$uppercaseEventName\" -a \"callback_args=$callbacks\" -a \"callback_typealias_name=${uppercaseEventName}EventHandler\" -o \"$cfAbsolutePath\" -ex \"kt\" \"${rfAbsolutePath}/.templates/{{\$subpackage}}\"" - println(command) - println(Runtime.getRuntime().exec(command).waitFor()) + val process = Runtime.getRuntime().exec(command) + val inputStream: InputStream = process.getInputStream() + val errorStream: InputStream = process.getErrorStream() + + val exitCode by lazy { process.waitFor() } + + if (verboseMode) { + inputStream.use { + it.copyTo(System.out) + } + println(exitCode) + } + + if (exitCode != 0) { + errorStream.use { + it.copyTo(System.out) + } + Runtime.getRuntime().exit(exitCode) + } } val eventsList: JsonArray = Json.parseToJsonElement(File("EventsList.json").readText()).jsonArray @@ -25,3 +71,62 @@ eventsList.forEach { it.jsonObject["callback"] ?.jsonPrimitive ?.content ?: "" ) } + +val eventTypeParts = mutableListOf() +val webAppParts = mutableListOf() +val extensionsParts = mutableListOf() + +currentFolder.listFiles() ?.forEach { generatedFolder: File -> + if (generatedFolder.isDirectory) { + generatedFolder.listFiles() ?.forEach { generatedFile: File -> + when { + generatedFile.name.startsWith("EventType") -> { + eventTypeParts + } + generatedFile.name.startsWith("WebApp") -> { + webAppParts + } + else -> { + extensionsParts + } + }.add(generatedFile.readText()) + } + } +} + +val eventTypePartsString = eventTypeParts.joinToString("\n") { " $it" } +eventTypeParts.clear() +val eventTypeFileContent = "package dev.inmo.tgbotapi.webapps\n\nsealed class EventType(val typeName: String) {\n${eventTypePartsString}\n}\n" +println(eventTypeFileContent) + +val eventTypeOutputFile = File(currentFolder, "../EventType.kt") +eventTypeOutputFile.writeText( + eventTypeFileContent +) + +val webAppPartsString = webAppParts.joinToString("\n") +webAppParts.clear() +val eventTypeFileContent = webAppPartsString +println(eventTypeFileContent) + +val webAppOutputFile = File(currentFolder, "ToPutInWebApp!!!!!.kt") +webAppOutputFile.writeText( + webAppPartsString +) + +val extensionsPartsString = extensionsParts.joinToString("\n") +extensionsParts.clear() +val extensionsPartsFileContent = "package dev.inmo.tgbotapi.webapps.events\n\n${extensionsPartsString}\n" +println(extensionsPartsFileContent) + +val extensionsPartsOutputFile = File(currentFolder, "Extensions.kt") +extensionsPartsOutputFile.writeText( + extensionsPartsFileContent +) + + +currentFolder.listFiles() ?.toList() ?.forEach { generatedFolder: File -> + if (it.isDirectory) { + it.deleteRecursively() + } +} diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/popup/PopupClosedEventArg.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/popup/PopupClosedEventArg.kt new file mode 100644 index 0000000000..8af1013cfd --- /dev/null +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/popup/PopupClosedEventArg.kt @@ -0,0 +1,6 @@ +package dev.inmo.tgbotapi.webapps.popup + +external interface PopupClosedEventArg { + @JsName("button_id") + val buttonId: String? +} \ No newline at end of file