diff --git a/CHANGELOG.md b/CHANGELOG.md index a6fcaa13d5..bf70590d56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # TelegramBotAPI changelog +## 3.1.1 + +* `Common`: + * Complete Bot API 6.2 implementation + ## 3.1.0 **This update contains including of Bot API 6.2** diff --git a/gradle.properties b/gradle.properties index 6ca3ff5cb4..c0a1d7b5fe 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,4 +6,4 @@ kotlin.incremental=true kotlin.incremental.js=true library_group=dev.inmo -library_version=3.1.0 +library_version=3.1.1 diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt index 103f327380..0e1cf5f246 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/Common.kt @@ -164,6 +164,7 @@ const val languageCodeField = "language_code" const val addedToAttachmentMenuField = "added_to_attachment_menu" const val isPremiumField = "is_premium" const val hasPrivateForwardsField = "has_private_forwards" +const val hasRestrictedVoiceAndVideoMessagesField = "has_restricted_voice_and_video_messages" const val canJoinGroupsField = "can_join_groups" const val canReadAllGroupMessagesField = "can_read_all_group_messages" const val supportInlineQueriesField = "supports_inline_queries" diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/Extended.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/Extended.kt index fed027677d..01ead1be28 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/Extended.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/Extended.kt @@ -62,7 +62,9 @@ data class ExtendedPrivateChatImpl( @SerialName(bioField) override val bio: String = "", @SerialName(hasPrivateForwardsField) - override val hasPrivateForwards: Boolean = false + override val hasPrivateForwards: Boolean = false, + @SerialName(hasRestrictedVoiceAndVideoMessagesField) + override val hasRestrictedVoiceAndVideoMessages: Boolean = false ) : ExtendedPrivateChat typealias ExtendedUser = ExtendedPrivateChatImpl diff --git a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ExtendedAbstracts.kt b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ExtendedAbstracts.kt index 26cf8115ae..6705d8203d 100644 --- a/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ExtendedAbstracts.kt +++ b/tgbotapi.core/src/commonMain/kotlin/dev/inmo/tgbotapi/types/chat/ExtendedAbstracts.kt @@ -19,6 +19,7 @@ sealed interface ExtendedGroupChat : GroupChat, ExtendedPublicChat { sealed interface ExtendedPrivateChat : PrivateChat, ExtendedChat { val bio: String val hasPrivateForwards: Boolean + val hasRestrictedVoiceAndVideoMessages: Boolean val allowCreateUserIdLink: Boolean get() = hasPrivateForwards diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/AlertCallback.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/AlertCallback.kt new file mode 100644 index 0000000000..8ed7e55b60 --- /dev/null +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/AlertCallback.kt @@ -0,0 +1,3 @@ +package dev.inmo.tgbotapi.webapps + +typealias AlertCallback = () -> Unit diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/ConfirmCallback.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/ConfirmCallback.kt new file mode 100644 index 0000000000..4c9f85296b --- /dev/null +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/ConfirmCallback.kt @@ -0,0 +1,3 @@ +package dev.inmo.tgbotapi.webapps + +typealias ConfirmCallback = (confirmed: Boolean) -> Unit diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/EventHandler.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/EventHandler.kt index e0e5dc7f37..f83d2fd7dc 100644 --- a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/EventHandler.kt +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/EventHandler.kt @@ -5,3 +5,4 @@ import dev.inmo.tgbotapi.webapps.invoice.InvoiceClosedInfo typealias EventHandler = WebApp.() -> Unit typealias ViewportChangedEventHandler = WebApp.(ViewportChangedData) -> Unit typealias InvoiceClosedEventHandler = WebApp.(InvoiceClosedInfo) -> Unit +typealias PopupClosedEventHandler = WebApp.(String?) -> Unit 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 a75b20218c..ff71329074 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 @@ -7,4 +7,5 @@ sealed class EventType(val typeName: String) { object BackButtonClicked : EventType("backButtonClicked") object SettingsButtonClicked : EventType("settingsButtonClicked") object InvoiceClosed : EventType("invoiceClosed") + object PopupClosed : EventType("popupClosed") } diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/WebApp.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/WebApp.kt index 365d07af4b..d31d1d6cf9 100644 --- a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/WebApp.kt +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/WebApp.kt @@ -3,6 +3,7 @@ package dev.inmo.tgbotapi.webapps import dev.inmo.tgbotapi.utils.TelegramAPIUrlsKeeper import dev.inmo.tgbotapi.webapps.haptic.HapticFeedback import dev.inmo.tgbotapi.webapps.invoice.InvoiceClosedInfo +import dev.inmo.tgbotapi.webapps.popup.* external class WebApp { val version: String @@ -24,6 +25,15 @@ external class WebApp { val viewportHeight: Float val viewportStableHeight: Float + + val isClosingConfirmationEnabled: Boolean + fun enableClosingConfirmation() + fun disableClosingConfirmation() + + fun showPopup(params: PopupParams, callback: ClosePopupCallback? = definedExternally) + fun showAlert(message: String, callback: AlertCallback? = definedExternally) + fun showConfirm(message: String, callback: ConfirmCallback? = definedExternally) + @JsName("MainButton") val mainButton: MainButton @@ -38,6 +48,8 @@ external class WebApp { internal fun onEventWithViewportChangedData(type: String, callback: (ViewportChangedData) -> Unit) @JsName("onEvent") internal fun onEventWithInvoiceClosedInfo(type: String, callback: (InvoiceClosedInfo) -> Unit) + @JsName("onEvent") + internal fun onEventWithPopupClosedInfo(type: String, callback: (String?) -> Unit) fun offEvent(type: String, callback: () -> Unit) @JsName("offEvent") @@ -100,6 +112,18 @@ fun WebApp.onEvent(type: EventType.InvoiceClosed, eventHandler: InvoiceClosedEve ) } +/** + * @return The callback which should be used in case you want to turn off events handling + */ +fun WebApp.onEvent(type: EventType.PopupClosed, eventHandler: PopupClosedEventHandler) = { it: String? -> + eventHandler(js("this").unsafeCast(), it) +}.also { + onEventWithPopupClosedInfo( + type.typeName, + callback = it + ) +} + /** * @return The callback which should be used in case you want to turn off events handling */ @@ -124,8 +148,55 @@ fun WebApp.onSettingsButtonClicked(eventHandler: EventHandler) = onEvent(EventTy * @return The callback which should be used in case you want to turn off events handling */ fun WebApp.onInvoiceClosed(eventHandler: InvoiceClosedEventHandler) = onEvent(EventType.InvoiceClosed, eventHandler) +/** + * @return The callback which should be used in case you want to turn off events handling + */ +fun WebApp.onPopupClosed(eventHandler: PopupClosedEventHandler) = onEvent(EventType.PopupClosed, eventHandler) fun WebApp.isInitDataSafe(botToken: String) = TelegramAPIUrlsKeeper(botToken).checkWebAppData( initData, initDataUnsafe.hash ) + +fun WebApp.showPopup( + message: String, + title: String?, + buttons: Array, + callback: ClosePopupCallback? = null +) = showPopup( + PopupParams( + message, + title, + buttons + ), + callback +) + +fun WebApp.showPopup( + message: String, + title: String?, + firstButton: PopupButton, + vararg otherButtons: PopupButton, + callback: ClosePopupCallback? = null +) = showPopup( + PopupParams( + message, + title, + arrayOf(firstButton, *otherButtons) + ), + callback +) + +var WebApp.requireClosingConfirmation + get() = isClosingConfirmationEnabled + set(value) { + if (value) { + enableClosingConfirmation() + } else { + disableClosingConfirmation() + } + } + +fun WebApp.toggleClosingConfirmation() { + requireClosingConfirmation = !requireClosingConfirmation +} diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/WebAppUser.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/WebAppUser.kt index 92f7b87fd2..facd42061e 100644 --- a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/WebAppUser.kt +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/WebAppUser.kt @@ -17,10 +17,14 @@ external interface WebAppUser { val username: String? @JsName(languageCodeField) val languageCode: String? + val is_premium: Boolean? @JsName(photoUrlField) val photoUrl: String? } +val WebAppUser.isPremium + get() = is_premium == true + fun WebAppUser.asUser() = if (isBot == true) { CommonBot( UserId(id), @@ -34,6 +38,7 @@ fun WebAppUser.asUser() = if (isBot == true) { firstName, lastName ?: "", username ?.let(::Username), - languageCode ?.let(::IetfLanguageCode) + languageCode ?.let(::IetfLanguageCode), + isPremium = isPremium ) } diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/popup/ClosePopupCallback.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/popup/ClosePopupCallback.kt new file mode 100644 index 0000000000..17727bef69 --- /dev/null +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/popup/ClosePopupCallback.kt @@ -0,0 +1,3 @@ +package dev.inmo.tgbotapi.webapps.popup + +typealias ClosePopupCallback = (id: String) -> Unit diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/popup/PopupButton.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/popup/PopupButton.kt new file mode 100644 index 0000000000..992a70c1cb --- /dev/null +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/popup/PopupButton.kt @@ -0,0 +1,55 @@ +package dev.inmo.tgbotapi.webapps.popup + +import kotlin.js.json + +external interface PopupButton { + val id: String + val type: PopupButtonType + val text: String? +} + +fun PopupButton( + id: String, + type: PopupButtonType, + text: String? = null +) = json( + *listOfNotNull( + "id" to id, + "type" to type.typeName, + ("text" to text).takeIf { text != null } + ).toTypedArray() +).unsafeCast() + +value class PopupButtonType( + val typeName: String +) { + companion object { + val Default = PopupButtonType("default") + val Ok = PopupButtonType("ok") + val Close = PopupButtonType("close") + val Cancel = PopupButtonType("cancel") + val Destructive = PopupButtonType("destructive") + } +} + +fun DefaultPopupButton( + id: String, + text: String +) = PopupButton(id, PopupButtonType.Default, text) + +fun OkPopupButton( + id: String +) = PopupButton(id, PopupButtonType.Ok) + +fun ClosePopupButton( + id: String +) = PopupButton(id, PopupButtonType.Close) + +fun CancelPopupButton( + id: String +) = PopupButton(id, PopupButtonType.Cancel) + +fun DestructivePopupButton( + id: String, + text: String +) = PopupButton(id, PopupButtonType.Destructive, text) diff --git a/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/popup/PopupParams.kt b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/popup/PopupParams.kt new file mode 100644 index 0000000000..8fe40507cb --- /dev/null +++ b/tgbotapi.webapps/src/jsMain/kotlin/dev/inmo/tgbotapi/webapps/popup/PopupParams.kt @@ -0,0 +1,48 @@ +package dev.inmo.tgbotapi.webapps.popup + +import kotlin.js.json + +external interface PopupParams { + val message: String + val title: String? + val buttons: Array +} + +fun PopupParams( + message: String, + title: String?, + buttons: Array +) = json( + *listOfNotNull( + "message" to message, + "buttons" to buttons, + ("title" to title).takeIf { title != null } + ).toTypedArray() +).unsafeCast() + +fun PopupParams( + message: String, + firstButton: PopupButton, + vararg otherButtons: PopupButton +) = PopupParams( + message, + null, + arrayOf( + firstButton, + *otherButtons + ) +) + +fun PopupParams( + title: String, + message: String, + firstButton: PopupButton, + vararg otherButtons: PopupButton +) = PopupParams( + message, + title, + arrayOf( + firstButton, + *otherButtons + ) +)