Skip to content

Commit 800a234

Browse files
authored
[CV2] QoL & fixes (#3153)
1 parent c343ce9 commit 800a234

File tree

6 files changed

+226
-33
lines changed

6 files changed

+226
-33
lines changed

src/Discord.Net.Core/Entities/Interactions/MessageComponents/Builders/ActionRowBuilder.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
using System;
44
using System.Collections.Generic;
5+
using System.Collections.Immutable;
56
using System.Diagnostics;
67
using System.Linq;
78

@@ -13,6 +14,18 @@ namespace Discord;
1314
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
1415
public class ActionRowBuilder : IMessageComponentBuilder, IInteractableComponentContainer
1516
{
17+
/// <inheritdoc />
18+
public ImmutableArray<ComponentType> SupportedComponentTypes { get; } =
19+
[
20+
ComponentType.Button,
21+
ComponentType.SelectMenu,
22+
ComponentType.UserSelect,
23+
ComponentType.RoleSelect,
24+
ComponentType.ChannelSelect,
25+
ComponentType.MentionableSelect,
26+
ComponentType.TextInput
27+
];
28+
1629
/// <inheritdoc />
1730
public ComponentType Type => ComponentType.ActionRow;
1831

@@ -207,7 +220,10 @@ public ActionRowComponent Build()
207220
{
208221
Preconditions.AtLeast(Components.Count, 1, nameof(Components), "There must be at least 1 component in a row.");
209222
Preconditions.AtMost(Components.Count, MaxChildCount, nameof(Components), $"Action row can only contain {MaxChildCount} child components!");
210-
223+
224+
if (Components.Any(x => !SupportedComponentTypes.Contains(x.Type)))
225+
throw new InvalidOperationException($"This component container only supports components of types: {string.Join(", ", SupportedComponentTypes)}");
226+
211227
return new ActionRowComponent(_components.Select(x => x.Build()).ToList(), Id);
212228
}
213229
IMessageComponent IMessageComponentBuilder.Build() => Build();
@@ -242,6 +258,8 @@ internal bool CanTakeComponent(IMessageComponentBuilder component)
242258

243259
/// <inheritdoc />
244260
IComponentContainer IComponentContainer.WithComponents(IEnumerable<IMessageComponentBuilder> components) => WithComponents(components);
261+
/// <inheritdoc />
262+
int IComponentContainer.MaxChildCount => MaxChildCount;
245263

246264
private string DebuggerDisplay => $"{nameof(ActionRowBuilder)}: {this.ComponentCount()} child components.";
247265
}

src/Discord.Net.Core/Entities/Interactions/MessageComponents/Builders/ComponentBuilderV2.cs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Collections.Immutable;
34
using System.Diagnostics;
45
using System.Linq;
56

@@ -9,10 +10,22 @@ namespace Discord;
910
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
1011
public class ComponentBuilderV2 : IStaticComponentContainer
1112
{
13+
/// <inheritdoc />
14+
public ImmutableArray<ComponentType> SupportedComponentTypes { get; } =
15+
[
16+
ComponentType.ActionRow,
17+
ComponentType.Section,
18+
ComponentType.MediaGallery,
19+
ComponentType.Separator,
20+
ComponentType.Container,
21+
ComponentType.File,
22+
ComponentType.TextDisplay
23+
];
24+
1225
/// <summary>
1326
/// Gets the maximum number of components that can be added to a message.
1427
/// </summary>
15-
public const int MaxComponents = 40;
28+
public const int MaxChildCount = 40;
1629

1730
private List<IMessageComponentBuilder> _components = new();
1831

@@ -74,21 +87,14 @@ public MessageComponent Build()
7487
{
7588
Preconditions.NotNull(Components, nameof(Components));
7689
Preconditions.AtLeast(Components.Count, 1, nameof(Components.Count), "At least 1 component must be added to this container.");
77-
Preconditions.AtMost(this.ComponentCount(), MaxComponents, nameof(Components.Count), $"A message must contain {MaxComponents} components or less.");
90+
Preconditions.AtMost(this.ComponentCount(), MaxChildCount, nameof(Components.Count), $"A message must contain {MaxChildCount} components or less.");
7891

7992
var ids = this.GetComponentIds().ToList();
8093
if (ids.Count != ids.Distinct().Count())
8194
throw new InvalidOperationException("Components must have unique ids.");
8295

83-
if (_components.Any(x =>
84-
x is not ActionRowBuilder
85-
and not SectionBuilder
86-
and not TextDisplayBuilder
87-
and not MediaGalleryBuilder
88-
and not FileComponentBuilder
89-
and not SeparatorBuilder
90-
and not ContainerBuilder))
91-
throw new InvalidOperationException($"Only the following components can be at the top level: {nameof(ActionRowBuilder)}, {nameof(TextDisplayBuilder)}, {nameof(SectionBuilder)}, {nameof(MediaGalleryBuilder)}, {nameof(SeparatorBuilder)}, or {nameof(FileComponentBuilder)} components.");
96+
if (Components.Any(x => !SupportedComponentTypes.Contains(x.Type)))
97+
throw new InvalidOperationException($"This component container only supports components of types: {string.Join(", ", SupportedComponentTypes)}");
9298

9399
return new MessageComponent(Components.Select(x => x.Build()).ToList());
94100
}
@@ -101,6 +107,8 @@ and not SeparatorBuilder
101107

102108
/// <inheritdoc/>
103109
IComponentContainer IComponentContainer.WithComponents(IEnumerable<IMessageComponentBuilder> components) => WithComponents(components);
110+
/// <inheritdoc/>
111+
int IComponentContainer.MaxChildCount => MaxChildCount;
104112

105113
private string DebuggerDisplay => $"{nameof(ComponentBuilderV2)}: {this.ComponentCount()} child components.";
106114
}

src/Discord.Net.Core/Entities/Interactions/MessageComponents/Builders/ComponentContainerExtensions.cs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Collections.Generic;
23
using System.Linq;
34

@@ -52,6 +53,21 @@ public static BuilderT WithTextDisplay<BuilderT>(this BuilderT container,
5253
.WithContent(content)
5354
.WithId(id));
5455

56+
/// <summary>
57+
/// Adds a <see cref="TextDisplayBuilder"/> to the container.
58+
/// </summary>
59+
/// <returns>
60+
/// The current container.
61+
/// </returns>
62+
public static BuilderT WithTextDisplay<BuilderT>(this BuilderT container,
63+
Action<TextDisplayBuilder> options)
64+
where BuilderT : class, IStaticComponentContainer
65+
{
66+
var comp = new TextDisplayBuilder();
67+
options(comp);
68+
return container.WithTextDisplay(comp);
69+
}
70+
5571
/// <summary>
5672
/// Adds a <see cref="SectionBuilder"/> to the container.
5773
/// </summary>
@@ -65,6 +81,21 @@ public static BuilderT WithSection<BuilderT>(this BuilderT container, SectionBui
6581
return container;
6682
}
6783

84+
/// <summary>
85+
/// Adds a <see cref="SectionBuilder"/> to the container.
86+
/// </summary>
87+
/// <returns>
88+
/// The current container.
89+
/// </returns>
90+
public static BuilderT WithSection<BuilderT>(this BuilderT container,
91+
Action<SectionBuilder> options)
92+
where BuilderT : class, IStaticComponentContainer
93+
{
94+
var comp = new SectionBuilder();
95+
options(comp);
96+
return container.WithSection(comp);
97+
}
98+
6899
/// <summary>
69100
/// Adds a <see cref="SectionBuilder"/> to the container.
70101
/// </summary>
@@ -122,6 +153,21 @@ public static BuilderT WithMediaGallery<BuilderT>(this BuilderT container,
122153
.WithItems(urls.Select(x => new MediaGalleryItemProperties(new UnfurledMediaItemProperties(x))))
123154
.WithId(id));
124155

156+
/// <summary>
157+
/// Adds a <see cref="MediaGalleryBuilder"/> to the container.
158+
/// </summary>
159+
/// <returns>
160+
/// The current container.
161+
/// </returns>
162+
public static BuilderT WithMediaGallery<BuilderT>(this BuilderT container,
163+
Action<MediaGalleryBuilder> options)
164+
where BuilderT : class, IStaticComponentContainer
165+
{
166+
var comp = new MediaGalleryBuilder();
167+
options(comp);
168+
return container.WithMediaGallery(comp);
169+
}
170+
125171
/// <summary>
126172
/// Adds a <see cref="SeparatorBuilder"/> to the container.
127173
/// </summary>
@@ -151,6 +197,21 @@ public static BuilderT WithSeparator<BuilderT>(this BuilderT container,
151197
.WithIsDivider(isDivider)
152198
.WithId(id));
153199

200+
/// <summary>
201+
/// Adds a <see cref="SeparatorBuilder"/> to the container.
202+
/// </summary>
203+
/// <returns>
204+
/// The current container.
205+
/// </returns>
206+
public static BuilderT WithSeparator<BuilderT>(this BuilderT container,
207+
Action<SeparatorBuilder> options)
208+
where BuilderT : class, IStaticComponentContainer
209+
{
210+
var comp = new SeparatorBuilder();
211+
options(comp);
212+
return container.WithSeparator(comp);
213+
}
214+
154215
/// <summary>
155216
/// Adds a <see cref="FileComponentBuilder"/> to the container.
156217
/// </summary>
@@ -180,6 +241,21 @@ public static BuilderT WithFile<BuilderT>(this BuilderT container,
180241
.WithIsSpoiler(isSpoiler)
181242
.WithId(id));
182243

244+
/// <summary>
245+
/// Adds a <see cref="FileComponentBuilder"/> to the container.
246+
/// </summary>
247+
/// <returns>
248+
/// The current container.
249+
/// </returns>
250+
public static BuilderT WithFile<BuilderT>(this BuilderT container,
251+
Action<FileComponentBuilder> options)
252+
where BuilderT : class, IStaticComponentContainer
253+
{
254+
var comp = new FileComponentBuilder();
255+
options(comp);
256+
return container.WithFile(comp);
257+
}
258+
183259
/// <summary>
184260
/// Adds a <see cref="ContainerBuilder"/> to the container.
185261
/// </summary>
@@ -223,6 +299,21 @@ public static BuilderT WithContainer<BuilderT>(this BuilderT container,
223299
=> container.WithContainer(new ContainerBuilder()
224300
.WithComponents(components));
225301

302+
/// <summary>
303+
/// Adds a <see cref="ContainerBuilder"/> to the container.
304+
/// </summary>
305+
/// <returns>
306+
/// The current container.
307+
/// </returns>
308+
public static BuilderT WithContainer<BuilderT>(this BuilderT container,
309+
Action<ContainerBuilder> options)
310+
where BuilderT : class, IStaticComponentContainer
311+
{
312+
var comp = new ContainerBuilder();
313+
options(comp);
314+
return container.WithContainer(comp);
315+
}
316+
226317
/// <summary>
227318
/// Adds a <see cref="ButtonBuilder"/> to the container.
228319
/// </summary>
@@ -262,6 +353,21 @@ public static BuilderT WithButton<BuilderT>(this BuilderT container,
262353
.WithSkuId(skuId)
263354
.WithId(id));
264355

356+
/// <summary>
357+
/// Adds a <see cref="ButtonBuilder"/> to the container.
358+
/// </summary>
359+
/// <returns>
360+
/// The current container.
361+
/// </returns>
362+
public static BuilderT WithButton<BuilderT>(this BuilderT container,
363+
Action<ButtonBuilder> options)
364+
where BuilderT : class, IInteractableComponentContainer
365+
{
366+
var comp = new ButtonBuilder();
367+
options(comp);
368+
return container.WithButton(comp);
369+
}
370+
265371
/// <summary>
266372
/// Adds a <see cref="SelectMenuBuilder"/> to the container.
267373
/// </summary>
@@ -306,6 +412,21 @@ public static BuilderT WithSelectMenu<BuilderT>(this BuilderT container,
306412
.WithDefaultValues(defaultValues)
307413
.WithId(id));
308414

415+
/// <summary>
416+
/// Adds a <see cref="ButtonBuilder"/> to the container.
417+
/// </summary>
418+
/// <returns>
419+
/// The current container.
420+
/// </returns>
421+
public static BuilderT WithSelectMenu<BuilderT>(this BuilderT container,
422+
Action<SelectMenuBuilder> options)
423+
where BuilderT : class, IInteractableComponentContainer
424+
{
425+
var comp = new SelectMenuBuilder();
426+
options(comp);
427+
return container.WithSelectMenu(comp);
428+
}
429+
309430
/// <summary>
310431
/// Adds a <see cref="ActionRowBuilder"/> to the container.
311432
/// </summary>
@@ -333,6 +454,21 @@ public static BuilderT WithActionRow<BuilderT>(this BuilderT container,
333454
.WithComponents(components)
334455
.WithId(id));
335456

457+
/// <summary>
458+
/// Adds a <see cref="SectionBuilder"/> to the container.
459+
/// </summary>
460+
/// <returns>
461+
/// The current container.
462+
/// </returns>
463+
public static BuilderT WithActionRow<BuilderT>(this BuilderT container,
464+
Action<ActionRowBuilder> options)
465+
where BuilderT : class, IStaticComponentContainer
466+
{
467+
var cont = new ActionRowBuilder();
468+
options(cont);
469+
return container.WithActionRow(cont);
470+
}
471+
336472
/// <summary>
337473
/// Finds the first <see cref="IMessageComponentBuilder"/> in the <see cref="IComponentContainer"/>
338474
/// or any of its child <see cref="IComponentContainer"/>s with matching id.

src/Discord.Net.Core/Entities/Interactions/MessageComponents/Builders/ContainerBuilder.cs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,25 @@ namespace Discord;
99
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
1010
public class ContainerBuilder : IMessageComponentBuilder, IStaticComponentContainer
1111
{
12+
/// <inheritdoc />
13+
public ImmutableArray<ComponentType> SupportedComponentTypes { get; } =
14+
[
15+
ComponentType.ActionRow,
16+
ComponentType.Section,
17+
ComponentType.Button,
18+
ComponentType.MediaGallery,
19+
ComponentType.Separator,
20+
ComponentType.File,
21+
ComponentType.SelectMenu,
22+
ComponentType.TextDisplay
23+
];
24+
1225
/// <inheritdoc />
1326
public ComponentType Type => ComponentType.Container;
1427

28+
/// <inheritdoc cref="IComponentContainer.MaxChildCount"/>
29+
public const int MaxChildCount = 39;
30+
1531
/// <inheritdoc />
1632
public int? Id { get; set; }
1733

@@ -46,7 +62,7 @@ public ContainerBuilder(params IEnumerable<IMessageComponentBuilder> components)
4662
{
4763
Components = components?.ToList();
4864
}
49-
65+
5066
/// <summary>
5167
/// Initializes a new <see cref="ContainerBuilder"/> from existing component.
5268
/// </summary>
@@ -107,14 +123,11 @@ public ContainerBuilder WithComponents(IEnumerable<IMessageComponentBuilder> com
107123
/// <inheritdoc cref="IMessageComponentBuilder.Build"/>
108124
public ContainerComponent Build()
109125
{
110-
if (_components.Any(x => x
111-
is not ActionRowBuilder
112-
and not TextDisplayBuilder
113-
and not SectionBuilder
114-
and not MediaGalleryBuilder
115-
and not SeparatorBuilder
116-
and not FileComponentBuilder))
117-
throw new InvalidOperationException($"A container can only contain {nameof(ActionRowBuilder)}, {nameof(TextDisplayBuilder)}, {nameof(SectionBuilder)}, {nameof(MediaGalleryBuilder)}, {nameof(SeparatorBuilder)}, or {nameof(FileComponentBuilder)} components.");
126+
Preconditions.NotNull(Components, nameof(Components));
127+
Preconditions.AtLeast(Components.Count, 1, nameof(Components.Count), "At least 1 component must be added to this container.");
128+
129+
if (Components.Any(x => !SupportedComponentTypes.Contains(x.Type)))
130+
throw new InvalidOperationException($"This component container only supports components of types: {string.Join(", ", SupportedComponentTypes)}");
118131

119132
return new(Components.ConvertAll(x => x.Build()).ToImmutableArray(), AccentColor, IsSpoiler, Id);
120133
}
@@ -127,6 +140,8 @@ and not SeparatorBuilder
127140
IComponentContainer IComponentContainer.AddComponents(params IMessageComponentBuilder[] components) => AddComponents(components);
128141
/// <inheritdoc />
129142
IComponentContainer IComponentContainer.WithComponents(IEnumerable<IMessageComponentBuilder> components) => WithComponents(components);
143+
/// <inheritdoc/>
144+
int IComponentContainer.MaxChildCount => MaxChildCount;
130145

131146
private string DebuggerDisplay => $"{nameof(ContainerBuilder)}: {this.ComponentCount()} child components.";
132147
}

0 commit comments

Comments
 (0)