Skip to content

Commit 531b5eb

Browse files
authored
[Feature] premium buttonz (#2933)
1 parent f7f29d5 commit 531b5eb

File tree

12 files changed

+1825
-1718
lines changed

12 files changed

+1825
-1718
lines changed
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
using Discord.Utils;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System;
5+
6+
namespace Discord;
7+
8+
/// <summary>
9+
/// Represents a class used to build Action rows.
10+
/// </summary>
11+
public class ActionRowBuilder
12+
{
13+
/// <summary>
14+
/// The max amount of child components this row can hold.
15+
/// </summary>
16+
public const int MaxChildCount = 5;
17+
18+
/// <summary>
19+
/// Gets or sets the components inside this row.
20+
/// </summary>
21+
/// <exception cref="ArgumentNullException" accessor="set"><see cref="Components"/> cannot be null.</exception>
22+
/// <exception cref="ArgumentException" accessor="set"><see cref="Components"/> count exceeds <see cref="MaxChildCount"/>.</exception>
23+
public List<IMessageComponent> Components
24+
{
25+
get => _components;
26+
set
27+
{
28+
if (value == null)
29+
throw new ArgumentNullException(nameof(value), $"{nameof(Components)} cannot be null.");
30+
31+
_components = value.Count switch
32+
{
33+
0 => throw new ArgumentOutOfRangeException(nameof(value), "There must be at least 1 component in a row."),
34+
> MaxChildCount => throw new ArgumentOutOfRangeException(nameof(value), $"Action row can only contain {MaxChildCount} child components!"),
35+
_ => value
36+
};
37+
}
38+
}
39+
40+
private List<IMessageComponent> _components = new List<IMessageComponent>();
41+
42+
/// <summary>
43+
/// Adds a list of components to the current row.
44+
/// </summary>
45+
/// <param name="components">The list of components to add.</param>
46+
/// <inheritdoc cref="Components"/>
47+
/// <returns>The current builder.</returns>
48+
public ActionRowBuilder WithComponents(List<IMessageComponent> components)
49+
{
50+
Components = components;
51+
return this;
52+
}
53+
54+
/// <summary>
55+
/// Adds a component at the end of the current row.
56+
/// </summary>
57+
/// <param name="component">The component to add.</param>
58+
/// <exception cref="InvalidOperationException">Components count reached <see cref="MaxChildCount"/></exception>
59+
/// <returns>The current builder.</returns>
60+
public ActionRowBuilder AddComponent(IMessageComponent component)
61+
{
62+
if (Components.Count >= MaxChildCount)
63+
throw new InvalidOperationException($"Components count reached {MaxChildCount}");
64+
65+
Components.Add(component);
66+
return this;
67+
}
68+
69+
/// <summary>
70+
/// Adds a <see cref="SelectMenuBuilder"/> to the <see cref="ActionRowBuilder"/>.
71+
/// </summary>
72+
/// <param name="customId">The custom id of the menu.</param>
73+
/// <param name="options">The options of the menu.</param>
74+
/// <param name="placeholder">The placeholder of the menu.</param>
75+
/// <param name="minValues">The min values of the placeholder.</param>
76+
/// <param name="maxValues">The max values of the placeholder.</param>
77+
/// <param name="disabled">Whether or not the menu is disabled.</param>
78+
/// <param name="type">The type of the select menu.</param>
79+
/// <param name="channelTypes">Menus valid channel types (only for <see cref="ComponentType.ChannelSelect"/>)</param>
80+
/// <returns>The current builder.</returns>
81+
public ActionRowBuilder WithSelectMenu(string customId, List<SelectMenuOptionBuilder> options = null,
82+
string placeholder = null, int minValues = 1, int maxValues = 1, bool disabled = false,
83+
ComponentType type = ComponentType.SelectMenu, ChannelType[] channelTypes = null)
84+
{
85+
return WithSelectMenu(new SelectMenuBuilder()
86+
.WithCustomId(customId)
87+
.WithOptions(options)
88+
.WithPlaceholder(placeholder)
89+
.WithMaxValues(maxValues)
90+
.WithMinValues(minValues)
91+
.WithDisabled(disabled)
92+
.WithType(type)
93+
.WithChannelTypes(channelTypes));
94+
}
95+
96+
/// <summary>
97+
/// Adds a <see cref="SelectMenuBuilder"/> to the <see cref="ActionRowBuilder"/>.
98+
/// </summary>
99+
/// <param name="menu">The menu to add.</param>
100+
/// <exception cref="InvalidOperationException">A Select Menu cannot exist in a pre-occupied ActionRow.</exception>
101+
/// <returns>The current builder.</returns>
102+
public ActionRowBuilder WithSelectMenu(SelectMenuBuilder menu)
103+
{
104+
if (menu.Options is not null && menu.Options.Distinct().Count() != menu.Options.Count)
105+
throw new InvalidOperationException("Please make sure that there is no duplicates values.");
106+
107+
var builtMenu = menu.Build();
108+
109+
if (Components.Count != 0)
110+
throw new InvalidOperationException($"A Select Menu cannot exist in a pre-occupied ActionRow.");
111+
112+
AddComponent(builtMenu);
113+
114+
return this;
115+
}
116+
117+
/// <summary>
118+
/// Adds a <see cref="ButtonBuilder"/> with specified parameters to the <see cref="ActionRowBuilder"/>.
119+
/// </summary>
120+
/// <param name="label">The label text for the newly added button.</param>
121+
/// <param name="style">The style of this newly added button.</param>
122+
/// <param name="emote">A <see cref="IEmote"/> to be used with this button.</param>
123+
/// <param name="customId">The custom id of the newly added button.</param>
124+
/// <param name="url">A URL to be used only if the <see cref="ButtonStyle"/> is a Link.</param>
125+
/// <param name="disabled">Whether or not the newly created button is disabled.</param>
126+
/// <returns>The current builder.</returns>
127+
public ActionRowBuilder WithButton(
128+
string label = null,
129+
string customId = null,
130+
ButtonStyle style = ButtonStyle.Primary,
131+
IEmote emote = null,
132+
string url = null,
133+
bool disabled = false)
134+
{
135+
var button = new ButtonBuilder()
136+
.WithLabel(label)
137+
.WithStyle(style)
138+
.WithEmote(emote)
139+
.WithCustomId(customId)
140+
.WithUrl(url)
141+
.WithDisabled(disabled);
142+
143+
return WithButton(button);
144+
}
145+
146+
/// <summary>
147+
/// Adds a <see cref="ButtonBuilder"/> to the <see cref="ActionRowBuilder"/>.
148+
/// </summary>
149+
/// <param name="button">The button to add.</param>
150+
/// <exception cref="InvalidOperationException">Components count reached <see cref="MaxChildCount"/>.</exception>
151+
/// <exception cref="InvalidOperationException">A button cannot be added to a row with a SelectMenu.</exception>
152+
/// <returns>The current builder.</returns>
153+
public ActionRowBuilder WithButton(ButtonBuilder button)
154+
{
155+
var builtButton = button.Build();
156+
157+
if (Components.Count >= 5)
158+
throw new InvalidOperationException($"Components count reached {MaxChildCount}");
159+
160+
if (Components.Any(x => x.Type.IsSelectType()))
161+
throw new InvalidOperationException($"A button cannot be added to a row with a SelectMenu");
162+
163+
AddComponent(builtButton);
164+
165+
return this;
166+
}
167+
168+
/// <summary>
169+
/// Builds the current builder to a <see cref="ActionRowComponent"/> that can be used within a <see cref="ComponentBuilder"/>
170+
/// </summary>
171+
/// <returns>A <see cref="ActionRowComponent"/> that can be used within a <see cref="ComponentBuilder"/></returns>
172+
public ActionRowComponent Build()
173+
{
174+
return new ActionRowComponent(_components);
175+
}
176+
177+
internal bool CanTakeComponent(IMessageComponent component)
178+
{
179+
switch (component.Type)
180+
{
181+
case ComponentType.ActionRow:
182+
return false;
183+
case ComponentType.Button:
184+
if (Components.Any(x => x.Type.IsSelectType()))
185+
return false;
186+
else
187+
return Components.Count < 5;
188+
case ComponentType.SelectMenu:
189+
case ComponentType.ChannelSelect:
190+
case ComponentType.MentionableSelect:
191+
case ComponentType.RoleSelect:
192+
case ComponentType.UserSelect:
193+
return Components.Count == 0;
194+
default:
195+
return false;
196+
}
197+
}
198+
}

0 commit comments

Comments
 (0)