diff --git a/CHANGELOG.md b/CHANGELOG.md
index 74bbc70..eab6a36 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+# 1.25.0
+
+- 🤖 Bot API 7.10
+- Added `Bot.onPaidMediaPurchase` for listening to [PaidMediaPurchased](https://core.telegram.org/bots/api#paidmediapurchased) updates.
+- Added much more helper methods on `Context`
+
# 1.24.0
- 🤖 Bot API 7.9
diff --git a/README.md b/README.md
index 1e429a4..5d32bd0 100644
--- a/README.md
+++ b/README.md
@@ -3,17 +3,16 @@
[![Pub Version](https://img.shields.io/pub/v/televerse?color=blue&logo=blue)](https://pub.dev/packages/televerse)
![GitHub](https://img.shields.io/github/license/xooniverse/televerse?color=green)
-![](https://shields.io/badge/Latest-Bot%20API%207.9-blue)
+![](https://shields.io/badge/Latest-Bot%20API%207.10-blue)
-
+
-
---
-🤖 `Bot API version: Bot API 7.9 (August 14, 2024)`
+🤖 `Bot API version: Bot API 7.10 (September 6, 2024)`
Televerse is a powerful, easy-to-use, and highly customizable Telegram bot
framework built with Dart programming language. It provides a complete and
@@ -23,13 +22,13 @@ public interface, making it easy for developers to write strictly typed code.
## 🔥 What's latest?
-### 🤖 Bot API 7.9
+### 🤖 Bot API 7.10
-(🗓️ August 14, 2024)
+(🗓️ September 6, 2024)
-In a nutshell, this update brigngs support for channel subscription, and support for Paid Media across all chats.
+In a nutshell, this update brigngs support for Telegram Star giveaway, new Update type for paid media purchases.
-Checkout [changelog](https://core.telegram.org/bots/api-changelog#august-14-2024) for more
+Checkout [changelog](https://core.telegram.org/bots/api-changelog#september-6-2024) for more
details! 🚀
### 🎉 Support for Custom Contexts!
diff --git a/lib/src/telegram/models/birthdate.dart b/lib/src/telegram/models/birthdate.dart
index 7fcb761..ef66747 100644
--- a/lib/src/telegram/models/birthdate.dart
+++ b/lib/src/telegram/models/birthdate.dart
@@ -33,6 +33,6 @@ class Birthdate {
'day': day,
'month': month,
'year': year,
- };
+ }..removeWhere(_nullFilter);
}
}
diff --git a/lib/src/telegram/models/chat_boost_source_giveaway.dart b/lib/src/telegram/models/chat_boost_source_giveaway.dart
index d84cc27..ad0968d 100644
--- a/lib/src/telegram/models/chat_boost_source_giveaway.dart
+++ b/lib/src/telegram/models/chat_boost_source_giveaway.dart
@@ -15,11 +15,15 @@ class ChatBoostSourceGiveaway implements ChatBoostSource {
/// Optional. True, if the giveaway was completed, but there was no user to win the prize
final bool? isUnclaimed;
+ /// Optional. The number of Telegram Stars to be split between giveaway winners; for Telegram Star giveaways only
+ final int? prizeStarCount;
+
/// Creates a source of a chat boost.
const ChatBoostSourceGiveaway({
this.user,
this.isUnclaimed,
this.giveawayMessageId = 0,
+ this.prizeStarCount,
});
/// Converts the `ChatBoostSourceGiveaway` object to a JSON object.
@@ -30,6 +34,7 @@ class ChatBoostSourceGiveaway implements ChatBoostSource {
'user': user?.toJson(),
'is_unclaimed': isUnclaimed,
'giveaway_message_id': giveawayMessageId,
+ 'prize_star_count': prizeStarCount,
}..removeWhere(_nullFilter);
}
@@ -39,6 +44,7 @@ class ChatBoostSourceGiveaway implements ChatBoostSource {
user: User.fromJson(json['user']),
isUnclaimed: json['is_unclaimed'],
giveawayMessageId: json['giveaway_message_id'],
+ prizeStarCount: json['prize_star_count'],
);
}
}
diff --git a/lib/src/telegram/models/giveaway.dart b/lib/src/telegram/models/giveaway.dart
index 74e1de5..e59a909 100644
--- a/lib/src/telegram/models/giveaway.dart
+++ b/lib/src/telegram/models/giveaway.dart
@@ -26,6 +26,9 @@ class Giveaway {
/// The number of months the Telegram Premium subscription won from the giveaway will be active for
final int? premiumSubscriptionMonthCount;
+ /// Optional. The number of Telegram Stars to be split between giveaway winners; for Telegram Star giveaways only
+ final int? prizeStarCount;
+
/// Constructor
const Giveaway({
required this.chats,
@@ -36,6 +39,7 @@ class Giveaway {
this.prizeDescription,
this.countryCodes,
this.premiumSubscriptionMonthCount,
+ this.prizeStarCount,
});
/// Constructor from JSON data
@@ -50,6 +54,7 @@ class Giveaway {
prizeDescription: json['prize_description'],
countryCodes: json['country_codes']?.cast(),
premiumSubscriptionMonthCount: json['premium_subscription_month_count'],
+ prizeStarCount: json['prize_star_count'],
);
}
@@ -64,6 +69,7 @@ class Giveaway {
'prize_description': prizeDescription,
'country_codes': countryCodes,
'premium_subscription_month_count': premiumSubscriptionMonthCount,
+ 'prize_star_count': prizeStarCount,
}..removeWhere(_nullFilter);
}
}
diff --git a/lib/src/telegram/models/giveaway_completed.dart b/lib/src/telegram/models/giveaway_completed.dart
index 23e917d..e7b1bd3 100644
--- a/lib/src/telegram/models/giveaway_completed.dart
+++ b/lib/src/telegram/models/giveaway_completed.dart
@@ -11,11 +11,15 @@ class GiveawayCompleted {
/// Message with the giveaway that was completed, if it wasn't deleted
final Message? giveawayMessage;
+ /// Optional. True, if the giveaway is a Telegram Star giveaway. Otherwise, currently, the giveaway is a Telegram Premium giveaway.
+ final bool? isStarGiveaway;
+
/// Constructor
const GiveawayCompleted({
required this.winnerCount,
this.unclaimedPrizeCount,
this.giveawayMessage,
+ this.isStarGiveaway,
});
/// Constructor from JSON data
@@ -26,6 +30,7 @@ class GiveawayCompleted {
giveawayMessage: json['giveaway_message'] != null
? Message.fromJson(json['giveaway_message'])
: null,
+ isStarGiveaway: json['is_star_giveaway'],
);
}
@@ -35,6 +40,7 @@ class GiveawayCompleted {
'winner_count': winnerCount,
'unclaimed_prize_count': unclaimedPrizeCount,
'giveaway_message': giveawayMessage?.toJson(),
+ 'is_star_giveaway': isStarGiveaway,
}..removeWhere(_nullFilter);
}
}
diff --git a/lib/src/telegram/models/giveaway_created.dart b/lib/src/telegram/models/giveaway_created.dart
index 6f2d0f2..6f28de7 100644
--- a/lib/src/telegram/models/giveaway_created.dart
+++ b/lib/src/telegram/models/giveaway_created.dart
@@ -2,16 +2,25 @@ part of 'models.dart';
/// This object represents a service message about the creation of a scheduled giveaway. Currently holds no information.
class GiveawayCreated {
+ /// Optional. The number of Telegram Stars to be split between giveaway winners; for Telegram Star giveaways only
+ final int? prizeStarCount;
+
/// Creates a `GiveawayCreated` object.
- const GiveawayCreated();
+ const GiveawayCreated({
+ this.prizeStarCount,
+ });
/// Creates a `GiveawayCreated` object from a JSON object.
factory GiveawayCreated.fromJson(Map json) {
- return GiveawayCreated();
+ return GiveawayCreated(
+ prizeStarCount: json['prize_star_count'],
+ );
}
/// Converts the `GiveawayCreated` object to a JSON object.
Map toJson() {
- return {};
+ return {
+ 'prize_star_count': prizeStarCount,
+ }..removeWhere(_nullFilter);
}
}
diff --git a/lib/src/telegram/models/giveaway_winners.dart b/lib/src/telegram/models/giveaway_winners.dart
index 27ea357..b2f846a 100644
--- a/lib/src/telegram/models/giveaway_winners.dart
+++ b/lib/src/telegram/models/giveaway_winners.dart
@@ -35,6 +35,9 @@ class GiveawayWinners {
/// Description of additional giveaway prize
final String? prizeDescription;
+ /// Optional. The number of Telegram Stars to be split between giveaway winners; for Telegram Star giveaways only
+ final int? prizeStarCount;
+
/// Constructor
const GiveawayWinners({
required this.chat,
@@ -48,6 +51,7 @@ class GiveawayWinners {
this.onlyNewMembers,
this.wasRefunded,
this.prizeDescription,
+ this.prizeStarCount,
});
/// Constructor from JSON data
@@ -65,6 +69,7 @@ class GiveawayWinners {
onlyNewMembers: json['only_new_members'],
wasRefunded: json['was_refunded'],
prizeDescription: json['prize_description'],
+ prizeStarCount: json['prize_star_count'],
);
}
@@ -82,6 +87,7 @@ class GiveawayWinners {
'only_new_members': onlyNewMembers,
'was_refunded': wasRefunded,
'prize_description': prizeDescription,
+ 'prize_star_count': prizeStarCount,
}..removeWhere(_nullFilter);
}
}
diff --git a/lib/src/telegram/models/models.dart b/lib/src/telegram/models/models.dart
index 19aeb84..42408d0 100644
--- a/lib/src/telegram/models/models.dart
+++ b/lib/src/telegram/models/models.dart
@@ -271,3 +271,6 @@ part 'refunded_payment.dart';
// Bot API 7.9
part 'reaction_type_paid.dart';
+
+// Bot API 7.10
+part 'paid_media_purchased.dart';
diff --git a/lib/src/telegram/models/paid_media_purchased.dart b/lib/src/telegram/models/paid_media_purchased.dart
new file mode 100644
index 0000000..7379cc5
--- /dev/null
+++ b/lib/src/telegram/models/paid_media_purchased.dart
@@ -0,0 +1,37 @@
+part of 'models.dart';
+
+/// Represents a paid media purchase made by a user.
+class PaidMediaPurchased implements WithUser {
+ /// The user who purchased the media.
+ @override
+ final User from;
+
+ /// A bot-specified payload related to the paid media.
+ final String paidMediaPayload;
+
+ /// Creates a [PaidMediaPurchased] object.
+ const PaidMediaPurchased({
+ required this.from,
+ required this.paidMediaPayload,
+ });
+
+ /// Creates a [PaidMediaPurchased] object from a JSON map.
+ ///
+ /// The JSON map should contain `from` and `paid_media_payload` fields.
+ factory PaidMediaPurchased.fromJson(Map json) {
+ return PaidMediaPurchased(
+ from: User.fromJson(json['from']),
+ paidMediaPayload: json['paid_media_payload'],
+ );
+ }
+
+ /// Converts this object to a JSON map.
+ ///
+ /// Returns a map with `from` and `paid_media_payload` fields.
+ Map toJson() {
+ return {
+ 'from': from.toJson(),
+ 'paid_media_payload': paidMediaPayload,
+ };
+ }
+}
diff --git a/lib/src/telegram/models/transaction_partner_user.dart b/lib/src/telegram/models/transaction_partner_user.dart
index fd51dca..5f528c5 100644
--- a/lib/src/telegram/models/transaction_partner_user.dart
+++ b/lib/src/telegram/models/transaction_partner_user.dart
@@ -14,11 +14,15 @@ class TransactionPartnerUser extends TransactionPartner {
/// Optional. Information about the paid media bought by the user
final List? paidMedia;
+ /// Optional. Bot-specified paid media payload
+ final String? paidMediaPayload;
+
/// Constructs a [TransactionPartnerUser] object.
const TransactionPartnerUser({
required this.user,
this.invoicePayload,
this.paidMedia,
+ this.paidMediaPayload,
});
/// Creates a [TransactionPartnerUser] object from JSON.
@@ -33,6 +37,7 @@ class TransactionPartnerUser extends TransactionPartner {
),
)
: null,
+ paidMediaPayload: json['paid_media_payload'],
);
}
@@ -44,6 +49,7 @@ class TransactionPartnerUser extends TransactionPartner {
'user': user.toJson(),
'invoice_payload': invoicePayload,
'paid_media': paidMedia?.map((e) => e.toJson()).toList(),
+ 'paid_media_payload': paidMediaPayload,
}..removeWhere(_nullFilter);
}
}
diff --git a/lib/src/telegram/models/update.dart b/lib/src/telegram/models/update.dart
index 3e6ae9d..1341aab 100644
--- a/lib/src/telegram/models/update.dart
+++ b/lib/src/telegram/models/update.dart
@@ -73,6 +73,9 @@ class Update {
/// Optional. Messages were deleted from a connected business account
final BusinessMessagesDeleted? deletedBusinessMessages;
+ /// Optional. A user purchased paid media with a non-empty payload sent by the bot in a non-channel chat
+ final PaidMediaPurchased? purchasedPaidMedia;
+
/// Update Constructor
const Update({
required this.updateId,
@@ -98,6 +101,7 @@ class Update {
this.businessMessage,
this.editedBusinessMessage,
this.deletedBusinessMessages,
+ this.purchasedPaidMedia,
});
/// Creates a [Update] from json [Map].
@@ -169,6 +173,9 @@ class Update {
deletedBusinessMessages: json['deleted_business_messages'] != null
? BusinessMessagesDeleted.fromJson(json['deleted_business_messages'])
: null,
+ purchasedPaidMedia: json['purchased_paid_media'] != null
+ ? PaidMediaPurchased.fromJson(json['purchased_paid_media'])
+ : null,
);
}
@@ -198,6 +205,7 @@ class Update {
'business_message': businessMessage?.toJson(),
'edited_business_message': editedBusinessMessage?.toJson(),
'deleted_business_messages': deletedBusinessMessages?.toJson(),
+ 'purchased_paid_media': purchasedPaidMedia?.toJson(),
}..removeWhere(_nullFilter);
}
@@ -250,6 +258,8 @@ class Update {
return UpdateType.editedBusinessMessage;
} else if (deletedBusinessMessages != null) {
return UpdateType.deletedBusinessMessages;
+ } else if (purchasedPaidMedia != null) {
+ return UpdateType.purchasedPaidMedia;
} else {
throw TeleverseException(
"The update type is unknown",
diff --git a/lib/src/televerse/api/raw_api.dart b/lib/src/televerse/api/raw_api.dart
index e4f4fe1..2da4595 100644
--- a/lib/src/televerse/api/raw_api.dart
+++ b/lib/src/televerse/api/raw_api.dart
@@ -3984,6 +3984,7 @@ class RawAPI {
ReplyParameters? replyParameters,
ReplyMarkup? replyMarkup,
String? businessConnectionId,
+ String? payload,
}) async {
final params = {
"chat_id": chatId.id,
@@ -3997,6 +3998,7 @@ class RawAPI {
"reply_parameters": replyParameters?.toJson(),
"reply_markup": replyMarkup?.toJson(),
"business_connection_id": businessConnectionId,
+ "payload": payload,
};
List<_MultipartHelper> helpers = [];
diff --git a/lib/src/televerse/bot/bot.dart b/lib/src/televerse/bot/bot.dart
index bb69b13..7b13c17 100644
--- a/lib/src/televerse/bot/bot.dart
+++ b/lib/src/televerse/bot/bot.dart
@@ -2653,4 +2653,14 @@ class Bot {
options: options,
);
}
+
+ /// Registers a callback to be fired when a user purchases paid media sent by the bot
+ void onPaidMediaPurchase(
+ Handler callback,
+ ) {
+ return _acceptAll(
+ callback,
+ [UpdateType.purchasedPaidMedia],
+ );
+ }
}
diff --git a/lib/src/televerse/context/context.dart b/lib/src/televerse/context/context.dart
index 3dc16c7..f0d932e 100644
--- a/lib/src/televerse/context/context.dart
+++ b/lib/src/televerse/context/context.dart
@@ -160,6 +160,72 @@ class Context {
);
}
}
+
+ /// Determine whether the update is a text message
+ bool hasText() => msg?.text != null;
+
+ /// Determine whether the update contains a photo
+ bool hasPhoto() => msg?.photo != null;
+
+ /// Determine whether the update contains a video
+ bool hasVideo() => msg?.video != null;
+
+ /// Determine whether the update contains a document
+ bool hasDocument() => msg?.document != null;
+
+ /// Determine whether the update contains a location
+ bool hasLocation() => msg?.location != null;
+
+ /// Determine whether the update contains a live location
+ bool hasLiveLocation() => msg?.location?.livePeriod != null;
+
+ /// Determine whether the update contains a GIF/Animation
+ bool hasAnimation() => msg?.animation != null;
+
+ /// Determine whether the update is part of media group
+ bool hasMediaGroup() => msg?.mediaGroupId != null;
+
+ /// Determine whether the incoming message has a message effect added to it
+ bool hasEffect() => msg?.hasEffect == true;
+
+ /// Determine whether the update contains a paid media
+ bool hasPaidMedia() => msg?.paidMedia != null;
+
+ /// Determine whether the update contains a contact
+ bool hasContact() => msg?.contact != null;
+
+ /// Determine whether the update is a service message
+ bool isServiceMessage() {
+ return msg?.leftChatMember != null ||
+ msg?.newChatTitle != null ||
+ msg?.newChatPhoto != null ||
+ msg?.deleteChatPhoto == true ||
+ msg?.groupChatCreated == true ||
+ msg?.supergroupChatCreated == true ||
+ msg?.channelChatCreated == true ||
+ msg?.messageAutoDeleteTimerChanged != null ||
+ msg?.successfulPayment != null ||
+ msg?.refundedPayment != null ||
+ msg?.usersShared != null ||
+ msg?.chatShared != null ||
+ msg?.writeAccessAllowed != null ||
+ msg?.proximityAlertTriggered != null ||
+ msg?.boostAdded != null ||
+ msg?.chatBackgroundSet != null ||
+ msg?.forumTopicCreated != null ||
+ msg?.forumTopicEdited != null ||
+ msg?.forumTopicClosed != null ||
+ msg?.forumTopicReopened != null ||
+ msg?.generalForumTopicHidden != null ||
+ msg?.generalForumTopicUnhidden != null ||
+ msg?.giveawayCreated != null ||
+ msg?.giveawayCompleted != null ||
+ msg?.videoChatScheduled != null ||
+ msg?.videoChatStarted != null ||
+ msg?.videoChatEnded != null ||
+ msg?.videoChatParticipantsInvited != null ||
+ msg?.webAppData != null;
+ }
}
/// Base handler
diff --git a/lib/src/types/update_type.dart b/lib/src/types/update_type.dart
index 7b5a7b0..0c82538 100644
--- a/lib/src/types/update_type.dart
+++ b/lib/src/types/update_type.dart
@@ -67,6 +67,9 @@ enum UpdateType {
/// Messages were deleted from a connected business account
deletedBusinessMessages("deleted_business_messages"),
+
+ /// Updates about purchased paid media
+ purchasedPaidMedia("purchased_paid_media"),
;
/// The value of this enum.
diff --git a/lib/src/utils/utils.dart b/lib/src/utils/utils.dart
index 8a657d4..c3822be 100644
--- a/lib/src/utils/utils.dart
+++ b/lib/src/utils/utils.dart
@@ -68,7 +68,8 @@ extension FromAndChatExt on Update {
myChatMember ??
chatMember ??
chatJoinRequest ??
- businessConnection)
+ businessConnection ??
+ purchasedPaidMedia)
?.from;
if (callbackQuery?.message is Message) {
x ??= (callbackQuery?.message as Message).from;
diff --git a/pubspec.yaml b/pubspec.yaml
index e07ba5b..469d429 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
name: televerse
-description: Televerse lets you create your own efficient Telegram bots with ease in Dart. Supports latest Telegram Bot API - 7.9!
-version: 1.24.0
+description: Televerse lets you create your own efficient Telegram bots with ease in Dart. Supports latest Telegram Bot API - 7.10!
+version: 1.25.0
homepage: https://televerse.xooniverse.com
repository: https://github.com/xooniverse/televerse
topics:
@@ -17,7 +17,7 @@ environment:
sdk: ">=3.0.0 <4.0.0"
dependencies:
- dio: ^5.4.0
+ dio: ^5.7.0
dev_dependencies:
lints: ^4.0.0