Skip to content

Commit ef075ba

Browse files
committed
Added (Inline)KeyboardButton constructors for all button types
because the With* helpers don't allow to set additional properties like Style & IconCustomEmojiId
1 parent 3fa4839 commit ef075ba

7 files changed

Lines changed: 125 additions & 15 deletions

File tree

.github/workflows/dev.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,12 @@ jobs:
3030
COMMITS=${DESCR_TAG#*-}
3131
COMMITS=${COMMITS%-*}
3232
LAST_TAG=${DESCR_TAG%%-*}
33-
NEXT_VERSION=${LAST_TAG%.*}.$((${LAST_TAG##*.} + 1))-dev.$COMMITS
33+
if [[ $LAST_TAG =~ \.[0-9]+\.[0-9]+\. ]]; then # 4-numbers version
34+
COMMITS=$((COMMITS + ${LAST_TAG##*.})); LAST_TAG="${LAST_TAG%.*}";
35+
NEXT_VERSION=$LAST_TAG-dev.$COMMITS
36+
else
37+
NEXT_VERSION=${LAST_TAG%.*}.$((${LAST_TAG##*.} + 1))-dev.$COMMITS
38+
fi
3439
RELEASE_VERSION=${{vars.RELEASE_VERSION}}-dev.$COMMITS
3540
if [[ "$RELEASE_VERSION" > "$NEXT_VERSION" ]] then VERSION=$RELEASE_VERSION; else VERSION=$NEXT_VERSION; fi
3641
echo Last tag: $LAST_TAG · Next version: $NEXT_VERSION · Release version: $RELEASE_VERSION · Build version: $VERSION

.github/workflows/release.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ jobs:
3636
DESCR_TAG=$(git describe --tags --long)
3737
DESCR_TAG=${DESCR_TAG#v}
3838
LAST_TAG=${DESCR_TAG%%-*}
39+
if [[ $LAST_TAG =~ \.[0-9]+\.[0-9]+\. ]]; then LAST_TAG="${LAST_TAG%.*}"; fi
3940
NEXT_VERSION=${LAST_TAG%.*}.$((${LAST_TAG##*.} + 1))
4041
RELEASE_VERSION=${{vars.RELEASE_VERSION}}
4142
if [[ "$RELEASE_VERSION" > "$NEXT_VERSION" ]] then VERSION=$RELEASE_VERSION; else VERSION=$NEXT_VERSION; fi

src/Telegram.Bot/Extend.Types.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,29 @@ public InlineKeyboardButton(string text, string callbackDataOrUrl)
452452
CallbackData = callbackDataOrUrl;
453453
}
454454

455+
/// <summary>Generate an inline keyboard button of the given type</summary>
456+
/// <param name="text">Button's text</param>
457+
/// <param name="type">Type of the button to be created. (there are other types with specific constructors)</param>
458+
/// <param name="value">Url, Data or Text to be associated with the button. Meaning depends on the button <paramref name="type"/></param>
459+
[SetsRequiredMembers]
460+
public InlineKeyboardButton(string text, InlineButtonType type, string value = "")
461+
{
462+
Text = text;
463+
switch (type)
464+
{
465+
case InlineButtonType.Url: Url = value; break;
466+
case InlineButtonType.Callback: CallbackData = value; break;
467+
case InlineButtonType.WebApp: WebApp = value; break;
468+
case InlineButtonType.LoginUrl: LoginUrl = new LoginUrl { Url = value }; break;
469+
case InlineButtonType.SwitchInlineQuery: SwitchInlineQuery = value; break;
470+
case InlineButtonType.SwitchInlineQueryCurrentChat: SwitchInlineQueryCurrentChat = value; break;
471+
case InlineButtonType.CopyText: CopyText = value; break;
472+
case InlineButtonType.Game: CallbackGame = new(); break;
473+
case InlineButtonType.Pay: Pay = true; break;
474+
default: throw new NotSupportedException("Unrecognized type of inline button");
475+
}
476+
}
477+
455478
/// <summary>Performs an implicit conversion from <see cref="string"/> to <see cref="InlineKeyboardButton"/></summary>
456479
/// <param name="textAndCallbackDataOrUrl">Text serving as the label of the button, as well as the URL to be opened or the callback data to be sent</param>
457480
/// <returns>The result of the conversion.</returns>
@@ -472,6 +495,18 @@ public static InlineKeyboardButton WithCallbackData(string textAndCallbackData)
472495

473496
public partial class KeyboardButton
474497
{
498+
/// <summary>Generate a keyboard button from text, with one optional request</summary>
499+
/// <param name="text">Button's text</param>
500+
/// <param name="requestContact">Pass <see langword="true"/> to request the user's phone number, which will be sent as a contact when the button is pressed. Available in private chats only</param>
501+
/// <param name="requestLocation">Pass <see langword="true"/> to request the user's current location, which will be sent as a location message when the button is pressed. Available in private chats only</param>
502+
[SetsRequiredMembers]
503+
public KeyboardButton(string text, bool requestContact = false, bool requestLocation = false)
504+
{
505+
Text = text;
506+
RequestContact = requestContact;
507+
RequestLocation = requestLocation;
508+
}
509+
475510
/// <summary>Generate a keyboard button from text</summary>
476511
/// <param name="text">Button's text</param>
477512
public static implicit operator KeyboardButton(string text)

src/Telegram.Bot/TelegramBotClient.cs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -136,23 +136,20 @@ public virtual async Task<TResponse> SendRequest<TResponse>(IRequest<TResponse>
136136
await OnApiResponseReceived.Invoke(this, responseEventArgs, cancellationToken).ConfigureAwait(false);
137137
}
138138

139-
if (httpResponse.StatusCode != HttpStatusCode.OK)
139+
if (httpResponse.StatusCode == HttpStatusCode.OK)
140140
{
141-
var failedApiResponse = await DeserializeContent<ApiResponse>(httpResponse,
142-
response => response.ErrorCode != default && response.Description != null, cancellationToken).ConfigureAwait(false);
143-
144-
if (failedApiResponse.ErrorCode == 429 && _options.RetryThreshold > 0 && attempt < _options.RetryCount &&
145-
failedApiResponse.Parameters?.RetryAfter <= _options.RetryThreshold)
146-
{
147-
await Task.Delay(failedApiResponse.Parameters.RetryAfter.Value * 1000, cancellationToken).ConfigureAwait(false);
148-
continue; // retry attempt
149-
}
150-
throw ExceptionsParser.Parse(failedApiResponse);
141+
var apiResponse = await DeserializeContent<ApiResponse<TResponse>>(httpResponse,
142+
response => response.Ok && response.Result != null, cancellationToken).ConfigureAwait(false);
143+
return apiResponse.Result!;
151144
}
152145

153-
var apiResponse = await DeserializeContent<ApiResponse<TResponse>>(httpResponse,
154-
response => response.Ok && response.Result != null, cancellationToken).ConfigureAwait(false);
155-
return apiResponse.Result!;
146+
var failedApiResponse = await DeserializeContent<ApiResponse>(httpResponse,
147+
response => response.ErrorCode != default && response.Description != null, cancellationToken).ConfigureAwait(false);
148+
if (failedApiResponse.ErrorCode != 429 || _options.RetryThreshold <= 0 || attempt >= _options.RetryCount ||
149+
!(failedApiResponse.Parameters?.RetryAfter <= _options.RetryThreshold))
150+
throw ExceptionsParser.Parse(failedApiResponse);
151+
// 429 Too Many Requests => Retry After N seconds
152+
await Task.Delay(failedApiResponse.Parameters.RetryAfter.Value * 1000, cancellationToken).ConfigureAwait(false);
156153
}
157154
}
158155
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
namespace Telegram.Bot.Types.ReplyMarkups;
2+
3+
/// <summary>The enum is for use with <see cref="KeyboardButton"/> or <see cref="InlineKeyboardButton"/> constructors</summary>
4+
public enum InlineButtonType
5+
{
6+
/// <summary><c>value</c> = HTTP or tg:// URL to be opened when the button is pressed. Links <c>tg://user?id=&lt;UserId&gt;</c> can be used to mention a user by their identifier without using a username, if this is allowed by their privacy settings.</summary>
7+
Url,
8+
/// <summary><c>value</c> = Data to be sent in a <see cref="CallbackQuery">callback query</see> to the bot when the button is pressed, 1-64 bytes</summary>
9+
Callback,
10+
/// <summary><c>value</c> = An HTTPS URL of the <a href="https://core.telegram.org/bots/webapps">Web App</a> that will be launched when the user presses the button. The Web App will be able to send an arbitrary message on behalf of the user using the method <see cref="TelegramBotClientExtensions.AnswerWebAppQuery">AnswerWebAppQuery</see>. Available only in private chats between a user and the bot. Not supported for messages sent on behalf of a Telegram Business account.</summary>
11+
WebApp,
12+
/// <summary><c>value</c> = An HTTPS URL used to automatically authorize the user. Can be used as a replacement for the <a href="https://core.telegram.org/widgets/login">Telegram Login Widget</a>.</summary>
13+
LoginUrl,
14+
/// <summary>Pressing the button will prompt the user to select one of their chats, open that chat and insert the bot's username and the specified inline query <c>value</c> in the input field.<br/><c>value</c> may be left empty, in which case just the bot's username will be inserted. Not supported for messages sent in channel direct messages chats and on behalf of a Telegram Business account.</summary>
15+
SwitchInlineQuery,
16+
/// <summary>Pressing the button will insert the bot's username and the specified inline query <c>value</c> in the current chat's input field.<br/><c>value</c> may be left empty, in which case only the bot's username will be inserted.<br/><br/>This offers a quick way for the user to open your bot in inline mode in the same chat - good for selecting something from multiple options. Not supported in channels and for messages sent in channel direct messages chats and on behalf of a Telegram Business account.</summary>
17+
SwitchInlineQueryCurrentChat,
18+
/// <summary><c>value</c> = The text to be copied to the clipboard when button is pressed; 1-256 characters</summary>
19+
CopyText,
20+
/// <summary>Launching a game (set in <a href="https://t.me/botfather">@BotFather</a>) when the user presses the button.<br/><br/><b>NOTE:</b> This type of button <b>must</b> always be the first button in the first row.</summary>
21+
Game,
22+
/// <summary><a href="https://core.telegram.org/bots/api#payments">Pay button</a>. Substrings “⭐” and “XTR” in the buttons's text will be replaced with a Telegram Star icon.<br/><br/><b>NOTE:</b> This type of button <b>must</b> always be the first button in the first row and can only be used in invoice messages.</summary>
23+
Pay,
24+
}

src/Telegram.Bot/Types/ReplyMarkups/InlineKeyboardButton.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,24 @@ public static InlineKeyboardButton WithUrl(string text, string url) =>
7373
public static InlineKeyboardButton WithCallbackData(string text, string callbackData) =>
7474
new(text) { CallbackData = callbackData };
7575

76+
/// <summary>Creates an inline keyboard button with description of the <a href="https://core.telegram.org/bots/webapps">Web App</a> that will be launched when the user presses the button. The Web App will be able to send an arbitrary message on behalf of the user using the method <see cref="TelegramBotClientExtensions.AnswerWebAppQuery">AnswerWebAppQuery</see>. Available only in private chats between a user and the bot. Not supported for messages sent on behalf of a Telegram Business account.</summary>
77+
/// <param name="text">Label text on the button</param>
78+
/// <param name="webApp">Description of the <a href="https://core.telegram.org/bots/webapps">Web App</a> that will be launched when the user presses the button. The Web App will be able to send an arbitrary message on behalf of the user using the method <see cref="TelegramBotClientExtensions.AnswerWebAppQuery">AnswerWebAppQuery</see>. Available only in private chats between a user and the bot. Not supported for messages sent on behalf of a Telegram Business account.</param>
79+
[SetsRequiredMembers]
80+
public InlineKeyboardButton(string text, WebAppInfo webApp) { Text = text; WebApp = webApp; }
81+
7682
/// <summary>Creates an inline keyboard button with description of the <a href="https://core.telegram.org/bots/webapps">Web App</a> that will be launched when the user presses the button. The Web App will be able to send an arbitrary message on behalf of the user using the method <see cref="TelegramBotClientExtensions.AnswerWebAppQuery">AnswerWebAppQuery</see>. Available only in private chats between a user and the bot. Not supported for messages sent on behalf of a Telegram Business account.</summary>
7783
/// <param name="text">Label text on the button</param>
7884
/// <param name="webApp">Description of the <a href="https://core.telegram.org/bots/webapps">Web App</a> that will be launched when the user presses the button. The Web App will be able to send an arbitrary message on behalf of the user using the method <see cref="TelegramBotClientExtensions.AnswerWebAppQuery">AnswerWebAppQuery</see>. Available only in private chats between a user and the bot. Not supported for messages sent on behalf of a Telegram Business account.</param>
7985
public static InlineKeyboardButton WithWebApp(string text, WebAppInfo webApp) =>
8086
new(text) { WebApp = webApp };
8187

88+
/// <summary>Creates an inline keyboard button with an HTTPS URL used to automatically authorize the user. Can be used as a replacement for the <a href="https://core.telegram.org/widgets/login">Telegram Login Widget</a>.</summary>
89+
/// <param name="text">Label text on the button</param>
90+
/// <param name="loginUrl">An HTTPS URL used to automatically authorize the user. Can be used as a replacement for the <a href="https://core.telegram.org/widgets/login">Telegram Login Widget</a>.</param>
91+
[SetsRequiredMembers]
92+
public InlineKeyboardButton(string text, LoginUrl loginUrl) { Text = text; LoginUrl = loginUrl; }
93+
8294
/// <summary>Creates an inline keyboard button with an HTTPS URL used to automatically authorize the user. Can be used as a replacement for the <a href="https://core.telegram.org/widgets/login">Telegram Login Widget</a>.</summary>
8395
/// <param name="text">Label text on the button</param>
8496
/// <param name="loginUrl">An HTTPS URL used to automatically authorize the user. Can be used as a replacement for the <a href="https://core.telegram.org/widgets/login">Telegram Login Widget</a>.</param>
@@ -97,12 +109,24 @@ public static InlineKeyboardButton WithSwitchInlineQuery(string text, string swi
97109
public static InlineKeyboardButton WithSwitchInlineQueryCurrentChat(string text, string switchInlineQueryCurrentChat = "") =>
98110
new(text) { SwitchInlineQueryCurrentChat = switchInlineQueryCurrentChat };
99111

112+
/// <summary>Creates an inline keyboard button. Pressing the button will prompt the user to select one of their chats of the specified type, open that chat and insert the bot's username and the specified inline query in the input field. Not supported for messages sent in channel direct messages chats and on behalf of a Telegram Business account.</summary>
113+
/// <param name="text">Label text on the button</param>
114+
/// <param name="switchInlineQueryChosenChat">If set, pressing the button will prompt the user to select one of their chats of the specified type, open that chat and insert the bot's username and the specified inline query in the input field. Not supported for messages sent in channel direct messages chats and on behalf of a Telegram Business account.</param>
115+
[SetsRequiredMembers]
116+
public InlineKeyboardButton(string text, SwitchInlineQueryChosenChat switchInlineQueryChosenChat) { Text = text; SwitchInlineQueryChosenChat = switchInlineQueryChosenChat; }
117+
100118
/// <summary>Creates an inline keyboard button. Pressing the button will prompt the user to select one of their chats of the specified type, open that chat and insert the bot's username and the specified inline query in the input field. Not supported for messages sent in channel direct messages chats and on behalf of a Telegram Business account.</summary>
101119
/// <param name="text">Label text on the button</param>
102120
/// <param name="switchInlineQueryChosenChat">If set, pressing the button will prompt the user to select one of their chats of the specified type, open that chat and insert the bot's username and the specified inline query in the input field. Not supported for messages sent in channel direct messages chats and on behalf of a Telegram Business account.</param>
103121
public static InlineKeyboardButton WithSwitchInlineQueryChosenChat(string text, SwitchInlineQueryChosenChat switchInlineQueryChosenChat) =>
104122
new(text) { SwitchInlineQueryChosenChat = switchInlineQueryChosenChat };
105123

124+
/// <summary>Creates an inline keyboard button with description of the button that copies the specified text to the clipboard.</summary>
125+
/// <param name="text">Label text on the button</param>
126+
/// <param name="copyText">Description of the button that copies the specified text to the clipboard.</param>
127+
[SetsRequiredMembers]
128+
public InlineKeyboardButton(string text, CopyTextButton copyText) { Text = text; CopyText = copyText; }
129+
106130
/// <summary>Creates an inline keyboard button with description of the button that copies the specified text to the clipboard.</summary>
107131
/// <param name="text">Label text on the button</param>
108132
/// <param name="copyText">Description of the button that copies the specified text to the clipboard.</param>

0 commit comments

Comments
 (0)