mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI-examples.git
synced 2024-12-22 08:37:18 +00:00
commit
6a61da2eb7
@ -11,6 +11,9 @@ buildscript {
|
|||||||
plugins {
|
plugins {
|
||||||
id "org.jetbrains.kotlin.multiplatform"
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
id "org.jetbrains.kotlin.plugin.serialization"
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
|
|
||||||
|
id "org.jetbrains.kotlin.plugin.compose" version "$kotlin_version"
|
||||||
|
id "org.jetbrains.compose" version "$compose_version"
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'application'
|
apply plugin: 'application'
|
||||||
@ -27,12 +30,15 @@ kotlin {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation kotlin('stdlib')
|
implementation kotlin('stdlib')
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$serialization_version"
|
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$serialization_version"
|
||||||
|
implementation "dev.inmo:tgbotapi.core:$telegram_bot_api_version"
|
||||||
|
implementation compose.runtime
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jsMain {
|
jsMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "dev.inmo:tgbotapi.webapps:$telegram_bot_api_version"
|
implementation "dev.inmo:tgbotapi.webapps:$telegram_bot_api_version"
|
||||||
|
implementation compose.web.core
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +47,7 @@ kotlin {
|
|||||||
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
|
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
|
||||||
implementation "dev.inmo:micro_utils.ktor.server:$micro_utils_version"
|
implementation "dev.inmo:micro_utils.ktor.server:$micro_utils_version"
|
||||||
implementation "io.ktor:ktor-server-cio:$ktor_version"
|
implementation "io.ktor:ktor-server-cio:$ktor_version"
|
||||||
|
implementation compose.desktop.currentOs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
3
WebApp/src/commonMain/kotlin/CustomEmojiIdToSet.kt
Normal file
3
WebApp/src/commonMain/kotlin/CustomEmojiIdToSet.kt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import dev.inmo.tgbotapi.types.CustomEmojiId
|
||||||
|
|
||||||
|
val CustomEmojiIdToSet = CustomEmojiId("5424939566278649034")
|
@ -1,22 +1,35 @@
|
|||||||
|
import androidx.compose.runtime.*
|
||||||
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
|
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
|
||||||
|
import dev.inmo.tgbotapi.types.CustomEmojiId
|
||||||
|
import dev.inmo.tgbotapi.types.userIdField
|
||||||
import dev.inmo.tgbotapi.types.webAppQueryIdField
|
import dev.inmo.tgbotapi.types.webAppQueryIdField
|
||||||
import dev.inmo.tgbotapi.webapps.*
|
import dev.inmo.tgbotapi.webapps.*
|
||||||
|
import dev.inmo.tgbotapi.webapps.accelerometer.AccelerometerStartParams
|
||||||
import dev.inmo.tgbotapi.webapps.cloud.*
|
import dev.inmo.tgbotapi.webapps.cloud.*
|
||||||
|
import dev.inmo.tgbotapi.webapps.events.*
|
||||||
|
import dev.inmo.tgbotapi.webapps.gyroscope.GyroscopeStartParams
|
||||||
import dev.inmo.tgbotapi.webapps.haptic.HapticFeedbackStyle
|
import dev.inmo.tgbotapi.webapps.haptic.HapticFeedbackStyle
|
||||||
import dev.inmo.tgbotapi.webapps.haptic.HapticFeedbackType
|
import dev.inmo.tgbotapi.webapps.haptic.HapticFeedbackType
|
||||||
|
import dev.inmo.tgbotapi.webapps.orientation.DeviceOrientationStartParams
|
||||||
import dev.inmo.tgbotapi.webapps.popup.*
|
import dev.inmo.tgbotapi.webapps.popup.*
|
||||||
import io.ktor.client.HttpClient
|
import io.ktor.client.HttpClient
|
||||||
import io.ktor.client.request.*
|
import io.ktor.client.request.*
|
||||||
import io.ktor.client.statement.bodyAsText
|
import io.ktor.client.statement.bodyAsText
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import io.ktor.http.content.TextContent
|
import io.ktor.http.content.TextContent
|
||||||
import kotlinx.browser.document
|
|
||||||
import kotlinx.browser.window
|
import kotlinx.browser.window
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.dom.appendElement
|
import kotlinx.dom.appendElement
|
||||||
import kotlinx.dom.appendText
|
import kotlinx.dom.appendText
|
||||||
import kotlinx.dom.clear
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import org.jetbrains.compose.web.attributes.InputType
|
||||||
|
import org.jetbrains.compose.web.css.DisplayStyle
|
||||||
|
import org.jetbrains.compose.web.css.Color as ComposeColor
|
||||||
|
import org.jetbrains.compose.web.css.backgroundColor
|
||||||
|
import org.jetbrains.compose.web.css.display
|
||||||
|
import org.jetbrains.compose.web.dom.*
|
||||||
|
import org.jetbrains.compose.web.dom.Text
|
||||||
|
import org.jetbrains.compose.web.renderComposable
|
||||||
import org.w3c.dom.*
|
import org.w3c.dom.*
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
import kotlin.random.nextUBytes
|
import kotlin.random.nextUBytes
|
||||||
@ -32,277 +45,356 @@ fun main() {
|
|||||||
val client = HttpClient()
|
val client = HttpClient()
|
||||||
val baseUrl = window.location.origin.removeSuffix("/")
|
val baseUrl = window.location.origin.removeSuffix("/")
|
||||||
|
|
||||||
window.onload = {
|
renderComposable("root") {
|
||||||
val scope = CoroutineScope(Dispatchers.Default)
|
val scope = rememberCoroutineScope()
|
||||||
runCatching {
|
val isSafeState = remember { mutableStateOf<Boolean?>(null) }
|
||||||
|
val logsState = remember { mutableStateListOf<Any?>() }
|
||||||
|
|
||||||
scope.launchSafelyWithoutExceptions {
|
// Text(window.location.href)
|
||||||
val response = client.post("$baseUrl/check") {
|
// P()
|
||||||
setBody(
|
|
||||||
Json.encodeToString(
|
LaunchedEffect(baseUrl) {
|
||||||
WebAppDataWrapper.serializer(),
|
val response = client.post("$baseUrl/check") {
|
||||||
WebAppDataWrapper(webApp.initData, webApp.initDataUnsafe.hash)
|
setBody(
|
||||||
)
|
Json.encodeToString(
|
||||||
|
WebAppDataWrapper.serializer(),
|
||||||
|
WebAppDataWrapper(webApp.initData, webApp.initDataUnsafe.hash)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val dataIsSafe = response.bodyAsText().toBoolean()
|
||||||
|
|
||||||
|
if (dataIsSafe) {
|
||||||
|
isSafeState.value = true
|
||||||
|
logsState.add("Data is safe")
|
||||||
|
} else {
|
||||||
|
isSafeState.value = false
|
||||||
|
logsState.add("Data is unsafe")
|
||||||
|
}
|
||||||
|
|
||||||
|
logsState.add(
|
||||||
|
webApp.initDataUnsafe.chat.toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(
|
||||||
|
when (isSafeState.value) {
|
||||||
|
null -> "Checking safe state..."
|
||||||
|
true -> "Data is safe"
|
||||||
|
false -> "Data is unsafe"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
P()
|
||||||
|
Text("Chat from WebAppInitData: ${webApp.initDataUnsafe.chat}")
|
||||||
|
|
||||||
|
val emojiStatusAccessState = remember { mutableStateOf(false) }
|
||||||
|
webApp.onEmojiStatusAccessRequested {
|
||||||
|
emojiStatusAccessState.value = it.isAllowed
|
||||||
|
}
|
||||||
|
Button({
|
||||||
|
onClick {
|
||||||
|
webApp.requestEmojiStatusAccess()
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("Request custom emoji status access")
|
||||||
|
}
|
||||||
|
if (emojiStatusAccessState.value) {
|
||||||
|
Button({
|
||||||
|
onClick {
|
||||||
|
webApp.setEmojiStatus(CustomEmojiIdToSet/* android custom emoji id */)
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("Set custom emoji status")
|
||||||
|
}
|
||||||
|
val userId = webApp.initDataUnsafe.user ?.id
|
||||||
|
userId ?.let { userId ->
|
||||||
|
Button({
|
||||||
|
onClick {
|
||||||
|
scope.launchSafelyWithoutExceptions {
|
||||||
|
client.post("$baseUrl/setCustomEmoji") {
|
||||||
|
parameter(userIdField, userId.long)
|
||||||
|
setBody(
|
||||||
|
Json.encodeToString(
|
||||||
|
WebAppDataWrapper.serializer(),
|
||||||
|
WebAppDataWrapper(webApp.initData, webApp.initDataUnsafe.hash)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("Set custom emoji status via bot")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button({
|
||||||
|
onClick {
|
||||||
|
scope.launchSafelyWithoutExceptions {
|
||||||
|
handleResult({ "Clicked" }) {
|
||||||
|
client.post("${window.location.origin.removeSuffix("/")}/inline") {
|
||||||
|
parameter(webAppQueryIdField, it)
|
||||||
|
setBody(TextContent("Clicked", ContentType.Text.Plain))
|
||||||
|
logsState.add(url.build().toString())
|
||||||
|
}.coroutineContext.job.join()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("Answer in chat button")
|
||||||
|
}
|
||||||
|
|
||||||
|
P()
|
||||||
|
Text("Allow to write in private messages: ${webApp.initDataUnsafe.user ?.allowsWriteToPM ?: "User unavailable"}")
|
||||||
|
|
||||||
|
P()
|
||||||
|
Text("Alerts:")
|
||||||
|
Button({
|
||||||
|
onClick {
|
||||||
|
webApp.showPopup(
|
||||||
|
PopupParams(
|
||||||
|
"It is sample title of default button",
|
||||||
|
"It is sample message of default button",
|
||||||
|
DefaultPopupButton("default", "Default button"),
|
||||||
|
OkPopupButton("ok"),
|
||||||
|
DestructivePopupButton("destructive", "Destructive button")
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
logsState.add(
|
||||||
|
when (it) {
|
||||||
|
"default" -> "You have clicked default button in popup"
|
||||||
|
"ok" -> "You have clicked ok button in popup"
|
||||||
|
"destructive" -> "You have clicked destructive button in popup"
|
||||||
|
else -> "I can't imagine where you take button with id $it"
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val dataIsSafe = response.bodyAsText().toBoolean()
|
|
||||||
|
|
||||||
document.body ?.log(
|
|
||||||
if (dataIsSafe) {
|
|
||||||
"Data is safe"
|
|
||||||
} else {
|
|
||||||
"Data is unsafe"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
document.body ?.log(
|
|
||||||
webApp.initDataUnsafe.chat.toString()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
}) {
|
||||||
document.body ?.appendElement("button") {
|
Text("Popup")
|
||||||
addEventListener("click", {
|
}
|
||||||
scope.launchSafelyWithoutExceptions {
|
Button({
|
||||||
handleResult({ "Clicked" }) {
|
onClick {
|
||||||
client.post("${window.location.origin.removeSuffix("/")}/inline") {
|
webApp.showAlert(
|
||||||
parameter(webAppQueryIdField, it)
|
"This is alert message"
|
||||||
setBody(TextContent("Clicked", ContentType.Text.Plain))
|
) {
|
||||||
document.body ?.log(url.build().toString())
|
logsState.add(
|
||||||
}.coroutineContext.job.join()
|
"You have closed alert"
|
||||||
}
|
)
|
||||||
}
|
|
||||||
})
|
|
||||||
appendText("Answer in chat button")
|
|
||||||
} ?: window.alert("Unable to load body")
|
|
||||||
|
|
||||||
document.body ?.appendElement("p", {})
|
|
||||||
document.body ?.appendText("Allow to write in private messages: ${webApp.initDataUnsafe.user ?.allowsWriteToPM ?: "User unavailable"}")
|
|
||||||
|
|
||||||
document.body ?.appendElement("p", {})
|
|
||||||
document.body ?.appendText("Alerts:")
|
|
||||||
|
|
||||||
document.body ?.appendElement("button") {
|
|
||||||
addEventListener("click", {
|
|
||||||
webApp.showPopup(
|
|
||||||
PopupParams(
|
|
||||||
"It is sample title of default button",
|
|
||||||
"It is sample message of default button",
|
|
||||||
DefaultPopupButton("default", "Default button"),
|
|
||||||
OkPopupButton("ok"),
|
|
||||||
DestructivePopupButton("destructive", "Destructive button")
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
document.body ?.log(
|
|
||||||
when (it) {
|
|
||||||
"default" -> "You have clicked default button in popup"
|
|
||||||
"ok" -> "You have clicked ok button in popup"
|
|
||||||
"destructive" -> "You have clicked destructive button in popup"
|
|
||||||
else -> "I can't imagine where you take button with id $it"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
appendText("Popup")
|
|
||||||
} ?: window.alert("Unable to load body")
|
|
||||||
|
|
||||||
document.body ?.appendElement("button") {
|
|
||||||
addEventListener("click", {
|
|
||||||
webApp.showAlert(
|
|
||||||
"This is alert message"
|
|
||||||
) {
|
|
||||||
document.body ?.log(
|
|
||||||
"You have closed alert"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
appendText("Alert")
|
|
||||||
} ?: window.alert("Unable to load body")
|
|
||||||
|
|
||||||
document.body ?.appendElement("p", {})
|
|
||||||
|
|
||||||
document.body ?.appendElement("button") {
|
|
||||||
addEventListener("click", { webApp.requestWriteAccess() })
|
|
||||||
appendText("Request write access without callback")
|
|
||||||
} ?: window.alert("Unable to load body")
|
|
||||||
|
|
||||||
document.body ?.appendElement("button") {
|
|
||||||
addEventListener("click", { webApp.requestWriteAccess { document.body ?.log("Write access request result: $it") } })
|
|
||||||
appendText("Request write access with callback")
|
|
||||||
} ?: window.alert("Unable to load body")
|
|
||||||
|
|
||||||
document.body ?.appendElement("p", {})
|
|
||||||
|
|
||||||
document.body ?.appendElement("button") {
|
|
||||||
addEventListener("click", { webApp.requestContact() })
|
|
||||||
appendText("Request contact without callback")
|
|
||||||
} ?: window.alert("Unable to load body")
|
|
||||||
|
|
||||||
document.body ?.appendElement("button") {
|
|
||||||
addEventListener("click", { webApp.requestContact { document.body ?.log("Contact request result: $it") } })
|
|
||||||
appendText("Request contact with callback")
|
|
||||||
} ?: window.alert("Unable to load body")
|
|
||||||
|
|
||||||
document.body ?.appendElement("p", {})
|
|
||||||
|
|
||||||
document.body ?.appendElement("button") {
|
|
||||||
addEventListener("click", {
|
|
||||||
webApp.showConfirm(
|
|
||||||
"This is confirm message"
|
|
||||||
) {
|
|
||||||
document.body ?.log(
|
|
||||||
"You have pressed \"${if (it) "Ok" else "Cancel"}\" in confirm"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
appendText("Confirm")
|
|
||||||
} ?: window.alert("Unable to load body")
|
|
||||||
|
|
||||||
document.body ?.appendElement("p", {})
|
|
||||||
|
|
||||||
document.body ?.appendElement("button") {
|
|
||||||
fun updateText() {
|
|
||||||
textContent = if (webApp.isClosingConfirmationEnabled) {
|
|
||||||
"Disable closing confirmation"
|
|
||||||
} else {
|
|
||||||
"Enable closing confirmation"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
addEventListener("click", {
|
}
|
||||||
webApp.toggleClosingConfirmation()
|
}) {
|
||||||
updateText()
|
Text("Alert")
|
||||||
})
|
}
|
||||||
updateText()
|
|
||||||
} ?: window.alert("Unable to load body")
|
|
||||||
|
|
||||||
document.body ?.appendElement("p", {})
|
P()
|
||||||
|
Button({
|
||||||
document.body ?.appendElement("button") {
|
onClick {
|
||||||
fun updateHeaderColor() {
|
webApp.requestWriteAccess()
|
||||||
val (r, g, b) = Random.nextUBytes(3)
|
}
|
||||||
val hex = Color.Hex(r, g, b)
|
}) {
|
||||||
webApp.setHeaderColor(hex)
|
Text("Request write access without callback")
|
||||||
(this as? HTMLButtonElement) ?.style ?.backgroundColor = hex.value
|
}
|
||||||
textContent = "Header color: ${webApp.headerColor ?.uppercase()} (click to change)"
|
Button({
|
||||||
|
onClick {
|
||||||
|
webApp.requestWriteAccess {
|
||||||
|
logsState.add("Write access request result: $it")
|
||||||
}
|
}
|
||||||
addEventListener("click", {
|
}
|
||||||
updateHeaderColor()
|
}) {
|
||||||
})
|
Text("Request write access with callback")
|
||||||
|
}
|
||||||
|
|
||||||
|
P()
|
||||||
|
Button({
|
||||||
|
onClick {
|
||||||
|
webApp.requestContact()
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("Request contact without callback")
|
||||||
|
}
|
||||||
|
Button({
|
||||||
|
onClick {
|
||||||
|
webApp.requestContact { logsState.add("Contact request result: $it") }
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("Request contact with callback")
|
||||||
|
}
|
||||||
|
P()
|
||||||
|
|
||||||
|
Button({
|
||||||
|
onClick {
|
||||||
|
webApp.showConfirm(
|
||||||
|
"This is confirm message"
|
||||||
|
) {
|
||||||
|
logsState.add(
|
||||||
|
"You have pressed \"${if (it) "Ok" else "Cancel"}\" in confirm"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("Confirm")
|
||||||
|
}
|
||||||
|
|
||||||
|
P()
|
||||||
|
|
||||||
|
val isClosingConfirmationEnabledState = remember { mutableStateOf(webApp.isClosingConfirmationEnabled) }
|
||||||
|
Button({
|
||||||
|
onClick {
|
||||||
|
webApp.toggleClosingConfirmation()
|
||||||
|
isClosingConfirmationEnabledState.value = webApp.isClosingConfirmationEnabled
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text(
|
||||||
|
if (isClosingConfirmationEnabledState.value) {
|
||||||
|
"Disable closing confirmation"
|
||||||
|
} else {
|
||||||
|
"Enable closing confirmation"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
P()
|
||||||
|
|
||||||
|
val headerColor = remember { mutableStateOf<Color.Hex>(Color.Hex("#000000")) }
|
||||||
|
fun updateHeaderColor() {
|
||||||
|
val (r, g, b) = Random.nextUBytes(3)
|
||||||
|
headerColor.value = Color.Hex(r, g, b)
|
||||||
|
webApp.setHeaderColor(headerColor.value)
|
||||||
|
}
|
||||||
|
DisposableEffect(0) {
|
||||||
|
updateHeaderColor()
|
||||||
|
onDispose { }
|
||||||
|
}
|
||||||
|
Button({
|
||||||
|
style {
|
||||||
|
backgroundColor(ComposeColor(headerColor.value.value))
|
||||||
|
}
|
||||||
|
onClick {
|
||||||
updateHeaderColor()
|
updateHeaderColor()
|
||||||
} ?: window.alert("Unable to load body")
|
}
|
||||||
|
}) {
|
||||||
|
key(headerColor.value) {
|
||||||
|
Text("Header color: ${webApp.headerColor ?.uppercase()} (click to change)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
document.body ?.appendElement("p", {})
|
P()
|
||||||
|
|
||||||
document.body ?.appendElement("button") {
|
val backgroundColor = remember { mutableStateOf<Color.Hex>(Color.Hex("#000000")) }
|
||||||
fun updateBackgroundColor() {
|
fun updateBackgroundColor() {
|
||||||
val (r, g, b) = Random.nextUBytes(3)
|
val (r, g, b) = Random.nextUBytes(3)
|
||||||
val hex = Color.Hex(r, g, b)
|
backgroundColor.value = Color.Hex(r, g, b)
|
||||||
webApp.setBackgroundColor(hex)
|
webApp.setBackgroundColor(backgroundColor.value)
|
||||||
(this as? HTMLButtonElement) ?.style ?.backgroundColor = hex.value
|
}
|
||||||
textContent = "Background color: ${webApp.backgroundColor ?.uppercase()} (click to change)"
|
DisposableEffect(0) {
|
||||||
}
|
updateBackgroundColor()
|
||||||
addEventListener("click", {
|
onDispose { }
|
||||||
updateBackgroundColor()
|
}
|
||||||
})
|
Button({
|
||||||
|
style {
|
||||||
|
backgroundColor(ComposeColor(backgroundColor.value.value))
|
||||||
|
}
|
||||||
|
onClick {
|
||||||
updateBackgroundColor()
|
updateBackgroundColor()
|
||||||
} ?: window.alert("Unable to load body")
|
}
|
||||||
|
}) {
|
||||||
|
key(backgroundColor.value) {
|
||||||
|
Text("Background color: ${webApp.backgroundColor ?.uppercase()} (click to change)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
document.body ?.appendElement("p", {})
|
P()
|
||||||
|
|
||||||
document.body ?.appendElement("button") {
|
val bottomBarColor = remember { mutableStateOf<Color.Hex>(Color.Hex("#000000")) }
|
||||||
fun updateBottomBarColor() {
|
fun updateBottomBarColor() {
|
||||||
val (r, g, b) = Random.nextUBytes(3)
|
val (r, g, b) = Random.nextUBytes(3)
|
||||||
val hex = Color.Hex(r, g, b)
|
bottomBarColor.value = Color.Hex(r, g, b)
|
||||||
webApp.setBottomBarColor(hex)
|
webApp.setBottomBarColor(bottomBarColor.value)
|
||||||
(this as? HTMLButtonElement) ?.style ?.backgroundColor = hex.value
|
}
|
||||||
textContent = "Bottom bar color: ${webApp.bottomBarColor ?.uppercase()} (click to change)"
|
DisposableEffect(0) {
|
||||||
}
|
updateBottomBarColor()
|
||||||
addEventListener("click", {
|
onDispose { }
|
||||||
updateBottomBarColor()
|
}
|
||||||
})
|
Button({
|
||||||
|
style {
|
||||||
|
backgroundColor(ComposeColor(bottomBarColor.value.value))
|
||||||
|
}
|
||||||
|
onClick {
|
||||||
updateBottomBarColor()
|
updateBottomBarColor()
|
||||||
} ?: window.alert("Unable to load body")
|
}
|
||||||
|
}) {
|
||||||
|
key(bottomBarColor.value) {
|
||||||
|
Text("Bottom bar color: ${webApp.bottomBarColor ?.uppercase()} (click to change)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
document.body ?.appendElement("p", {})
|
P()
|
||||||
|
|
||||||
fun Element.updateCloudStorageContent() {
|
val storageTrigger = remember { mutableStateOf<List<Pair<CloudStorageKey, CloudStorageValue>>>(emptyList()) }
|
||||||
clear()
|
fun updateCloudStorage() {
|
||||||
webApp.cloudStorage.getAll {
|
webApp.cloudStorage.getAll {
|
||||||
it.onSuccess {
|
it.onSuccess {
|
||||||
document.body ?.log(it.toString())
|
storageTrigger.value = it.toList().sortedBy { it.first.key }
|
||||||
appendElement("label") { textContent = "Cloud storage" }
|
|
||||||
|
|
||||||
appendElement("p", {})
|
|
||||||
|
|
||||||
it.forEach { (k, v) ->
|
|
||||||
appendElement("div") {
|
|
||||||
val kInput = appendElement("input", {}) as HTMLInputElement
|
|
||||||
val vInput = appendElement("input", {}) as HTMLInputElement
|
|
||||||
|
|
||||||
kInput.value = k.key
|
|
||||||
vInput.value = v.value
|
|
||||||
|
|
||||||
appendElement("button") {
|
|
||||||
addEventListener("click", {
|
|
||||||
if (k.key == kInput.value) {
|
|
||||||
webApp.cloudStorage.set(k.key, vInput.value) {
|
|
||||||
document.body ?.log(it.toString())
|
|
||||||
this@updateCloudStorageContent.updateCloudStorageContent()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
webApp.cloudStorage.remove(k.key) {
|
|
||||||
it.onSuccess {
|
|
||||||
webApp.cloudStorage.set(kInput.value, vInput.value) {
|
|
||||||
document.body ?.log(it.toString())
|
|
||||||
this@updateCloudStorageContent.updateCloudStorageContent()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.textContent = "Save"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
appendElement("p", {})
|
|
||||||
}
|
|
||||||
appendElement("label") { textContent = "Cloud storage: add new" }
|
|
||||||
|
|
||||||
appendElement("p", {})
|
|
||||||
|
|
||||||
appendElement("div") {
|
|
||||||
val kInput = appendElement("input", {}) as HTMLInputElement
|
|
||||||
|
|
||||||
appendElement("button") {
|
|
||||||
textContent = "Add key"
|
|
||||||
addEventListener("click", {
|
|
||||||
webApp.cloudStorage.set(kInput.value, kInput.value) {
|
|
||||||
document.body ?.log(it.toString())
|
|
||||||
this@updateCloudStorageContent.updateCloudStorageContent()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
appendElement("p", {})
|
|
||||||
}.onFailure {
|
|
||||||
document.body ?.log(it.stackTraceToString())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val cloudStorageContentDiv = document.body ?.appendElement("div") {} as HTMLDivElement
|
}
|
||||||
|
key(storageTrigger.value) {
|
||||||
document.body ?.appendElement("p", {})
|
storageTrigger.value.forEach { (key, value) ->
|
||||||
|
val keyState = remember { mutableStateOf(key.key) }
|
||||||
|
val valueState = remember { mutableStateOf(value.value) }
|
||||||
|
Input(InputType.Text) {
|
||||||
|
value(key.key)
|
||||||
|
onInput { keyState.value = it.value }
|
||||||
|
}
|
||||||
|
Input(InputType.Text) {
|
||||||
|
value(value.value)
|
||||||
|
onInput { valueState.value = it.value }
|
||||||
|
}
|
||||||
|
Button({
|
||||||
|
onClick {
|
||||||
|
if (key.key != keyState.value) {
|
||||||
|
webApp.cloudStorage.remove(key)
|
||||||
|
}
|
||||||
|
webApp.cloudStorage.set(keyState.value, valueState.value)
|
||||||
|
updateCloudStorage()
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("Save")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let { // new element adding
|
||||||
|
val keyState = remember { mutableStateOf("") }
|
||||||
|
val valueState = remember { mutableStateOf("") }
|
||||||
|
Input(InputType.Text) {
|
||||||
|
onInput { keyState.value = it.value }
|
||||||
|
}
|
||||||
|
Input(InputType.Text) {
|
||||||
|
onInput { valueState.value = it.value }
|
||||||
|
}
|
||||||
|
Button({
|
||||||
|
onClick {
|
||||||
|
webApp.cloudStorage.set(keyState.value, valueState.value)
|
||||||
|
updateCloudStorage()
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("Save")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
remember {
|
||||||
webApp.apply {
|
webApp.apply {
|
||||||
|
|
||||||
onThemeChanged {
|
onThemeChanged {
|
||||||
document.body ?.log("Theme changed: ${webApp.themeParams}")
|
logsState.add("Theme changed: ${webApp.themeParams}")
|
||||||
}
|
}
|
||||||
onViewportChanged {
|
onViewportChanged {
|
||||||
document.body ?.log("Viewport changed: ${it.isStateStable}")
|
logsState.add("Viewport changed: ${it}")
|
||||||
}
|
}
|
||||||
backButton.apply {
|
backButton.apply {
|
||||||
onClick {
|
onClick {
|
||||||
document.body ?.log("Back button clicked")
|
logsState.add("Back button clicked")
|
||||||
hapticFeedback.impactOccurred(
|
hapticFeedback.impactOccurred(
|
||||||
HapticFeedbackStyle.Heavy
|
HapticFeedbackStyle.Heavy
|
||||||
)
|
)
|
||||||
@ -312,7 +404,7 @@ fun main() {
|
|||||||
mainButton.apply {
|
mainButton.apply {
|
||||||
setText("Main button")
|
setText("Main button")
|
||||||
onClick {
|
onClick {
|
||||||
document.body ?.log("Main button clicked")
|
logsState.add("Main button clicked")
|
||||||
hapticFeedback.notificationOccurred(
|
hapticFeedback.notificationOccurred(
|
||||||
HapticFeedbackType.Success
|
HapticFeedbackType.Success
|
||||||
)
|
)
|
||||||
@ -322,7 +414,7 @@ fun main() {
|
|||||||
secondaryButton.apply {
|
secondaryButton.apply {
|
||||||
setText("Secondary button")
|
setText("Secondary button")
|
||||||
onClick {
|
onClick {
|
||||||
document.body ?.log("Secondary button clicked")
|
logsState.add("Secondary button clicked")
|
||||||
hapticFeedback.notificationOccurred(
|
hapticFeedback.notificationOccurred(
|
||||||
HapticFeedbackType.Warning
|
HapticFeedbackType.Warning
|
||||||
)
|
)
|
||||||
@ -330,22 +422,231 @@ fun main() {
|
|||||||
show()
|
show()
|
||||||
}
|
}
|
||||||
onSettingsButtonClicked {
|
onSettingsButtonClicked {
|
||||||
document.body ?.log("Settings button clicked")
|
logsState.add("Settings button clicked")
|
||||||
}
|
}
|
||||||
onWriteAccessRequested {
|
onWriteAccessRequested {
|
||||||
document.body ?.log("Write access request result: $it")
|
logsState.add("Write access request result: $it")
|
||||||
}
|
}
|
||||||
onContactRequested {
|
onContactRequested {
|
||||||
document.body ?.log("Contact request result: $it")
|
logsState.add("Contact request result: $it")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
webApp.ready()
|
}
|
||||||
document.body ?.appendElement("input", {
|
P()
|
||||||
(this as HTMLInputElement).value = window.location.href
|
|
||||||
})
|
let { // Accelerometer
|
||||||
cloudStorageContentDiv.updateCloudStorageContent()
|
val enabledState = remember { mutableStateOf(webApp.accelerometer.isStarted) }
|
||||||
}.onFailure {
|
webApp.onAccelerometerStarted { enabledState.value = true }
|
||||||
window.alert(it.stackTraceToString())
|
webApp.onAccelerometerStopped { enabledState.value = false }
|
||||||
|
Button({
|
||||||
|
onClick {
|
||||||
|
if (enabledState.value) {
|
||||||
|
webApp.accelerometer.stop { }
|
||||||
|
} else {
|
||||||
|
webApp.accelerometer.start(AccelerometerStartParams(200))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("${if (enabledState.value) "Stop" else "Start"} accelerometer")
|
||||||
|
}
|
||||||
|
val xState = remember { mutableStateOf(webApp.accelerometer.x) }
|
||||||
|
val yState = remember { mutableStateOf(webApp.accelerometer.y) }
|
||||||
|
val zState = remember { mutableStateOf(webApp.accelerometer.z) }
|
||||||
|
fun updateValues() {
|
||||||
|
xState.value = webApp.accelerometer.x
|
||||||
|
yState.value = webApp.accelerometer.y
|
||||||
|
zState.value = webApp.accelerometer.z
|
||||||
|
}
|
||||||
|
remember {
|
||||||
|
updateValues()
|
||||||
|
}
|
||||||
|
|
||||||
|
webApp.onAccelerometerChanged {
|
||||||
|
updateValues()
|
||||||
|
}
|
||||||
|
if (enabledState.value) {
|
||||||
|
P()
|
||||||
|
Text("x: ${xState.value}")
|
||||||
|
P()
|
||||||
|
Text("y: ${yState.value}")
|
||||||
|
P()
|
||||||
|
Text("z: ${zState.value}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
P()
|
||||||
|
|
||||||
|
let { // Gyroscope
|
||||||
|
val enabledState = remember { mutableStateOf(webApp.gyroscope.isStarted) }
|
||||||
|
webApp.onGyroscopeStarted { enabledState.value = true }
|
||||||
|
webApp.onGyroscopeStopped { enabledState.value = false }
|
||||||
|
Button({
|
||||||
|
onClick {
|
||||||
|
if (enabledState.value) {
|
||||||
|
webApp.gyroscope.stop { }
|
||||||
|
} else {
|
||||||
|
webApp.gyroscope.start(GyroscopeStartParams(200))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("${if (enabledState.value) "Stop" else "Start"} gyroscope")
|
||||||
|
}
|
||||||
|
val xState = remember { mutableStateOf(webApp.gyroscope.x) }
|
||||||
|
val yState = remember { mutableStateOf(webApp.gyroscope.y) }
|
||||||
|
val zState = remember { mutableStateOf(webApp.gyroscope.z) }
|
||||||
|
fun updateValues() {
|
||||||
|
xState.value = webApp.gyroscope.x
|
||||||
|
yState.value = webApp.gyroscope.y
|
||||||
|
zState.value = webApp.gyroscope.z
|
||||||
|
}
|
||||||
|
remember {
|
||||||
|
updateValues()
|
||||||
|
}
|
||||||
|
|
||||||
|
webApp.onGyroscopeChanged {
|
||||||
|
updateValues()
|
||||||
|
}
|
||||||
|
if (enabledState.value) {
|
||||||
|
P()
|
||||||
|
Text("x: ${xState.value}")
|
||||||
|
P()
|
||||||
|
Text("y: ${yState.value}")
|
||||||
|
P()
|
||||||
|
Text("z: ${zState.value}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
P()
|
||||||
|
|
||||||
|
let { // DeviceOrientation
|
||||||
|
val enabledState = remember { mutableStateOf(webApp.deviceOrientation.isStarted) }
|
||||||
|
webApp.onDeviceOrientationStarted { enabledState.value = true }
|
||||||
|
webApp.onDeviceOrientationStopped { enabledState.value = false }
|
||||||
|
Button({
|
||||||
|
onClick {
|
||||||
|
if (enabledState.value) {
|
||||||
|
webApp.deviceOrientation.stop { }
|
||||||
|
} else {
|
||||||
|
webApp.deviceOrientation.start(DeviceOrientationStartParams(200))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Text("${if (enabledState.value) "Stop" else "Start"} deviceOrientation")
|
||||||
|
}
|
||||||
|
val alphaState = remember { mutableStateOf(webApp.deviceOrientation.alpha) }
|
||||||
|
val betaState = remember { mutableStateOf(webApp.deviceOrientation.beta) }
|
||||||
|
val gammaState = remember { mutableStateOf(webApp.deviceOrientation.gamma) }
|
||||||
|
fun updateValues() {
|
||||||
|
alphaState.value = webApp.deviceOrientation.alpha
|
||||||
|
betaState.value = webApp.deviceOrientation.beta
|
||||||
|
gammaState.value = webApp.deviceOrientation.gamma
|
||||||
|
}
|
||||||
|
remember {
|
||||||
|
updateValues()
|
||||||
|
}
|
||||||
|
|
||||||
|
webApp.onDeviceOrientationChanged {
|
||||||
|
updateValues()
|
||||||
|
}
|
||||||
|
if (enabledState.value) {
|
||||||
|
P()
|
||||||
|
Text("alpha: ${alphaState.value}")
|
||||||
|
P()
|
||||||
|
Text("beta: ${betaState.value}")
|
||||||
|
P()
|
||||||
|
Text("gamma: ${gammaState.value}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
P()
|
||||||
|
|
||||||
|
EventType.values().forEach { eventType ->
|
||||||
|
when (eventType) {
|
||||||
|
EventType.AccelerometerChanged -> webApp.onAccelerometerChanged { /*logsState.add("AccelerometerChanged") /* see accelerometer block */ */ }
|
||||||
|
EventType.AccelerometerFailed -> webApp.onAccelerometerFailed {
|
||||||
|
logsState.add(it.error)
|
||||||
|
}
|
||||||
|
EventType.AccelerometerStarted -> webApp.onAccelerometerStarted { logsState.add("AccelerometerStarted") }
|
||||||
|
EventType.AccelerometerStopped -> webApp.onAccelerometerStopped { logsState.add("AccelerometerStopped") }
|
||||||
|
EventType.Activated -> webApp.onActivated { logsState.add("Activated") }
|
||||||
|
EventType.BackButtonClicked -> webApp.onBackButtonClicked { logsState.add("BackButtonClicked") }
|
||||||
|
EventType.BiometricAuthRequested -> webApp.onBiometricAuthRequested {
|
||||||
|
logsState.add(it.isAuthenticated)
|
||||||
|
}
|
||||||
|
EventType.BiometricManagerUpdated -> webApp.onBiometricManagerUpdated { logsState.add("BiometricManagerUpdated") }
|
||||||
|
EventType.BiometricTokenUpdated -> webApp.onBiometricTokenUpdated {
|
||||||
|
logsState.add(it.isUpdated)
|
||||||
|
}
|
||||||
|
EventType.ClipboardTextReceived -> webApp.onClipboardTextReceived {
|
||||||
|
logsState.add(it.data)
|
||||||
|
}
|
||||||
|
EventType.ContactRequested -> webApp.onContactRequested {
|
||||||
|
logsState.add(it.status)
|
||||||
|
}
|
||||||
|
EventType.ContentSafeAreaChanged -> webApp.onContentSafeAreaChanged { logsState.add("ContentSafeAreaChanged") }
|
||||||
|
EventType.Deactivated -> webApp.onDeactivated { logsState.add("Deactivated") }
|
||||||
|
EventType.DeviceOrientationChanged -> webApp.onDeviceOrientationChanged { /*logsState.add("DeviceOrientationChanged")*//* see accelerometer block */ }
|
||||||
|
EventType.DeviceOrientationFailed -> webApp.onDeviceOrientationFailed {
|
||||||
|
logsState.add(it.error)
|
||||||
|
}
|
||||||
|
EventType.DeviceOrientationStarted -> webApp.onDeviceOrientationStarted { logsState.add("DeviceOrientationStarted") }
|
||||||
|
EventType.DeviceOrientationStopped -> webApp.onDeviceOrientationStopped { logsState.add("DeviceOrientationStopped") }
|
||||||
|
EventType.EmojiStatusAccessRequested -> webApp.onEmojiStatusAccessRequested {
|
||||||
|
logsState.add(it.status)
|
||||||
|
}
|
||||||
|
EventType.EmojiStatusFailed -> webApp.onEmojiStatusFailed {
|
||||||
|
logsState.add(it.error)
|
||||||
|
}
|
||||||
|
EventType.EmojiStatusSet -> webApp.onEmojiStatusSet { logsState.add("EmojiStatusSet") }
|
||||||
|
EventType.FileDownloadRequested -> webApp.onFileDownloadRequested {
|
||||||
|
logsState.add(it.status)
|
||||||
|
}
|
||||||
|
EventType.FullscreenChanged -> webApp.onFullscreenChanged { logsState.add("FullscreenChanged") }
|
||||||
|
EventType.FullscreenFailed -> webApp.onFullscreenFailed {
|
||||||
|
logsState.add(it.error)
|
||||||
|
}
|
||||||
|
EventType.GyroscopeChanged -> webApp.onGyroscopeChanged { /*logsState.add("GyroscopeChanged")*//* see gyroscope block */ }
|
||||||
|
EventType.GyroscopeFailed -> webApp.onGyroscopeFailed {
|
||||||
|
logsState.add(it.error)
|
||||||
|
}
|
||||||
|
EventType.GyroscopeStarted -> webApp.onGyroscopeStarted { logsState.add("GyroscopeStarted")/* see accelerometer block */ }
|
||||||
|
EventType.GyroscopeStopped -> webApp.onGyroscopeStopped { logsState.add("GyroscopeStopped") }
|
||||||
|
EventType.HomeScreenAdded -> webApp.onHomeScreenAdded { logsState.add("HomeScreenAdded") }
|
||||||
|
EventType.HomeScreenChecked -> webApp.onHomeScreenChecked {
|
||||||
|
logsState.add(it.status)
|
||||||
|
}
|
||||||
|
EventType.InvoiceClosed -> webApp.onInvoiceClosed { url, status ->
|
||||||
|
logsState.add(url)
|
||||||
|
logsState.add(status)
|
||||||
|
}
|
||||||
|
EventType.LocationManagerUpdated -> webApp.onLocationManagerUpdated { logsState.add("LocationManagerUpdated") }
|
||||||
|
EventType.LocationRequested -> webApp.onLocationRequested {
|
||||||
|
logsState.add(it.locationData)
|
||||||
|
}
|
||||||
|
EventType.MainButtonClicked -> webApp.onMainButtonClicked { logsState.add("MainButtonClicked") }
|
||||||
|
EventType.PopupClosed -> webApp.onPopupClosed {
|
||||||
|
logsState.add(it.buttonId)
|
||||||
|
}
|
||||||
|
EventType.QrTextReceived -> webApp.onQrTextReceived {
|
||||||
|
logsState.add(it.data)
|
||||||
|
}
|
||||||
|
EventType.SafeAreaChanged -> webApp.onSafeAreaChanged { logsState.add("SafeAreaChanged") }
|
||||||
|
EventType.ScanQrPopupClosed -> webApp.onScanQrPopupClosed { logsState.add("ScanQrPopupClosed") }
|
||||||
|
EventType.SecondaryButtonClicked -> webApp.onSecondaryButtonClicked { logsState.add("SecondaryButtonClicked") }
|
||||||
|
EventType.SettingsButtonClicked -> webApp.onSettingsButtonClicked { logsState.add("SettingsButtonClicked") }
|
||||||
|
EventType.ShareMessageFailed -> webApp.onShareMessageFailed {
|
||||||
|
logsState.add(it.error)
|
||||||
|
}
|
||||||
|
EventType.ShareMessageSent -> webApp.onShareMessageSent { logsState.add("ShareMessageSent") }
|
||||||
|
EventType.ThemeChanged -> webApp.onThemeChanged { logsState.add("ThemeChanged") }
|
||||||
|
EventType.ViewportChanged -> webApp.onViewportChanged {
|
||||||
|
logsState.add(it)
|
||||||
|
}
|
||||||
|
EventType.WriteAccessRequested -> webApp.onWriteAccessRequested {
|
||||||
|
logsState.add(it.status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logsState.forEach {
|
||||||
|
P { Text(it.toString()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
<title>Web App Example</title>
|
<title>Web App Example</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
<script type="application/javascript" src="https://telegram.org/js/telegram-web-app.js"></script>
|
<script type="application/javascript" src="https://telegram.org/js/telegram-web-app.js"></script>
|
||||||
<script type="application/javascript" src="WebApp.js"></script>
|
<script type="application/javascript" src="WebApp.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
@ -6,6 +6,7 @@ import dev.inmo.tgbotapi.extensions.api.bot.getMe
|
|||||||
import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands
|
import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands
|
||||||
import dev.inmo.tgbotapi.extensions.api.send.reply
|
import dev.inmo.tgbotapi.extensions.api.send.reply
|
||||||
import dev.inmo.tgbotapi.extensions.api.send.send
|
import dev.inmo.tgbotapi.extensions.api.send.send
|
||||||
|
import dev.inmo.tgbotapi.extensions.api.set.setUserEmojiStatus
|
||||||
import dev.inmo.tgbotapi.extensions.api.telegramBot
|
import dev.inmo.tgbotapi.extensions.api.telegramBot
|
||||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling
|
||||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onBaseInlineQuery
|
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onBaseInlineQuery
|
||||||
@ -16,12 +17,9 @@ import dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard
|
|||||||
import dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard
|
import dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard
|
||||||
import dev.inmo.tgbotapi.extensions.utils.types.buttons.webAppButton
|
import dev.inmo.tgbotapi.extensions.utils.types.buttons.webAppButton
|
||||||
import dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton
|
import dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton
|
||||||
import dev.inmo.tgbotapi.types.BotCommand
|
import dev.inmo.tgbotapi.types.*
|
||||||
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.InlineQueryResultArticle
|
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.InlineQueryResultArticle
|
||||||
import dev.inmo.tgbotapi.types.InlineQueries.InputMessageContent.InputTextMessageContent
|
import dev.inmo.tgbotapi.types.InlineQueries.InputMessageContent.InputTextMessageContent
|
||||||
import dev.inmo.tgbotapi.types.InlineQueryId
|
|
||||||
import dev.inmo.tgbotapi.types.LinkPreviewOptions
|
|
||||||
import dev.inmo.tgbotapi.types.webAppQueryIdField
|
|
||||||
import dev.inmo.tgbotapi.types.webapps.WebAppInfo
|
import dev.inmo.tgbotapi.types.webapps.WebAppInfo
|
||||||
import dev.inmo.tgbotapi.utils.*
|
import dev.inmo.tgbotapi.utils.*
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
@ -30,7 +28,6 @@ import io.ktor.server.http.content.*
|
|||||||
import io.ktor.server.request.*
|
import io.ktor.server.request.*
|
||||||
import io.ktor.server.response.*
|
import io.ktor.server.response.*
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@ -105,6 +102,26 @@ suspend fun main(vararg args: String) {
|
|||||||
|
|
||||||
call.respond(HttpStatusCode.OK, isSafe.toString())
|
call.respond(HttpStatusCode.OK, isSafe.toString())
|
||||||
}
|
}
|
||||||
|
post("setCustomEmoji") {
|
||||||
|
val requestBody = call.receiveText()
|
||||||
|
val webAppCheckData = Json.decodeFromString(WebAppDataWrapper.serializer(), requestBody)
|
||||||
|
|
||||||
|
val isSafe = telegramBotAPIUrlsKeeper.checkWebAppData(webAppCheckData.data, webAppCheckData.hash)
|
||||||
|
val rawUserId = call.parameters[userIdField] ?.toLongOrNull() ?.let(::RawChatId) ?: error("$userIdField should be presented as long value")
|
||||||
|
|
||||||
|
val set = if (isSafe) {
|
||||||
|
runCatching {
|
||||||
|
bot.setUserEmojiStatus(
|
||||||
|
UserId(rawUserId),
|
||||||
|
CustomEmojiIdToSet
|
||||||
|
)
|
||||||
|
}.getOrElse { false }
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
call.respond(HttpStatusCode.OK, set.toString())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}.start(false)
|
}.start(false)
|
||||||
|
|
||||||
|
@ -29,3 +29,8 @@ allprojects {
|
|||||||
maven { url "https://nexus.inmo.dev/repository/maven-releases/" }
|
maven { url "https://nexus.inmo.dev/repository/maven-releases/" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fix of https://youtrack.jetbrains.com/issue/KTOR-7912/Module-not-found-errors-when-executing-browserProductionWebpack-task-since-3.0.2
|
||||||
|
rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin.class) {
|
||||||
|
rootProject.kotlinYarn.resolution("ws", "8.18.0")
|
||||||
|
}
|
||||||
|
@ -6,7 +6,8 @@ kotlin.daemon.jvmargs=-Xmx3g -Xms500m
|
|||||||
|
|
||||||
|
|
||||||
kotlin_version=2.1.0
|
kotlin_version=2.1.0
|
||||||
telegram_bot_api_version=21.0.0
|
telegram_bot_api_version=22.0.0
|
||||||
micro_utils_version=0.23.1
|
micro_utils_version=0.23.2
|
||||||
serialization_version=1.7.3
|
serialization_version=1.7.3
|
||||||
ktor_version=3.0.1
|
ktor_version=3.0.2
|
||||||
|
compose_version=1.7.1
|
||||||
|
Loading…
Reference in New Issue
Block a user