Merge pull request #235 from InsanusMokrassar/9.2.0

Migration onto 9.2.0
This commit is contained in:
InsanusMokrassar 2023-09-28 19:37:41 +06:00 committed by GitHub
commit d3d6cd16c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 431 additions and 51 deletions

View File

@ -18,4 +18,5 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "dev.inmo:tgbotapi:$telegram_bot_api_version"
implementation 'io.ktor:ktor-client-logging-jvm:2.3.3'
}

View File

@ -1,34 +1,50 @@
import dev.inmo.micro_utils.coroutines.runCatchingSafely
import dev.inmo.micro_utils.coroutines.firstOf
import dev.inmo.micro_utils.fsm.common.State
import dev.inmo.tgbotapi.bot.ktor.telegramBot
import dev.inmo.tgbotapi.extensions.api.bot.setMyCommands
import dev.inmo.tgbotapi.extensions.api.chat.get.getChat
import dev.inmo.tgbotapi.extensions.api.chat.members.getChatMember
import dev.inmo.tgbotapi.extensions.api.chat.members.promoteChannelAdministrator
import dev.inmo.tgbotapi.extensions.api.chat.members.restrictChatMember
import dev.inmo.tgbotapi.extensions.api.edit.edit
import dev.inmo.tgbotapi.extensions.api.send.reply
import dev.inmo.tgbotapi.extensions.api.send.send
import dev.inmo.tgbotapi.extensions.behaviour_builder.BehaviourContext
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithLongPolling
import dev.inmo.tgbotapi.extensions.behaviour_builder.buildBehaviourWithFSMAndStartLongPolling
import dev.inmo.tgbotapi.extensions.behaviour_builder.expectations.*
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onCommand
import dev.inmo.tgbotapi.extensions.behaviour_builder.triggers_handling.onMessageDataCallbackQuery
import dev.inmo.tgbotapi.extensions.utils.asContentMessage
import dev.inmo.tgbotapi.extensions.utils.asPossiblyReplyMessage
import dev.inmo.tgbotapi.extensions.utils.commonMessageOrNull
import dev.inmo.tgbotapi.extensions.utils.contentMessageOrNull
import dev.inmo.tgbotapi.extensions.utils.extendedGroupChatOrNull
import dev.inmo.tgbotapi.extensions.utils.fromUserMessageOrNull
import dev.inmo.tgbotapi.extensions.utils.restrictedChatMemberOrNull
import dev.inmo.tgbotapi.extensions.utils.types.buttons.dataButton
import dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard
import dev.inmo.tgbotapi.extensions.utils.whenMemberChatMember
import dev.inmo.tgbotapi.types.BotCommand
import dev.inmo.tgbotapi.types.ChatId
import dev.inmo.tgbotapi.types.UserId
import dev.inmo.tgbotapi.extensions.utils.*
import dev.inmo.tgbotapi.extensions.utils.extensions.sameChat
import dev.inmo.tgbotapi.extensions.utils.types.buttons.*
import dev.inmo.tgbotapi.types.*
import dev.inmo.tgbotapi.types.buttons.InlineKeyboardMarkup
import dev.inmo.tgbotapi.types.chat.ChannelChat
import dev.inmo.tgbotapi.types.chat.ChatPermissions
import dev.inmo.tgbotapi.types.chat.PublicChat
import dev.inmo.tgbotapi.types.chat.member.*
import dev.inmo.tgbotapi.types.commands.BotCommandScope
import dev.inmo.tgbotapi.types.toChatId
import dev.inmo.tgbotapi.utils.row
import dev.inmo.tgbotapi.types.request.RequestId
import dev.inmo.tgbotapi.utils.*
import dev.inmo.tgbotapi.utils.mention
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.mapNotNull
sealed interface UserRetrievingStep : State {
data class RetrievingChannelChatState(
override val context: ChatId
) : UserRetrievingStep
data class RetrievingUserIdChatState(
override val context: ChatId,
val channelId: ChatId
) : UserRetrievingStep
data class RetrievingChatInfoDoneState(
override val context: ChatId,
val channelId: ChatId,
val userId: UserId
) : UserRetrievingStep
}
suspend fun main(args: Array<String>) {
val botToken = args.first()
@ -60,20 +76,31 @@ suspend fun main(args: Array<String>) {
val otherMessagesToggleCommonData = "$commonDataPrefix other messages"
val webPagePreviewToggleCommonData = "$commonDataPrefix web page preview"
val adminRightsDataPrefix = "admin"
val refreshAdminRightsData = "${adminRightsDataPrefix}_refresh"
val postMessagesToggleAdminRightsData = "${adminRightsDataPrefix}_post_messages"
val editMessagesToggleAdminRightsData = "${adminRightsDataPrefix}_edit_messages"
val deleteMessagesToggleAdminRightsData = "${adminRightsDataPrefix}_delete_messages"
val editStoriesToggleAdminRightsData = "${adminRightsDataPrefix}_edit_stories"
val deleteStoriesToggleAdminRightsData = "${adminRightsDataPrefix}_delete_stories"
val postStoriesToggleAdminRightsData = "${adminRightsDataPrefix}_post_stories"
suspend fun BehaviourContext.getUserChatPermissions(chatId: ChatId, userId: UserId): ChatPermissions? {
val chatMember = getChatMember(chatId, userId)
return chatMember.restrictedChatMemberOrNull() ?: chatMember.whenMemberChatMember {
getChat(chatId).extendedGroupChatOrNull() ?.permissions
}
}
suspend fun BehaviourContext.buildGranularKeyboard(chatId: ChatId, userId: UserId): InlineKeyboardMarkup? {
val permissions = getUserChatPermissions(chatId, userId) ?: return null
fun buildGranularKeyboard(
permissions: ChatPermissions
): InlineKeyboardMarkup {
return inlineKeyboard {
row {
dataButton("Send messages${permissions.canSendMessages.allowedSymbol()}", messagesToggleGranularData)
dataButton("Send other messages${permissions.canSendOtherMessages.allowedSymbol()}", otherMessagesToggleGranularData)
dataButton(
"Send other messages${permissions.canSendOtherMessages.allowedSymbol()}",
otherMessagesToggleGranularData
)
}
row {
dataButton("Send audios${permissions.canSendAudios.allowedSymbol()}", audiosToggleGranularData)
@ -81,11 +108,17 @@ suspend fun main(args: Array<String>) {
}
row {
dataButton("Send videos${permissions.canSendVideos.allowedSymbol()}", videosToggleGranularData)
dataButton("Send video notes${permissions.canSendVideoNotes.allowedSymbol()}", videoNotesToggleGranularData)
dataButton(
"Send video notes${permissions.canSendVideoNotes.allowedSymbol()}",
videoNotesToggleGranularData
)
}
row {
dataButton("Send photos${permissions.canSendPhotos.allowedSymbol()}", photosToggleGranularData)
dataButton("Add web preview${permissions.canAddWebPagePreviews.allowedSymbol()}", webPagePreviewToggleGranularData)
dataButton(
"Add web preview${permissions.canAddWebPagePreviews.allowedSymbol()}",
webPagePreviewToggleGranularData
)
}
row {
dataButton("Send polls${permissions.canSendPolls.allowedSymbol()}", pollsToggleGranularData)
@ -93,6 +126,41 @@ suspend fun main(args: Array<String>) {
}
}
}
fun buildAdminRightsKeyboard(
permissions: AdministratorChatMember?,
channelId: ChatId,
userId: UserId
): InlineKeyboardMarkup {
return inlineKeyboard {
permissions ?.also {
row {
dataButton("Refresh", "$refreshAdminRightsData ${channelId.chatId} ${userId.chatId}")
}
row {
dataButton("Edit messages${permissions.canEditMessages.allowedSymbol()}", "$editMessagesToggleAdminRightsData ${channelId.chatId} ${userId.chatId}")
dataButton("Delete messages${permissions.canRemoveMessages.allowedSymbol()}", "$deleteMessagesToggleAdminRightsData ${channelId.chatId} ${userId.chatId}")
}
row {
dataButton("Post messages${permissions.canPostMessages.allowedSymbol()}", "$postMessagesToggleAdminRightsData ${channelId.chatId} ${userId.chatId}")
}
row {
dataButton("Edit stories${permissions.canEditStories.allowedSymbol()}", "$editStoriesToggleAdminRightsData ${channelId.chatId} ${userId.chatId}")
dataButton("Delete stories${permissions.canDeleteStories.allowedSymbol()}", "$deleteStoriesToggleAdminRightsData ${channelId.chatId} ${userId.chatId}")
}
row {
dataButton("Post stories${permissions.canPostStories.allowedSymbol()}", "$postStoriesToggleAdminRightsData ${channelId.chatId} ${userId.chatId}")
}
} ?: row {
dataButton("Promote to admin", "$postMessagesToggleAdminRightsData ${channelId.chatId} ${userId.chatId}")
}
}
}
suspend fun BehaviourContext.buildGranularKeyboard(chatId: ChatId, userId: UserId): InlineKeyboardMarkup? {
return buildGranularKeyboard(
getUserChatPermissions(chatId, userId) ?: return null
)
}
suspend fun BehaviourContext.buildCommonKeyboard(chatId: ChatId, userId: UserId): InlineKeyboardMarkup? {
val permissions = getUserChatPermissions(chatId, userId) ?: return null
@ -110,23 +178,32 @@ suspend fun main(args: Array<String>) {
}
}
bot.buildBehaviourWithLongPolling(
bot.buildBehaviourWithFSMAndStartLongPolling<UserRetrievingStep>(
defaultExceptionsHandler = {
it.printStackTrace()
}
},
) {
onCommand("simple", initialFilter = { it.chat is PublicChat && it.fromUserMessageOrNull() ?.user ?.id == allowedAdmin }) {
onCommand(
"simple",
initialFilter = { it.chat is PublicChat && it.fromUserMessageOrNull()?.user?.id == allowedAdmin }) {
val replyMessage = it.replyTo
val userInReply = replyMessage ?.fromUserMessageOrNull() ?.user ?.id ?: return@onCommand
val userInReply = replyMessage?.fromUserMessageOrNull()?.user?.id ?: return@onCommand
reply(
replyMessage,
"Manage keyboard:",
replyMarkup = buildCommonKeyboard(it.chat.id.toChatId(), userInReply) ?: return@onCommand
)
}
onCommand("granular", initialFilter = { it.chat is PublicChat && it.fromUserMessageOrNull() ?.user ?.id == allowedAdmin }) {
onCommand(
"granular",
initialFilter = {
it.chat is ChannelChat || (it.chat is PublicChat && it.fromUserMessageOrNull()?.user?.id == allowedAdmin)
}
) {
val replyMessage = it.replyTo
val userInReply = replyMessage ?.fromUserMessageOrNull() ?.user ?.id ?: return@onCommand
val usernameInText = it.content.textSources.firstNotNullOfOrNull { it.mentionTextSourceOrNull() } ?.username
val userInReply = replyMessage?.fromUserMessageOrNull()?.user?.id ?: return@onCommand
reply(
replyMessage,
"Manage keyboard:",
@ -138,60 +215,72 @@ suspend fun main(args: Array<String>) {
Regex("^${granularDataPrefix}.*"),
initialFilter = { it.user.id == allowedAdmin }
) {
val messageReply = it.message.commonMessageOrNull() ?.replyTo ?.fromUserMessageOrNull() ?: return@onMessageDataCallbackQuery
val messageReply =
it.message.commonMessageOrNull()?.replyTo?.fromUserMessageOrNull() ?: return@onMessageDataCallbackQuery
val userId = messageReply.user.id
val permissions = getUserChatPermissions(it.message.chat.id.toChatId(), userId) ?: return@onMessageDataCallbackQuery
val permissions =
getUserChatPermissions(it.message.chat.id.toChatId(), userId) ?: return@onMessageDataCallbackQuery
val newPermission = when (it.data) {
messagesToggleGranularData -> {
permissions.copyGranular(
canSendMessages = permissions.canSendMessages ?.let { !it } ?: false
canSendMessages = permissions.canSendMessages?.let { !it } ?: false
)
}
otherMessagesToggleGranularData -> {
permissions.copyGranular(
canSendOtherMessages = permissions.canSendOtherMessages ?.let { !it } ?: false
canSendOtherMessages = permissions.canSendOtherMessages?.let { !it } ?: false
)
}
audiosToggleGranularData -> {
permissions.copyGranular(
canSendAudios = permissions.canSendAudios ?.let { !it } ?: false
canSendAudios = permissions.canSendAudios?.let { !it } ?: false
)
}
voicesToggleGranularData -> {
permissions.copyGranular(
canSendVoiceNotes = permissions.canSendVoiceNotes ?.let { !it } ?: false
canSendVoiceNotes = permissions.canSendVoiceNotes?.let { !it } ?: false
)
}
videosToggleGranularData -> {
permissions.copyGranular(
canSendVideos = permissions.canSendVideos ?.let { !it } ?: false
canSendVideos = permissions.canSendVideos?.let { !it } ?: false
)
}
videoNotesToggleGranularData -> {
permissions.copyGranular(
canSendVideoNotes = permissions.canSendVideoNotes ?.let { !it } ?: false
canSendVideoNotes = permissions.canSendVideoNotes?.let { !it } ?: false
)
}
photosToggleGranularData -> {
permissions.copyGranular(
canSendPhotos = permissions.canSendPhotos ?.let { !it } ?: false
canSendPhotos = permissions.canSendPhotos?.let { !it } ?: false
)
}
webPagePreviewToggleGranularData -> {
permissions.copyGranular(
canAddWebPagePreviews = permissions.canAddWebPagePreviews ?.let { !it } ?: false
canAddWebPagePreviews = permissions.canAddWebPagePreviews?.let { !it } ?: false
)
}
pollsToggleGranularData -> {
permissions.copyGranular(
canSendPolls = permissions.canSendPolls ?.let { !it } ?: false
canSendPolls = permissions.canSendPolls?.let { !it } ?: false
)
}
documentsToggleGranularData -> {
permissions.copyGranular(
canSendDocuments = permissions.canSendDocuments ?.let { !it } ?: false
canSendDocuments = permissions.canSendDocuments?.let { !it } ?: false
)
}
else -> permissions.copyGranular()
}
@ -204,7 +293,8 @@ suspend fun main(args: Array<String>) {
edit(
it.message,
replyMarkup = buildGranularKeyboard(it.message.chat.id.toChatId(), userId) ?: return@onMessageDataCallbackQuery
replyMarkup = buildGranularKeyboard(it.message.chat.id.toChatId(), userId)
?: return@onMessageDataCallbackQuery
)
}
@ -212,25 +302,30 @@ suspend fun main(args: Array<String>) {
Regex("^${commonDataPrefix}.*"),
initialFilter = { it.user.id == allowedAdmin }
) {
val messageReply = it.message.commonMessageOrNull() ?.replyTo ?.fromUserMessageOrNull() ?: return@onMessageDataCallbackQuery
val messageReply =
it.message.commonMessageOrNull()?.replyTo?.fromUserMessageOrNull() ?: return@onMessageDataCallbackQuery
val userId = messageReply.user.id
val permissions = getUserChatPermissions(it.message.chat.id.toChatId(), userId) ?: return@onMessageDataCallbackQuery
val permissions =
getUserChatPermissions(it.message.chat.id.toChatId(), userId) ?: return@onMessageDataCallbackQuery
val newPermission = when (it.data) {
pollsToggleCommonData -> {
permissions.copyCommon(
canSendPolls = permissions.canSendPolls ?.let { !it } ?: false
canSendPolls = permissions.canSendPolls?.let { !it } ?: false
)
}
otherMessagesToggleCommonData -> {
permissions.copyCommon(
canSendOtherMessages = permissions.canSendOtherMessages ?.let { !it } ?: false
canSendOtherMessages = permissions.canSendOtherMessages?.let { !it } ?: false
)
}
webPagePreviewToggleCommonData -> {
permissions.copyCommon(
canAddWebPagePreviews = permissions.canAddWebPagePreviews ?.let { !it } ?: false
canAddWebPagePreviews = permissions.canAddWebPagePreviews?.let { !it } ?: false
)
}
else -> permissions.copyCommon()
}
@ -243,13 +338,169 @@ suspend fun main(args: Array<String>) {
edit(
it.message,
replyMarkup = buildCommonKeyboard(it.message.chat.id.toChatId(), userId) ?: return@onMessageDataCallbackQuery
replyMarkup = buildCommonKeyboard(it.message.chat.id.toChatId(), userId)
?: return@onMessageDataCallbackQuery
)
}
onMessageDataCallbackQuery(
Regex("^${adminRightsDataPrefix}.*"),
initialFilter = { it.user.id == allowedAdmin }
) {
val (channelIdString, userIdString) = it.data.split(" ").drop(1)
val channelId = ChatId(channelIdString.toLong())
val userId = ChatId(userIdString.toLong())
val chatMember = getChatMember(channelId, userId)
val asAdmin = chatMember.administratorChatMemberOrNull()
val asMember = chatMember.memberChatMemberOrNull()
val realData = it.data.takeWhile { it != ' ' }
fun Boolean?.toggleIfData(data: String) = if (realData == data) {
!(this ?: false)
} else {
null
}
if (realData != refreshAdminRightsData) {
promoteChannelAdministrator(
channelId,
userId,
canPostMessages = asAdmin ?.canPostMessages.toggleIfData(postMessagesToggleAdminRightsData),
canEditMessages = asAdmin ?.canEditMessages.toggleIfData(editMessagesToggleAdminRightsData),
canDeleteMessages = asAdmin ?.canRemoveMessages.toggleIfData(deleteMessagesToggleAdminRightsData),
canEditStories = asAdmin ?.canEditStories.toggleIfData(editStoriesToggleAdminRightsData),
canDeleteStories = asAdmin ?.canDeleteStories.toggleIfData(deleteStoriesToggleAdminRightsData),
canPostStories = asAdmin ?.canPostStories.toggleIfData(postStoriesToggleAdminRightsData),
)
}
edit(
it.message,
replyMarkup = buildAdminRightsKeyboard(
getChatMember(
channelId,
userId
).administratorChatMemberOrNull(),
channelId,
userId
)
)
}
strictlyOn<UserRetrievingStep.RetrievingChannelChatState> { state ->
val requestId = RequestId.random()
send(
state.context,
replyMarkup = replyKeyboard(
oneTimeKeyboard = true,
resizeKeyboard = true
) {
row {
requestChatButton(
"Choose channel",
requestId = requestId,
isChannel = true,
botIsMember = true,
botRightsInChat = ChatCommonAdministratorRights(
canPromoteMembers = true,
canRestrictMembers = true
),
userRightsInChat = ChatCommonAdministratorRights(
canPromoteMembers = true,
canRestrictMembers = true
)
)
}
}
) {
regular("Ok, send me the channel in which you wish to manage user, or use ")
botCommand("cancel")
regular(" to cancel the request")
}
firstOf {
include {
val chatId = waitChatSharedEventsMessages().mapNotNull {
it.chatEvent.chatId.takeIf { _ ->
it.chatEvent.requestId == requestId && it.sameChat(state.context)
}
}.first()
UserRetrievingStep.RetrievingUserIdChatState(state.context, chatId)
}
include {
waitCommandMessage("cancel").filter { it.sameChat(state.context) }.first()
null
}
}
}
strictlyOn<UserRetrievingStep.RetrievingUserIdChatState> { state ->
val requestId = RequestId.random()
send(
state.context,
replyMarkup = replyKeyboard(
oneTimeKeyboard = true,
resizeKeyboard = true
) {
row {
requestUserButton(
"Choose user",
requestId = requestId
)
}
}
) {
regular("Ok, send me the user for which you wish to change rights, or use ")
botCommand("cancel")
regular(" to cancel the request")
}
firstOf {
include {
val userContactChatId = waitUserSharedEventsMessages().filter {
it.sameChat(state.context)
}.first().chatEvent.chatId
UserRetrievingStep.RetrievingChatInfoDoneState(
state.context,
state.channelId,
userContactChatId
)
}
include {
waitCommandMessage("cancel").filter { it.sameChat(state.context) }.first()
null
}
}
}
strictlyOn<UserRetrievingStep.RetrievingChatInfoDoneState> { state ->
val chatMember = getChatMember(state.channelId, state.userId).administratorChatMemberOrNull()
if (chatMember == null) {
return@strictlyOn null
}
send(
state.context,
replyMarkup = buildAdminRightsKeyboard(
chatMember,
state.channelId,
state.userId
)
) {
regular("Rights of ")
mentionln(chatMember.user)
regular("Please, remember, that to be able to change user rights bot must promote user by itself to admin")
}
null
}
onCommand("rights_in_channel") {
startChain(UserRetrievingStep.RetrievingChannelChatState(it.chat.id.toChatId()))
}
setMyCommands(
BotCommand("simple", "Trigger simple keyboard. Use with reply to user"),
BotCommand("granular", "Trigger granular keyboard. Use with reply to user"),
BotCommand("rights_in_channel", "Trigger granular keyboard. Use with reply to user"),
scope = BotCommandScope.AllGroupChats
)
}.join()

View File

@ -1,6 +1,7 @@
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
import dev.inmo.tgbotapi.types.webAppQueryIdField
import dev.inmo.tgbotapi.webapps.*
import dev.inmo.tgbotapi.webapps.cloud.*
import dev.inmo.tgbotapi.webapps.haptic.HapticFeedbackStyle
import dev.inmo.tgbotapi.webapps.haptic.HapticFeedbackType
import dev.inmo.tgbotapi.webapps.popup.*
@ -14,8 +15,11 @@ import kotlinx.browser.window
import kotlinx.coroutines.*
import kotlinx.dom.appendElement
import kotlinx.dom.appendText
import kotlinx.dom.clear
import kotlinx.serialization.json.Json
import org.w3c.dom.HTMLElement
import org.w3c.dom.*
import kotlin.random.Random
import kotlin.random.nextUBytes
fun HTMLElement.log(text: String) {
appendText(text)
@ -70,6 +74,9 @@ fun main() {
appendText("Exit 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:")
@ -110,6 +117,32 @@ fun main() {
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(
@ -142,6 +175,91 @@ fun main() {
document.body ?.appendElement("p", {})
document.body ?.appendElement("button") {
fun updateHeaderColor() {
val (r, g, b) = Random.nextUBytes(3)
val hex = Color.Hex(r, g, b)
webApp.setHeaderColor(hex)
(this as? HTMLButtonElement) ?.style ?.backgroundColor = hex.value
textContent = "Header color: ${hex.value.uppercase()} (click to change)"
}
addEventListener("click", {
updateHeaderColor()
})
updateHeaderColor()
} ?: window.alert("Unable to load body")
document.body ?.appendElement("p", {})
fun Element.updateCloudStorageContent() {
clear()
webApp.cloudStorage.getAll {
it.onSuccess {
document.body ?.log(it.toString())
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
document.body ?.appendElement("p", {})
webApp.apply {
onThemeChanged {
document.body ?.log("Theme changed: ${webApp.themeParams}")
@ -171,8 +289,18 @@ fun main() {
onSettingsButtonClicked {
document.body ?.log("Settings button clicked")
}
onWriteAccessRequested {
document.body ?.log("Write access request result: $it")
}
onContactRequested {
document.body ?.log("Contact request result: $it")
}
}
webApp.ready()
document.body ?.appendElement("input", {
(this as HTMLInputElement).value = window.location.href
})
cloudStorageContentDiv.updateCloudStorageContent()
}.onFailure {
window.alert(it.stackTraceToString())
}

View File

@ -5,7 +5,7 @@ org.gradle.jvmargs=-Xmx2g
kotlin_version=1.8.22
telegram_bot_api_version=9.1.2
telegram_bot_api_version=9.2.0
micro_utils_version=0.19.9
serialization_version=1.5.1
ktor_version=2.3.3