using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading.Tasks; namespace Discord.Interactions { /// /// Represents a cached object initialization delegate. /// /// Property arguments array. /// /// Returns the constructed object. /// public delegate IModal ModalInitializer(object[] args); /// /// Represents the info class of an form. /// public class ModalInfo { internal readonly InteractionService _interactionService; internal readonly ModalInitializer _initializer; /// /// Gets the title of this modal. /// public string Title { get; } /// /// Gets the implementation used to initialize this object. /// public Type Type { get; } /// /// Gets a collection of the components of this modal. /// public IReadOnlyCollection Components { get; } /// /// Gets a collection of the text components of this modal. /// public IReadOnlyCollection TextComponents { get; } internal ModalInfo(Builders.ModalBuilder builder) { Title = builder.Title; Type = builder.Type; Components = builder.Components.Select(x => x switch { Builders.TextInputComponentBuilder textComponent => textComponent.Build(this), _ => throw new InvalidOperationException($"{x.GetType().FullName} isn't a supported modal input component builder type.") }).ToImmutableArray(); TextComponents = Components.OfType().ToImmutableArray(); _interactionService = builder._interactionService; _initializer = builder.ModalInitializer; } /// /// Creates an and fills it with provided message components. /// /// that will be injected into the modal. /// /// A filled with the provided components. /// [Obsolete("This method is no longer supported with the introduction of Component TypeConverters, please use the CreateModalAsync method.")] public IModal CreateModal(IModalInteraction modalInteraction, bool throwOnMissingField = false) { var args = new object[Components.Count]; var components = modalInteraction.Data.Components.ToList(); for (var i = 0; i < Components.Count; i++) { var input = Components.ElementAt(i); var component = components.Find(x => x.CustomId == input.CustomId); if (component is null) { if (!throwOnMissingField) args[i] = input.DefaultValue; else throw new InvalidOperationException($"Modal interaction is missing the required field: {input.CustomId}"); } else args[i] = component.Value; } return _initializer(args); } /// /// Creates an and fills it with provided message components. /// /// Context of the that will be injected into the modal. /// Services to be passed onto the s of the modal fiels. /// Wheter or not this method should exit on encountering a missing modal field. /// /// A if a type conversion has failed, else a . /// public async Task CreateModalAsync(IInteractionContext context, IServiceProvider services = null, bool throwOnMissingField = false) { if (context.Interaction is not IModalInteraction modalInteraction) return TypeConverterResult.FromError(InteractionCommandError.Unsuccessful, "Provided context doesn't belong to a Modal Interaction."); services ??= EmptyServiceProvider.Instance; var args = new object[Components.Count]; var components = modalInteraction.Data.Components.ToList(); for (var i = 0; i < Components.Count; i++) { var input = Components.ElementAt(i); var component = components.Find(x => x.CustomId == input.CustomId); if (component is null) { if (!throwOnMissingField) args[i] = input.DefaultValue; else return TypeConverterResult.FromError(InteractionCommandError.BadArgs, $"Modal interaction is missing the required field: {input.CustomId}"); } else { var readResult = await input.TypeConverter.ReadAsync(context, component, services).ConfigureAwait(false); if (!readResult.IsSuccess) return readResult; args[i] = readResult.Value; } } return TypeConverterResult.FromSuccess(_initializer(args)); } } }