mirror of
https://github.com/InsanusMokrassar/TelegramBotAPI-examples.git
synced 2026-04-16 15:04:13 +00:00
Compare commits
8 Commits
renovate/g
...
33.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
| bd71e642b2 | |||
| 514d9d68b8 | |||
| 9746a068b7 | |||
| 9903e0e323 | |||
| 8268cd9bf4 | |||
| b4e2d52e7e | |||
| f829ce7281 | |||
| 20b2ae8175 |
21
ManagedBotsBot/build.gradle
Normal file
21
ManagedBotsBot/build.gradle
Normal file
@@ -0,0 +1,21 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'kotlin'
|
||||
apply plugin: 'application'
|
||||
|
||||
mainClassName="CustomBotKt"
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
|
||||
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
|
||||
}
|
||||
143
ManagedBotsBot/src/main/kotlin/ManagedBotsBot.kt
Normal file
143
ManagedBotsBot/src/main/kotlin/ManagedBotsBot.kt
Normal file
@@ -0,0 +1,143 @@
|
||||
import dev.inmo.kslog.common.KSLog
|
||||
import dev.inmo.kslog.common.LogLevel
|
||||
import dev.inmo.kslog.common.defaultMessageFormatter
|
||||
import dev.inmo.kslog.common.setDefaultKSLog
|
||||
import dev.inmo.micro_utils.coroutines.subscribeLoggingDropExceptions
|
||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||
import dev.inmo.tgbotapi.extensions.api.bot.getMe
|
||||
import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
|
||||
import dev.inmo.tgbotapi.extensions.api.managed_bots.getManagedBotToken
|
||||
import dev.inmo.tgbotapi.extensions.api.managed_bots.replaceManagedBotToken
|
||||
import dev.inmo.tgbotapi.extensions.api.send.reply
|
||||
import dev.inmo.tgbotapi.extensions.api.send.send
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContextData
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildSubcontextInitialAction
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onManagedBotCreated
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onManagedBotUpdated
|
||||
import dev.inmo.tgbotapi.extensions.utils.chatEventMessageOrNull
|
||||
import dev.inmo.tgbotapi.extensions.utils.groupContentMessageOrNull
|
||||
import dev.inmo.tgbotapi.extensions.utils.managedBotCreatedOrNull
|
||||
import dev.inmo.tgbotapi.extensions.utils.types.buttons.flatReplyKeyboard
|
||||
import dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard
|
||||
import dev.inmo.tgbotapi.extensions.utils.types.buttons.requestManagedBotButton
|
||||
import dev.inmo.tgbotapi.types.Username
|
||||
import dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestManagedBot
|
||||
import dev.inmo.tgbotapi.types.buttons.PreparedKeyboardButtonId
|
||||
import dev.inmo.tgbotapi.types.message.abstracts.CommonMessage
|
||||
import dev.inmo.tgbotapi.types.request.RequestId
|
||||
import dev.inmo.tgbotapi.types.toChatId
|
||||
import dev.inmo.tgbotapi.types.update.abstracts.Update
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
||||
private var BehaviourContextData.update: Update?
|
||||
get() = get("update") as? Update
|
||||
set(value) = set("update", value)
|
||||
|
||||
private var BehaviourContextData.commonMessage: CommonMessage<*>?
|
||||
get() = get("commonMessage") as? CommonMessage<*>
|
||||
set(value) = set("commonMessage", value)
|
||||
|
||||
/**
|
||||
* This place can be the playground for your code.
|
||||
*/
|
||||
suspend fun main(vararg args: String) {
|
||||
val botToken = args.first()
|
||||
|
||||
val isDebug = args.any { it == "debug" }
|
||||
val isTestServer = args.any { it == "testServer" }
|
||||
|
||||
if (isDebug) {
|
||||
setDefaultKSLog(
|
||||
KSLog { level: LogLevel, tag: String?, message: Any, throwable: Throwable? ->
|
||||
println(defaultMessageFormatter(level, tag, message, throwable))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
telegramBotWithBehaviourAndLongPolling(
|
||||
botToken,
|
||||
CoroutineScope(Dispatchers.IO),
|
||||
testServer = isTestServer,
|
||||
builder = {
|
||||
includeMiddlewares {
|
||||
addMiddleware {
|
||||
doOnRequestReturnResult { result, request, _ ->
|
||||
println("Result of $request:\n\n$result")
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
subcontextInitialAction = buildSubcontextInitialAction {
|
||||
add {
|
||||
data.update = it
|
||||
}
|
||||
}
|
||||
) {
|
||||
// start here!!
|
||||
val me = getMe()
|
||||
println(me)
|
||||
|
||||
onCommand("start") {
|
||||
println(data.update)
|
||||
println(data.commonMessage)
|
||||
println(getChat(it.chat))
|
||||
}
|
||||
|
||||
onCommand("canManageBots") {
|
||||
val me = getMe()
|
||||
reply(it, if (me.canManageBots) "Yes" else "No")
|
||||
}
|
||||
|
||||
val requestId = RequestId(0)
|
||||
onCommand("keyboard") {
|
||||
reply(
|
||||
it,
|
||||
"Keyboard",
|
||||
replyMarkup = flatReplyKeyboard(
|
||||
resizeKeyboard = true,
|
||||
oneTimeKeyboard = true,
|
||||
) {
|
||||
requestManagedBotButton(
|
||||
"Add managed bot",
|
||||
KeyboardButtonRequestManagedBot(
|
||||
requestId = requestId,
|
||||
suggestedName = "SampleName",
|
||||
suggestedUsername = Username("@some_sample_bot")
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
onManagedBotCreated {
|
||||
reply(it, "Managed bot created successfully: ${it.chatEvent.bot}")
|
||||
val token = getManagedBotToken(
|
||||
it.chatEvent.bot.id.toChatId()
|
||||
)
|
||||
reply(it, "Token: $token")
|
||||
}
|
||||
|
||||
onManagedBotUpdated {
|
||||
send(it.user, "Managed bot has been updated: ${it.bot}")
|
||||
val token = getManagedBotToken(
|
||||
it.bot.id.toChatId()
|
||||
)
|
||||
send(it.user, "Token: $token")
|
||||
}
|
||||
|
||||
onCommand("replaceToken") {
|
||||
val reply = it.replyTo ?.chatEventMessageOrNull() ?: return@onCommand
|
||||
val managedBotCreated = reply.chatEvent.managedBotCreatedOrNull() ?: return@onCommand
|
||||
|
||||
reply(it, "Token in replace update: ${replaceManagedBotToken(managedBotCreated.bot.id.toChatId())}")
|
||||
}
|
||||
|
||||
allUpdatesFlow.subscribeLoggingDropExceptions(this) {
|
||||
println(it)
|
||||
}
|
||||
}.second.join()
|
||||
}
|
||||
@@ -6,11 +6,16 @@ import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||
import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands
|
||||
import dev.inmo.tgbotapi.extensions.api.send.polls.sendQuizPoll
|
||||
import dev.inmo.tgbotapi.extensions.api.send.polls.sendRegularPoll
|
||||
import dev.inmo.tgbotapi.extensions.api.send.reply
|
||||
import dev.inmo.tgbotapi.extensions.api.send.send
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.telegramBotWithBehaviourAndLongPolling
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onContentMessage
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPollAnswer
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPollOptionAdded
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPollOptionDeleted
|
||||
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onPollUpdates
|
||||
import dev.inmo.tgbotapi.extensions.utils.accessibleMessageOrNull
|
||||
import dev.inmo.tgbotapi.extensions.utils.customEmojiTextSourceOrNull
|
||||
import dev.inmo.tgbotapi.extensions.utils.extensions.parseCommandsWithArgsSources
|
||||
import dev.inmo.tgbotapi.types.BotCommand
|
||||
@@ -105,7 +110,9 @@ suspend fun main(vararg args: String) {
|
||||
}
|
||||
},
|
||||
isAnonymous = false,
|
||||
replyParameters = ReplyParameters(it)
|
||||
replyParameters = ReplyParameters(it),
|
||||
allowAddingOptions = true,
|
||||
hideResultsUntilCloses = true,
|
||||
)
|
||||
pollToChatMutex.withLock {
|
||||
pollToChat[sentPoll.content.poll.id] = sentPoll.chat.id
|
||||
@@ -118,7 +125,12 @@ suspend fun main(vararg args: String) {
|
||||
.firstOrNull { it.first.command == "quiz" }
|
||||
?.second
|
||||
?.firstNotNullOfOrNull { it.customEmojiTextSourceOrNull() }
|
||||
val correctAnswer = Random.nextInt(10)
|
||||
val correctAnswer = mutableListOf<Int>()
|
||||
(1 until Random.nextInt(9)).forEach {
|
||||
val option = Random.nextInt(10)
|
||||
if (correctAnswer.contains(option)) return@forEach
|
||||
correctAnswer.add(option)
|
||||
}
|
||||
val sentPoll = sendQuizPoll(
|
||||
it.chat.id,
|
||||
questionEntities = buildEntities {
|
||||
@@ -127,7 +139,13 @@ suspend fun main(vararg args: String) {
|
||||
customEmoji(customEmoji.customEmojiId, customEmoji.subsources)
|
||||
}
|
||||
},
|
||||
(1 .. 10).map {
|
||||
descriptionTextSources = buildEntities {
|
||||
regular("Test quiz poll description:")
|
||||
if (customEmoji != null) {
|
||||
customEmoji(customEmoji.customEmojiId, customEmoji.subsources)
|
||||
}
|
||||
},
|
||||
options = (1 .. 10).map {
|
||||
InputPollOption {
|
||||
regular(it.toString()) + " "
|
||||
if (customEmoji != null) {
|
||||
@@ -137,7 +155,11 @@ suspend fun main(vararg args: String) {
|
||||
},
|
||||
isAnonymous = false,
|
||||
replyParameters = ReplyParameters(it),
|
||||
correctOptionId = correctAnswer,
|
||||
correctOptionIds = correctAnswer.sorted(),
|
||||
allowMultipleAnswers = correctAnswer.size > 1,
|
||||
allowsRevoting = true,
|
||||
shuffleOptions = true,
|
||||
hideResultsUntilCloses = true,
|
||||
explanationTextSources = buildEntities {
|
||||
regular("Random solved it to be ") + underline((correctAnswer + 1).toString()) + " "
|
||||
if (customEmoji != null) {
|
||||
@@ -145,6 +167,7 @@ suspend fun main(vararg args: String) {
|
||||
}
|
||||
}
|
||||
)
|
||||
println("Sent poll data: $sentPoll")
|
||||
pollToChatMutex.withLock {
|
||||
pollToChat[sentPoll.content.poll.id] = sentPoll.chat.id
|
||||
}
|
||||
@@ -168,6 +191,32 @@ suspend fun main(vararg args: String) {
|
||||
}
|
||||
}
|
||||
|
||||
onPollOptionAdded {
|
||||
it.chatEvent.pollMessage ?.accessibleMessageOrNull() ?.let { pollMessage ->
|
||||
reply(pollMessage) {
|
||||
+"Poll option added: \n"
|
||||
+it.chatEvent.optionTextSources
|
||||
}
|
||||
}
|
||||
}
|
||||
onPollOptionDeleted {
|
||||
it.chatEvent.pollMessage ?.accessibleMessageOrNull() ?.let { pollMessage ->
|
||||
reply(pollMessage) {
|
||||
+"Poll option deleted: \n"
|
||||
+it.chatEvent.optionTextSources
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onContentMessage {
|
||||
val replyPollOptionId = it.replyInfo ?.pollOptionId ?: return@onContentMessage
|
||||
it.replyTo ?.accessibleMessageOrNull() ?.let { replied ->
|
||||
reply(replied, pollOptionId = replyPollOptionId) {
|
||||
+"Reply to poll option"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setMyCommands(
|
||||
BotCommand("anonymous", "Create anonymous regular poll"),
|
||||
BotCommand("public", "Create non anonymous regular poll"),
|
||||
|
||||
6
WebApp/src/commonMain/kotlin/PreparedSampleData.kt
Normal file
6
WebApp/src/commonMain/kotlin/PreparedSampleData.kt
Normal file
@@ -0,0 +1,6 @@
|
||||
import dev.inmo.tgbotapi.types.buttons.PreparedKeyboardButtonId
|
||||
import dev.inmo.tgbotapi.types.request.RequestId
|
||||
import kotlin.random.Random
|
||||
import kotlin.random.nextUInt
|
||||
|
||||
val preparedSampleKeyboardRequestId = RequestId(Random.nextUInt().toUShort())
|
||||
@@ -1,6 +1,7 @@
|
||||
import androidx.compose.runtime.*
|
||||
import dev.inmo.micro_utils.coroutines.launchLoggingDropExceptions
|
||||
import dev.inmo.tgbotapi.types.CustomEmojiId
|
||||
import dev.inmo.tgbotapi.types.buttons.PreparedKeyboardButtonId
|
||||
import dev.inmo.tgbotapi.types.userIdField
|
||||
import dev.inmo.tgbotapi.types.webAppQueryIdField
|
||||
import dev.inmo.tgbotapi.webapps.*
|
||||
@@ -17,6 +18,7 @@ import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.bodyAsText
|
||||
import io.ktor.http.*
|
||||
import io.ktor.http.content.TextContent
|
||||
import kotlinx.browser.document
|
||||
import kotlinx.browser.window
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.dom.appendElement
|
||||
@@ -65,7 +67,12 @@ fun main() {
|
||||
}
|
||||
val scope = rememberCoroutineScope()
|
||||
val isSafeState = remember { mutableStateOf<Boolean?>(null) }
|
||||
val logsState = remember { mutableStateListOf<Any?>() }
|
||||
val logsState = remember {
|
||||
mutableStateListOf<Any?>(
|
||||
window.location.href,
|
||||
)
|
||||
}
|
||||
val buttonIdState = remember { mutableStateOf<PreparedKeyboardButtonId?>(null) }
|
||||
|
||||
// Text(window.location.href)
|
||||
// P()
|
||||
@@ -94,6 +101,30 @@ fun main() {
|
||||
)
|
||||
}
|
||||
|
||||
LaunchedEffect(baseUrl) {
|
||||
val response = client.post("$baseUrl/getPreparedKeyboardButtonId") {
|
||||
setBody(
|
||||
Json.encodeToString(
|
||||
WebAppDataWrapper.serializer(),
|
||||
WebAppDataWrapper(webApp.initData, webApp.initDataUnsafe.hash)
|
||||
)
|
||||
)
|
||||
parameter(userIdField, webApp.initDataUnsafe.user ?.id ?.long ?: return@LaunchedEffect)
|
||||
}
|
||||
when (response.status) {
|
||||
HttpStatusCode.OK -> {
|
||||
val buttonId = response.bodyAsText()
|
||||
buttonIdState.value = PreparedKeyboardButtonId(buttonId)
|
||||
}
|
||||
HttpStatusCode.NoContent -> {
|
||||
buttonIdState.value = null
|
||||
}
|
||||
else -> {
|
||||
logsState.add("Error while getting prepared keyboard button id: ${response.status}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text(
|
||||
when (isSafeState.value) {
|
||||
null -> "Checking safe state..."
|
||||
@@ -249,6 +280,23 @@ fun main() {
|
||||
Text("Confirm")
|
||||
}
|
||||
|
||||
P()
|
||||
H3 { Text("Prepared keyboard button") }
|
||||
val buttonIdValue = buttonIdState.value
|
||||
if (buttonIdValue == null) {
|
||||
Text("Ensure that you have called /prepareKeyboard in bot. If you did it, check logs of server")
|
||||
} else {
|
||||
Button({
|
||||
onClick {
|
||||
webApp.requestChat(buttonIdValue) {
|
||||
logsState.add("Chat have been received: $it")
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Text("Prepared keyboard button")
|
||||
}
|
||||
}
|
||||
|
||||
P()
|
||||
H3 { Text("Write access callbacks") }
|
||||
Button({
|
||||
@@ -396,11 +444,15 @@ fun main() {
|
||||
}
|
||||
mainButton.apply {
|
||||
setText("Main button")
|
||||
setParams(
|
||||
BottomButtonParams(
|
||||
iconCustomEmojiId = CustomEmojiId("5370976574969486150") // 😏
|
||||
runCatching {
|
||||
setParams(
|
||||
BottomButtonParams(
|
||||
iconCustomEmojiId = CustomEmojiId("5370976574969486150") // 😏
|
||||
)
|
||||
)
|
||||
)
|
||||
}.onFailure {
|
||||
logsState.add("Can't set params for main button: $it")
|
||||
}
|
||||
onClick {
|
||||
logsState.add("Main button clicked")
|
||||
hapticFeedback.notificationOccurred(
|
||||
@@ -411,11 +463,15 @@ fun main() {
|
||||
}
|
||||
secondaryButton.apply {
|
||||
setText("Secondary button")
|
||||
setParams(
|
||||
BottomButtonParams(
|
||||
iconCustomEmojiId = CustomEmojiId("5370763368497944736") // 😒
|
||||
runCatching {
|
||||
setParams(
|
||||
BottomButtonParams(
|
||||
iconCustomEmojiId = CustomEmojiId("5370763368497944736") // 😒
|
||||
)
|
||||
)
|
||||
)
|
||||
}.onFailure {
|
||||
logsState.add("Can't set params for secondary button: $it")
|
||||
}
|
||||
onClick {
|
||||
logsState.add("Secondary button clicked")
|
||||
hapticFeedback.notificationOccurred(
|
||||
|
||||
@@ -5,6 +5,7 @@ import dev.inmo.micro_utils.ktor.server.createKtorServer
|
||||
import dev.inmo.tgbotapi.extensions.api.answers.answerInlineQuery
|
||||
import dev.inmo.tgbotapi.extensions.api.bot.getMe
|
||||
import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands
|
||||
import dev.inmo.tgbotapi.extensions.api.savePreparedKeyboardButton
|
||||
import dev.inmo.tgbotapi.extensions.api.send.reply
|
||||
import dev.inmo.tgbotapi.extensions.api.send.send
|
||||
import dev.inmo.tgbotapi.extensions.api.set.setUserEmojiStatus
|
||||
@@ -21,6 +22,10 @@ import dev.inmo.tgbotapi.requests.answers.InlineQueryResultsButton
|
||||
import dev.inmo.tgbotapi.types.*
|
||||
import dev.inmo.tgbotapi.types.InlineQueries.InlineQueryResult.InlineQueryResultArticle
|
||||
import dev.inmo.tgbotapi.types.InlineQueries.InputMessageContent.InputTextMessageContent
|
||||
import dev.inmo.tgbotapi.types.buttons.KeyboardButtonRequestManagedBot
|
||||
import dev.inmo.tgbotapi.types.buttons.PreparedKeyboardButton
|
||||
import dev.inmo.tgbotapi.types.buttons.PreparedKeyboardButtonId
|
||||
import dev.inmo.tgbotapi.types.buttons.reply.requestManagedBotReplyButton
|
||||
import dev.inmo.tgbotapi.types.webapps.WebAppInfo
|
||||
import dev.inmo.tgbotapi.utils.*
|
||||
import io.ktor.http.*
|
||||
@@ -59,6 +64,7 @@ suspend fun main(vararg args: String) {
|
||||
val initiationLogger = KSLog("Initialization")
|
||||
|
||||
val bot = telegramBot(telegramBotAPIUrlsKeeper)
|
||||
val usersToButtonsMap = mutableMapOf<UserId, PreparedKeyboardButtonId>()
|
||||
createKtorServer(
|
||||
"0.0.0.0",
|
||||
args.getOrNull(2) ?.toIntOrNull() ?: 8080
|
||||
@@ -123,6 +129,24 @@ suspend fun main(vararg args: String) {
|
||||
|
||||
call.respond(HttpStatusCode.OK, set.toString())
|
||||
}
|
||||
post("getPreparedKeyboardButtonId") {
|
||||
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")
|
||||
|
||||
if (isSafe) {
|
||||
val buttonId = usersToButtonsMap[UserId(rawUserId)]
|
||||
if (buttonId == null) {
|
||||
call.respond(HttpStatusCode.NoContent)
|
||||
} else {
|
||||
call.respond(HttpStatusCode.OK, buttonId.string)
|
||||
}
|
||||
} else {
|
||||
call.respond(HttpStatusCode.Forbidden)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start(false)
|
||||
|
||||
@@ -171,6 +195,20 @@ suspend fun main(vararg args: String) {
|
||||
)
|
||||
)
|
||||
}
|
||||
onCommand("prepareKeyboard") {
|
||||
val preparedKeyboardButton = savePreparedKeyboardButton(
|
||||
userId = it.chat.id.toChatId(),
|
||||
button = requestManagedBotReplyButton(
|
||||
text = "Saved sample button",
|
||||
requestManagedBot = KeyboardButtonRequestManagedBot(
|
||||
requestId = preparedSampleKeyboardRequestId,
|
||||
suggestedName = "Saved sample button bot",
|
||||
suggestedUsername = Username.prepare("saved_sample_button_bot")
|
||||
)
|
||||
)
|
||||
)
|
||||
usersToButtonsMap[it.chat.id.toChatId()] = preparedKeyboardButton.id
|
||||
}
|
||||
onBaseInlineQuery {
|
||||
answerInlineQuery(
|
||||
it,
|
||||
|
||||
@@ -5,9 +5,9 @@ org.gradle.jvmargs=-Xmx3148m
|
||||
kotlin.daemon.jvmargs=-Xmx3g -Xms500m
|
||||
|
||||
|
||||
kotlin_version=2.2.21
|
||||
telegram_bot_api_version=31.2.0
|
||||
micro_utils_version=0.26.9
|
||||
serialization_version=1.9.0
|
||||
ktor_version=3.3.2
|
||||
compose_version=1.8.2
|
||||
kotlin_version=2.3.20
|
||||
telegram_bot_api_version=33.0.0
|
||||
micro_utils_version=0.29.1
|
||||
serialization_version=1.10.0
|
||||
ktor_version=3.4.1
|
||||
compose_version=1.10.2
|
||||
|
||||
@@ -69,3 +69,5 @@ include ":DraftsBot"
|
||||
include ":GiftsBot"
|
||||
|
||||
include ":TagsBot"
|
||||
|
||||
include ":ManagedBotsBot"
|
||||
|
||||
Reference in New Issue
Block a user