1+ using Discord . Interactions . Utilities ;
12using System ;
23using System . Collections . Immutable ;
34using System . Linq ;
@@ -9,36 +10,13 @@ namespace Discord.Interactions;
910internal 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