Skip to content

Commit a59db13

Browse files
committed
move SelectMenuOptionAttribute to its own file
1 parent a49fb5b commit a59db13

File tree

2 files changed

+42
-61
lines changed

2 files changed

+42
-61
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
3+
namespace Discord.Interactions;
4+
5+
/// <summary>
6+
/// Adds additional metadata to enum fields that are used for select-menus.
7+
/// </summary>
8+
/// <remarks>
9+
/// To manually add select menu options to modal components, use <see cref="ModalSelectMenuOptionAttribute"/> instead.
10+
/// </remarks>
11+
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
12+
public class SelectMenuOptionAttribute : Attribute
13+
{
14+
/// <summary>
15+
/// Gets or sets the desription of the option.
16+
/// </summary>
17+
public string Description { get; set; }
18+
19+
/// <summary>
20+
/// Gets or sets whether the option is selected by default.
21+
/// </summary>
22+
public bool IsDefault { get; set; }
23+
24+
/// <summary>
25+
/// Gets or sets the emote of the option.
26+
/// </summary>
27+
/// <remarks>
28+
/// Can be either an <see cref="Emoji"/> or an <see cref="Discord.Emote"/>
29+
/// </remarks>
30+
public string Emote { get; set; }
31+
}
Lines changed: 11 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Discord.Interactions.Utilities;
12
using System;
23
using System.Collections.Immutable;
34
using System.Linq;
@@ -9,36 +10,13 @@ namespace Discord.Interactions;
910
internal sealed class EnumModalComponentConverter<T> : ModalComponentTypeConverter<T>
1011
where T : struct, Enum
1112
{
12-
private record Option(SelectMenuOptionBuilder OptionBuilder, Predicate<IDiscordInteraction> Predicate, T Value);
13-
1413
private readonly bool _isFlags;
15-
private readonly ImmutableArray<Option> _options;
14+
private readonly ImmutableArray<EnumSelectMenuOption> _options;
1615

1716
public EnumModalComponentConverter()
1817
{
19-
var names = Enum.GetNames(typeof(T));
20-
var members = names.SelectMany(x => typeof(T).GetMember(x));
21-
2218
_isFlags = typeof(T).IsDefined(typeof(FlagsAttribute));
23-
24-
_options = members.Select<MemberInfo, Option>(x =>
25-
{
26-
var selectMenuOptionAttr = x.GetCustomAttribute<SelectMenuOptionAttribute>();
27-
28-
Emoji emoji = null;
29-
Emote emote = null;
30-
31-
if (!string.IsNullOrEmpty(selectMenuOptionAttr?.Emote) && !(Emote.TryParse(selectMenuOptionAttr.Emote, out emote) || Emoji.TryParse(selectMenuOptionAttr.Emote, out emoji)))
32-
throw new ArgumentException($"Unable to parse {selectMenuOptionAttr.Emote} of {x.DeclaringType.Name}.{x.Name} into an {typeof(Emote).Name} or an {typeof(Emoji).Name}");
33-
34-
var hideAttr = x.GetCustomAttribute<HideAttribute>();
35-
Predicate<IDiscordInteraction> predicate = hideAttr != null ? hideAttr.Predicate : null;
36-
37-
var value = Enum.Parse<T>(x.Name);
38-
var optionBuilder = new SelectMenuOptionBuilder(x.GetCustomAttribute<ChoiceDisplayAttribute>()?.Name ?? x.Name, x.Name, selectMenuOptionAttr?.Description, emote != null ? emote : emoji, selectMenuOptionAttr?.IsDefault);
39-
40-
return new(optionBuilder, predicate, value);
41-
}).ToImmutableArray();
19+
_options = EnumUtils.BuildSelectMenuOptions(typeof(T)).ToImmutableArray();
4220
}
4321

4422
public override Task<TypeConverterResult> ReadAsync(IInteractionContext context, IComponentInteractionData option, IServiceProvider services)
@@ -67,46 +45,18 @@ public override Task WriteAsync<TBuilder>(TBuilder builder, IDiscordInteraction
6745
if (selectMenu.MaxValues > 1 && !_isFlags)
6846
throw new InvalidOperationException($"Enum type {typeof(T).FullName} is not a [Flags] enum, so it cannot be used in a multi-select menu.");
6947

70-
var visibleOptions = _options.Where(x => !x.Predicate?.Invoke(interaction) ?? true);
48+
var visibleOptions = _options.Where(x => !x.Predicate?.Invoke(interaction) ?? true).ToList();
7149

72-
if (value is T enumValue)
50+
foreach (var option in visibleOptions)
7351
{
74-
foreach(var option in visibleOptions)
75-
{
76-
option.OptionBuilder.IsDefault = _isFlags ? enumValue.HasFlag(option.Value) : enumValue.Equals(option.Value);
77-
}
78-
}
52+
var optionBuilder = new SelectMenuOptionBuilder(option.MenuOption);
53+
54+
if(value is T enumValue && option.Value is T optionValue)
55+
optionBuilder.IsDefault = _isFlags ? enumValue.HasFlag(optionValue) : enumValue.Equals(option.Value);
7956

80-
selectMenu.WithOptions([.. visibleOptions.Select(x => x.OptionBuilder)]);
57+
selectMenu.AddOption(optionBuilder);
58+
}
8159

8260
return Task.CompletedTask;
8361
}
8462
}
85-
86-
/// <summary>
87-
/// Adds additional metadata to enum fields that are used for select-menus.
88-
/// </summary>
89-
/// <remarks>
90-
/// To manually add select menu options to modal components, use <see cref="ModalSelectMenuOptionAttribute"/> instead.
91-
/// </remarks>
92-
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
93-
public class SelectMenuOptionAttribute : Attribute
94-
{
95-
/// <summary>
96-
/// Gets or sets the desription of the option.
97-
/// </summary>
98-
public string Description { get; set; }
99-
100-
/// <summary>
101-
/// Gets or sets whether the option is selected by default.
102-
/// </summary>
103-
public bool IsDefault { get; set; }
104-
105-
/// <summary>
106-
/// Gets or sets the emote of the option.
107-
/// </summary>
108-
/// <remarks>
109-
/// Can be either an <see cref="Emoji"/> or an <see cref="Discord.Emote"/>
110-
/// </remarks>
111-
public string Emote { get; set; }
112-
}

0 commit comments

Comments
 (0)