diff --git a/.github/workflows/kdocs.yml b/.github/workflows/kdocs.yml index a167050ff8..6d1a95b381 100644 --- a/.github/workflows/kdocs.yml +++ b/.github/workflows/kdocs.yml @@ -10,7 +10,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-java@v1 with: - java-version: 1.8 + java-version: 11 - name: Build run: ./gradlew dokkaHtml - name: Publish KDocs diff --git a/.github/workflows/packages_publishing.yml b/.github/workflows/packages_publishing.yml index c16ebdcb19..233fc307b8 100644 --- a/.github/workflows/packages_publishing.yml +++ b/.github/workflows/packages_publishing.yml @@ -7,10 +7,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-java@v1 with: - java-version: 1.8 - - name: Fix android 31.0.0 dx - continue-on-error: true - run: cd /usr/local/lib/android/sdk/build-tools/31.0.0/ && mv d8 dx && cd lib && mv d8.jar dx.jar + java-version: 11 - name: Rewrite version run: | branch="`echo "${{ github.ref }}" | grep -o "[^/]*$"`" @@ -21,7 +18,7 @@ jobs: run: ./gradlew build - name: Publish continue-on-error: true - run: ./gradlew publishAllPublicationsToGithubPackagesRepository --no-parallel -x signJsPublication -x signJvmPublication -x signKotlinMultiplatformPublication + run: ./gradlew publishAllPublicationsToGithubPackagesRepository --no-parallel env: GITHUBPACKAGES_USER: ${{ github.actor }} GITHUBPACKAGES_PASSWORD: ${{ secrets.GITHUB_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 42df2a81ac..52c6becbcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # TelegramBotAPI changelog +## 0.38.10 + +* `API`: + * All `with*Action` extensions got a contracts which declare that `block` will be called once + * Add several extensions `TelegramBot#sendPhoto` with `PhotoSize` + * Add several extensions `TelegramBot#reply` with `PhotoSize` + ## 0.38.9 * `Core`: diff --git a/gradle.properties b/gradle.properties index 5e9a295f20..4ff2348dfc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -20,6 +20,6 @@ javax_activation_version=1.1.1 dokka_version=1.6.10 library_group=dev.inmo -library_version=0.38.9 +library_version=0.38.10 github_release_plugin_version=2.2.12 diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/Replies.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/Replies.kt index 1779e7c648..eafb27672d 100644 --- a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/Replies.kt +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/Replies.kt @@ -571,6 +571,17 @@ suspend inline fun TelegramBot.reply( replyMarkup: KeyboardMarkup? = null ) = sendPhoto(to.chat, photo, text, parseMode, disableNotification, protectContent, to.messageId, allowSendingWithoutReply, replyMarkup) +suspend inline fun TelegramBot.reply( + to: Message, + photoSize: PhotoSize, + text: String? = null, + parseMode: ParseMode? = null, + disableNotification: Boolean = false, + protectContent: Boolean = false, + allowSendingWithoutReply: Boolean? = null, + replyMarkup: KeyboardMarkup? = null +) = sendPhoto(to.chat, photoSize, text, parseMode, disableNotification, protectContent, to.messageId, allowSendingWithoutReply, replyMarkup) + suspend inline fun TelegramBot.replyWithPhoto( to: Message, @@ -592,6 +603,16 @@ suspend inline fun TelegramBot.reply( replyMarkup: KeyboardMarkup? = null ) = sendPhoto(to.chat, photo, entities, disableNotification, protectContent, to.messageId, allowSendingWithoutReply, replyMarkup) +suspend inline fun TelegramBot.reply( + to: Message, + photoSize: PhotoSize, + entities: TextSourcesList, + disableNotification: Boolean = false, + protectContent: Boolean = false, + allowSendingWithoutReply: Boolean? = null, + replyMarkup: KeyboardMarkup? = null +) = sendPhoto(to.chat, photoSize, entities, disableNotification, protectContent, to.messageId, allowSendingWithoutReply, replyMarkup) + // Sticker diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/SendActionDSL.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/SendActionDSL.kt index c247ad55c1..e9d5a18ebf 100644 --- a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/SendActionDSL.kt +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/SendActionDSL.kt @@ -8,15 +8,20 @@ import dev.inmo.tgbotapi.types.* import dev.inmo.tgbotapi.types.actions.* import dev.inmo.tgbotapi.types.chat.abstracts.Chat import kotlinx.coroutines.* +import kotlin.contracts.* import kotlin.coroutines.coroutineContext private const val refreshTime: MilliSeconds = (botActionActualityTime - 1) * 1000L typealias TelegramBotActionCallback = suspend TelegramBot.() -> T +@OptIn(ExperimentalContracts::class) suspend fun TelegramBot.withAction( actionRequest: SendAction, block: TelegramBotActionCallback ): T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } val botActionJob = CoroutineScope(coroutineContext).launch { while (isActive) { delay(refreshTime) @@ -30,46 +35,190 @@ suspend fun TelegramBot.withAction( return result.getOrThrow() } +@OptIn(ExperimentalContracts::class) suspend fun TelegramBot.withAction( chatId: ChatId, action: BotAction, block: TelegramBotActionCallback -) = withAction( - SendAction(chatId, action), - block -) +): T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction( + SendAction(chatId, action), + block + ) +} +@OptIn(ExperimentalContracts::class) suspend fun TelegramBot.withAction( chat: Chat, action: BotAction, block: TelegramBotActionCallback -) = withAction( - chat.id, - action, - block -) +): T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction( + chat.id, + action, + block + ) +} -suspend fun TelegramBot.withTypingAction(chatId: ChatId, block: TelegramBotActionCallback) = withAction(chatId, TypingAction, block) -suspend fun TelegramBot.withUploadPhotoAction(chatId: ChatId, block: TelegramBotActionCallback) = withAction(chatId, UploadPhotoAction, block) -suspend fun TelegramBot.withRecordVideoAction(chatId: ChatId, block: TelegramBotActionCallback) = withAction(chatId, RecordVideoAction, block) -suspend fun TelegramBot.withUploadVideoAction(chatId: ChatId, block: TelegramBotActionCallback) = withAction(chatId, UploadVideoAction, block) -suspend fun TelegramBot.withRecordVoiceAction(chatId: ChatId, block: TelegramBotActionCallback) = withAction(chatId, RecordVoiceAction, block) -suspend fun TelegramBot.withUploadVoiceAction(chatId: ChatId, block: TelegramBotActionCallback) = withAction(chatId, UploadVoiceAction, block) -suspend fun TelegramBot.withUploadDocumentAction(chatId: ChatId, block: TelegramBotActionCallback) = withAction(chatId, UploadDocumentAction, block) -suspend fun TelegramBot.withFindLocationAction(chatId: ChatId, block: TelegramBotActionCallback) = withAction(chatId, FindLocationAction, block) -suspend fun TelegramBot.withRecordVideoNoteAction(chatId: ChatId, block: TelegramBotActionCallback) = withAction(chatId, RecordVideoNoteAction, block) -suspend fun TelegramBot.withUploadVideoNoteAction(chatId: ChatId, block: TelegramBotActionCallback) = withAction(chatId, UploadVideoNoteAction, block) -suspend fun TelegramBot.withChooseStickerAction(chatId: ChatId, block: TelegramBotActionCallback) = withAction(chatId, ChooseStickerAction, block) +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withTypingAction(chatId: ChatId, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chatId, TypingAction, block) +} +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withUploadPhotoAction(chatId: ChatId, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chatId, UploadPhotoAction, block) +} +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withRecordVideoAction(chatId: ChatId, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chatId, RecordVideoAction, block) +} +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withUploadVideoAction(chatId: ChatId, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chatId, UploadVideoAction, block) +} +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withRecordVoiceAction(chatId: ChatId, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chatId, RecordVoiceAction, block) +} +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withUploadVoiceAction(chatId: ChatId, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chatId, UploadVoiceAction, block) +} +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withUploadDocumentAction(chatId: ChatId, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chatId, UploadDocumentAction, block) +} +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withFindLocationAction(chatId: ChatId, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chatId, FindLocationAction, block) +} +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withRecordVideoNoteAction(chatId: ChatId, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chatId, RecordVideoNoteAction, block) +} +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withUploadVideoNoteAction(chatId: ChatId, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chatId, UploadVideoNoteAction, block) +} +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withChooseStickerAction(chatId: ChatId, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chatId, ChooseStickerAction, block) +} -suspend fun TelegramBot.withTypingAction(chat: Chat, block: TelegramBotActionCallback) = withAction(chat, TypingAction, block) -suspend fun TelegramBot.withUploadPhotoAction(chat: Chat, block: TelegramBotActionCallback) = withAction(chat, UploadPhotoAction, block) -suspend fun TelegramBot.withRecordVideoAction(chat: Chat, block: TelegramBotActionCallback) = withAction(chat, RecordVideoAction, block) -suspend fun TelegramBot.withUploadVideoAction(chat: Chat, block: TelegramBotActionCallback) = withAction(chat, UploadVideoAction, block) -suspend fun TelegramBot.withRecordVoiceAction(chat: Chat, block: TelegramBotActionCallback) = withAction(chat, RecordVoiceAction, block) -suspend fun TelegramBot.withUploadVoiceAction(chat: Chat, block: TelegramBotActionCallback) = withAction(chat, UploadVoiceAction, block) -suspend fun TelegramBot.withUploadDocumentAction(chat: Chat, block: TelegramBotActionCallback) = withAction(chat, UploadDocumentAction, block) -suspend fun TelegramBot.withFindLocationAction(chat: Chat, block: TelegramBotActionCallback) = withAction(chat, FindLocationAction, block) -suspend fun TelegramBot.withRecordVideoNoteAction(chat: Chat, block: TelegramBotActionCallback) = withAction(chat, RecordVideoNoteAction, block) -suspend fun TelegramBot.withUploadVideoNoteAction(chat: Chat, block: TelegramBotActionCallback) = withAction(chat, UploadVideoNoteAction, block) -suspend fun TelegramBot.withChooseStickerAction(chat: Chat, block: TelegramBotActionCallback) = withAction(chat, ChooseStickerAction, block) +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withTypingAction(chat: Chat, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chat, TypingAction, block) +} +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withUploadPhotoAction(chat: Chat, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chat, UploadPhotoAction, block) +} +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withRecordVideoAction(chat: Chat, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chat, RecordVideoAction, block) +} +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withUploadVideoAction(chat: Chat, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chat, UploadVideoAction, block) +} +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withRecordVoiceAction(chat: Chat, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chat, RecordVoiceAction, block) +} +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withUploadVoiceAction(chat: Chat, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chat, UploadVoiceAction, block) +} +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withUploadDocumentAction(chat: Chat, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chat, UploadDocumentAction, block) +} +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withFindLocationAction(chat: Chat, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chat, FindLocationAction, block) +} +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withRecordVideoNoteAction(chat: Chat, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chat, RecordVideoNoteAction, block) +} +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withUploadVideoNoteAction(chat: Chat, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chat, UploadVideoNoteAction, block) +} +@OptIn(ExperimentalContracts::class) +suspend fun TelegramBot.withChooseStickerAction(chat: Chat, block: TelegramBotActionCallback) : T { + contract { + callsInPlace(block, InvocationKind.EXACTLY_ONCE) + } + return withAction(chat, ChooseStickerAction, block) +} diff --git a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/media/SendPhoto.kt b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/media/SendPhoto.kt index 39d1b757af..21348dfe03 100644 --- a/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/media/SendPhoto.kt +++ b/tgbotapi.api/src/commonMain/kotlin/dev/inmo/tgbotapi/extensions/api/send/media/SendPhoto.kt @@ -9,8 +9,7 @@ import dev.inmo.tgbotapi.types.MessageIdentifier import dev.inmo.tgbotapi.types.ParseMode.ParseMode import dev.inmo.tgbotapi.types.buttons.KeyboardMarkup import dev.inmo.tgbotapi.types.chat.abstracts.Chat -import dev.inmo.tgbotapi.types.files.Photo -import dev.inmo.tgbotapi.types.files.biggest +import dev.inmo.tgbotapi.types.files.* /** * @param replyMarkup Some of [KeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard] or @@ -88,6 +87,38 @@ suspend fun TelegramBot.sendPhoto( replyMarkup: KeyboardMarkup? = null ) = sendPhoto(chat.id, photo, text, parseMode, disableNotification, protectContent, replyToMessageId, allowSendingWithoutReply, replyMarkup) +/** + * @param replyMarkup Some of [KeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard] or + * [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard] as a builders for that param + */ +suspend fun TelegramBot.sendPhoto( + chatId: ChatIdentifier, + photoSize: PhotoSize, + text: String? = null, + parseMode: ParseMode? = null, + disableNotification: Boolean = false, + protectContent: Boolean = false, + replyToMessageId: MessageIdentifier? = null, + allowSendingWithoutReply: Boolean? = null, + replyMarkup: KeyboardMarkup? = null +) = sendPhoto(chatId, photoSize.fileId, text, parseMode, disableNotification, protectContent, replyToMessageId, allowSendingWithoutReply, replyMarkup) + +/** + * @param replyMarkup Some of [KeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard] or + * [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard] as a builders for that param + */ +suspend fun TelegramBot.sendPhoto( + chat: Chat, + photoSize: PhotoSize, + text: String? = null, + parseMode: ParseMode? = null, + disableNotification: Boolean = false, + protectContent: Boolean = false, + replyToMessageId: MessageIdentifier? = null, + allowSendingWithoutReply: Boolean? = null, + replyMarkup: KeyboardMarkup? = null +) = sendPhoto(chat.id, photoSize, text, parseMode, disableNotification, protectContent, replyToMessageId, allowSendingWithoutReply, replyMarkup) + /** * @param replyMarkup Some of [KeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard] or @@ -159,3 +190,33 @@ suspend inline fun TelegramBot.sendPhoto( allowSendingWithoutReply: Boolean? = null, replyMarkup: KeyboardMarkup? = null ) = sendPhoto(chat.id, photo, entities, disableNotification, protectContent, replyToMessageId, allowSendingWithoutReply, replyMarkup) + +/** + * @param replyMarkup Some of [KeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard] or + * [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard] as a builders for that param + */ +suspend inline fun TelegramBot.sendPhoto( + chatId: ChatIdentifier, + photoSize: PhotoSize, + entities: TextSourcesList, + disableNotification: Boolean = false, + protectContent: Boolean = false, + replyToMessageId: MessageIdentifier? = null, + allowSendingWithoutReply: Boolean? = null, + replyMarkup: KeyboardMarkup? = null +) = sendPhoto(chatId, photoSize.fileId, entities, disableNotification, protectContent, replyToMessageId, allowSendingWithoutReply, replyMarkup) + +/** + * @param replyMarkup Some of [KeyboardMarkup]. See [dev.inmo.tgbotapi.extensions.utils.types.buttons.replyKeyboard] or + * [dev.inmo.tgbotapi.extensions.utils.types.buttons.inlineKeyboard] as a builders for that param + */ +suspend inline fun TelegramBot.sendPhoto( + chat: Chat, + photoSize: PhotoSize, + entities: TextSourcesList, + disableNotification: Boolean = false, + protectContent: Boolean = false, + replyToMessageId: MessageIdentifier? = null, + allowSendingWithoutReply: Boolean? = null, + replyMarkup: KeyboardMarkup? = null +) = sendPhoto(chat.id, photoSize, entities, disableNotification, protectContent, replyToMessageId, allowSendingWithoutReply, replyMarkup)