| @@ -0,0 +1,12 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| namespace Discord | |||||
| { | |||||
| //public class GuildChannelCategoryProperties : GuildChannelProperties | |||||
| //{ | |||||
| //} | |||||
| } | |||||
| @@ -26,5 +26,9 @@ | |||||
| /// Move the channel to the following position. This is 0-based! | /// Move the channel to the following position. This is 0-based! | ||||
| /// </summary> | /// </summary> | ||||
| public Optional<int> Position { get; set; } | public Optional<int> Position { get; set; } | ||||
| /// <summary> | |||||
| /// Sets the category for this channel | |||||
| /// </summary> | |||||
| public Optional<ulong?> ParentId { get; set; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -9,6 +9,10 @@ namespace Discord | |||||
| /// <summary> Gets the position of this channel in the guild's channel list, relative to others of the same type. </summary> | /// <summary> Gets the position of this channel in the guild's channel list, relative to others of the same type. </summary> | ||||
| int Position { get; } | int Position { get; } | ||||
| /// <summary> Gets the parentid (category) of this channel in the guild's channel list. </summary> | |||||
| ulong? ParentId { get; } | |||||
| /// <summary> Gets the parent channel (category) of this channel. </summary> | |||||
| Task<IGuildChannel> GetParentChannelAsync(); | |||||
| /// <summary> Gets the guild this channel is a member of. </summary> | /// <summary> Gets the guild this channel is a member of. </summary> | ||||
| IGuild Guild { get; } | IGuild Guild { get; } | ||||
| /// <summary> Gets the id of the guild this channel is a member of. </summary> | /// <summary> Gets the id of the guild this channel is a member of. </summary> | ||||
| @@ -23,7 +27,7 @@ namespace Discord | |||||
| Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 1800, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null); | Task<IInviteMetadata> CreateInviteAsync(int? maxAge = 1800, int? maxUses = default(int?), bool isTemporary = false, bool isUnique = false, RequestOptions options = null); | ||||
| /// <summary> Returns a collection of all invites to this channel. </summary> | /// <summary> Returns a collection of all invites to this channel. </summary> | ||||
| Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null); | Task<IReadOnlyCollection<IInviteMetadata>> GetInvitesAsync(RequestOptions options = null); | ||||
| /// <summary> Modifies this guild channel. </summary> | /// <summary> Modifies this guild channel. </summary> | ||||
| Task ModifyAsync(Action<GuildChannelProperties> func, RequestOptions options = null); | Task ModifyAsync(Action<GuildChannelProperties> func, RequestOptions options = null); | ||||
| @@ -0,0 +1,14 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| namespace Discord | |||||
| { | |||||
| public interface IGuildChannelCategory : IGuildChannel | |||||
| { | |||||
| ///// <summary> Modifies this text channel. </summary> | |||||
| //Task ModifyAsync(Action<GuildChannelCategoryProperties> func, RequestOptions options = null); | |||||
| } | |||||
| } | |||||
| @@ -84,6 +84,7 @@ namespace Discord | |||||
| Task<IReadOnlyCollection<ITextChannel>> GetTextChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<IReadOnlyCollection<ITextChannel>> GetTextChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
| Task<ITextChannel> GetTextChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<ITextChannel> GetTextChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
| Task<IReadOnlyCollection<IVoiceChannel>> GetVoiceChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<IReadOnlyCollection<IVoiceChannel>> GetVoiceChannelsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
| Task<IReadOnlyCollection<IGuildChannelCategory>> GetChannelCategoriesAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | |||||
| Task<IVoiceChannel> GetVoiceChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<IVoiceChannel> GetVoiceChannelAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
| Task<IVoiceChannel> GetAFKChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<IVoiceChannel> GetAFKChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
| Task<ITextChannel> GetSystemChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<ITextChannel> GetSystemChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | ||||
| @@ -23,6 +23,8 @@ namespace Discord.API | |||||
| public Optional<int> Position { get; set; } | public Optional<int> Position { get; set; } | ||||
| [JsonProperty("permission_overwrites")] | [JsonProperty("permission_overwrites")] | ||||
| public Optional<Overwrite[]> PermissionOverwrites { get; set; } | public Optional<Overwrite[]> PermissionOverwrites { get; set; } | ||||
| [JsonProperty("parent_id")] | |||||
| public ulong? ParentId { get; set; } | |||||
| //TextChannel | //TextChannel | ||||
| [JsonProperty("topic")] | [JsonProperty("topic")] | ||||
| @@ -0,0 +1,14 @@ | |||||
| #pragma warning disable CS1591 | |||||
| using Newtonsoft.Json; | |||||
| namespace Discord.API.Rest | |||||
| { | |||||
| [JsonObject(MemberSerialization = MemberSerialization.OptIn)] | |||||
| internal class ModifyGuildChannelCategoryParams | |||||
| { | |||||
| [JsonProperty("name")] | |||||
| public Optional<string> Name { get; set; } | |||||
| [JsonProperty("position")] | |||||
| public Optional<int> Position { get; set; } | |||||
| } | |||||
| } | |||||
| @@ -10,5 +10,7 @@ namespace Discord.API.Rest | |||||
| public Optional<string> Name { get; set; } | public Optional<string> Name { get; set; } | ||||
| [JsonProperty("position")] | [JsonProperty("position")] | ||||
| public Optional<int> Position { get; set; } | public Optional<int> Position { get; set; } | ||||
| [JsonProperty("parent_id")] | |||||
| public Optional<ulong?> ParentId { get; set; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -13,13 +13,13 @@ namespace Discord.Rest | |||||
| internal static class ChannelHelper | internal static class ChannelHelper | ||||
| { | { | ||||
| //General | //General | ||||
| public static async Task DeleteAsync(IChannel channel, BaseDiscordClient client, | |||||
| public static async Task DeleteAsync(IChannel channel, BaseDiscordClient client, | |||||
| RequestOptions options) | RequestOptions options) | ||||
| { | |||||
| { | |||||
| await client.ApiClient.DeleteChannelAsync(channel.Id, options).ConfigureAwait(false); | await client.ApiClient.DeleteChannelAsync(channel.Id, options).ConfigureAwait(false); | ||||
| } | } | ||||
| public static async Task<Model> ModifyAsync(IGuildChannel channel, BaseDiscordClient client, | |||||
| Action<GuildChannelProperties> func, | |||||
| public static async Task<Model> ModifyAsync(IGuildChannel channel, BaseDiscordClient client, | |||||
| Action<GuildChannelProperties> func, | |||||
| RequestOptions options) | RequestOptions options) | ||||
| { | { | ||||
| var args = new GuildChannelProperties(); | var args = new GuildChannelProperties(); | ||||
| @@ -27,12 +27,13 @@ namespace Discord.Rest | |||||
| var apiArgs = new API.Rest.ModifyGuildChannelParams | var apiArgs = new API.Rest.ModifyGuildChannelParams | ||||
| { | { | ||||
| Name = args.Name, | Name = args.Name, | ||||
| Position = args.Position | |||||
| Position = args.Position, | |||||
| ParentId = args.ParentId | |||||
| }; | }; | ||||
| return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | ||||
| } | } | ||||
| public static async Task<Model> ModifyAsync(ITextChannel channel, BaseDiscordClient client, | |||||
| Action<TextChannelProperties> func, | |||||
| public static async Task<Model> ModifyAsync(ITextChannel channel, BaseDiscordClient client, | |||||
| Action<TextChannelProperties> func, | |||||
| RequestOptions options) | RequestOptions options) | ||||
| { | { | ||||
| var args = new TextChannelProperties(); | var args = new TextChannelProperties(); | ||||
| @@ -41,13 +42,14 @@ namespace Discord.Rest | |||||
| { | { | ||||
| Name = args.Name, | Name = args.Name, | ||||
| Position = args.Position, | Position = args.Position, | ||||
| ParentId = args.ParentId, | |||||
| Topic = args.Topic, | Topic = args.Topic, | ||||
| IsNsfw = args.IsNsfw | IsNsfw = args.IsNsfw | ||||
| }; | }; | ||||
| return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | ||||
| } | } | ||||
| public static async Task<Model> ModifyAsync(IVoiceChannel channel, BaseDiscordClient client, | |||||
| Action<VoiceChannelProperties> func, | |||||
| public static async Task<Model> ModifyAsync(IVoiceChannel channel, BaseDiscordClient client, | |||||
| Action<VoiceChannelProperties> func, | |||||
| RequestOptions options) | RequestOptions options) | ||||
| { | { | ||||
| var args = new VoiceChannelProperties(); | var args = new VoiceChannelProperties(); | ||||
| @@ -57,6 +59,7 @@ namespace Discord.Rest | |||||
| Bitrate = args.Bitrate, | Bitrate = args.Bitrate, | ||||
| Name = args.Name, | Name = args.Name, | ||||
| Position = args.Position, | Position = args.Position, | ||||
| ParentId = args.ParentId, | |||||
| UserLimit = args.UserLimit.IsSpecified ? (args.UserLimit.Value ?? 0) : Optional.Create<int>() | UserLimit = args.UserLimit.IsSpecified ? (args.UserLimit.Value ?? 0) : Optional.Create<int>() | ||||
| }; | }; | ||||
| return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | return await client.ApiClient.ModifyGuildChannelAsync(channel.Id, apiArgs, options).ConfigureAwait(false); | ||||
| @@ -86,7 +89,7 @@ namespace Discord.Rest | |||||
| } | } | ||||
| //Messages | //Messages | ||||
| public static async Task<RestMessage> GetMessageAsync(IMessageChannel channel, BaseDiscordClient client, | |||||
| public static async Task<RestMessage> GetMessageAsync(IMessageChannel channel, BaseDiscordClient client, | |||||
| ulong id, RequestOptions options) | ulong id, RequestOptions options) | ||||
| { | { | ||||
| var guildId = (channel as IGuildChannel)?.GuildId; | var guildId = (channel as IGuildChannel)?.GuildId; | ||||
| @@ -97,7 +100,7 @@ namespace Discord.Rest | |||||
| var author = GetAuthor(client, guild, model.Author.Value, model.WebhookId.ToNullable()); | var author = GetAuthor(client, guild, model.Author.Value, model.WebhookId.ToNullable()); | ||||
| return RestMessage.Create(client, channel, author, model); | return RestMessage.Create(client, channel, author, model); | ||||
| } | } | ||||
| public static IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(IMessageChannel channel, BaseDiscordClient client, | |||||
| public static IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(IMessageChannel channel, BaseDiscordClient client, | |||||
| ulong? fromMessageId, Direction dir, int limit, RequestOptions options) | ulong? fromMessageId, Direction dir, int limit, RequestOptions options) | ||||
| { | { | ||||
| if (dir == Direction.Around) | if (dir == Direction.Around) | ||||
| @@ -123,7 +126,7 @@ namespace Discord.Rest | |||||
| foreach (var model in models) | foreach (var model in models) | ||||
| { | { | ||||
| var author = GetAuthor(client, guild, model.Author.Value, model.WebhookId.ToNullable()); | var author = GetAuthor(client, guild, model.Author.Value, model.WebhookId.ToNullable()); | ||||
| builder.Add(RestMessage.Create(client, channel, author, model)); | |||||
| builder.Add(RestMessage.Create(client, channel, author, model)); | |||||
| } | } | ||||
| return builder.ToImmutable(); | return builder.ToImmutable(); | ||||
| }, | }, | ||||
| @@ -179,7 +182,7 @@ namespace Discord.Rest | |||||
| var args = new UploadFileParams(stream) { Filename = filename, Content = text, IsTTS = isTTS }; | var args = new UploadFileParams(stream) { Filename = filename, Content = text, IsTTS = isTTS }; | ||||
| var model = await client.ApiClient.UploadFileAsync(channel.Id, args, options).ConfigureAwait(false); | var model = await client.ApiClient.UploadFileAsync(channel.Id, args, options).ConfigureAwait(false); | ||||
| return RestUserMessage.Create(client, channel, client.CurrentUser, model); | return RestUserMessage.Create(client, channel, client.CurrentUser, model); | ||||
| } | |||||
| } | |||||
| public static async Task DeleteMessagesAsync(IMessageChannel channel, BaseDiscordClient client, | public static async Task DeleteMessagesAsync(IMessageChannel channel, BaseDiscordClient client, | ||||
| IEnumerable<ulong> messageIds, RequestOptions options) | IEnumerable<ulong> messageIds, RequestOptions options) | ||||
| @@ -276,7 +279,7 @@ namespace Discord.Rest | |||||
| { | { | ||||
| await client.ApiClient.TriggerTypingIndicatorAsync(channel.Id, options).ConfigureAwait(false); | await client.ApiClient.TriggerTypingIndicatorAsync(channel.Id, options).ConfigureAwait(false); | ||||
| } | } | ||||
| public static IDisposable EnterTypingState(IMessageChannel channel, BaseDiscordClient client, | |||||
| public static IDisposable EnterTypingState(IMessageChannel channel, BaseDiscordClient client, | |||||
| RequestOptions options) | RequestOptions options) | ||||
| => new TypingNotifier(client, channel, options); | => new TypingNotifier(client, channel, options); | ||||
| @@ -5,6 +5,7 @@ | |||||
| Text = 0, | Text = 0, | ||||
| DM = 1, | DM = 1, | ||||
| Voice = 2, | Voice = 2, | ||||
| Group = 3 | |||||
| Group = 3, | |||||
| Category = 4 | |||||
| } | } | ||||
| } | } | ||||
| @@ -16,6 +16,8 @@ namespace Discord.Rest | |||||
| internal IGuild Guild { get; } | internal IGuild Guild { get; } | ||||
| public string Name { get; private set; } | public string Name { get; private set; } | ||||
| public int Position { get; private set; } | public int Position { get; private set; } | ||||
| public ulong? ParentId { get; private set; } | |||||
| public Task<IGuildChannel> GetParentChannelAsync() => ParentId == null ? null : Guild.GetChannelAsync(ParentId.Value); | |||||
| public ulong GuildId => Guild.Id; | public ulong GuildId => Guild.Id; | ||||
| @@ -61,7 +63,7 @@ namespace Discord.Rest | |||||
| } | } | ||||
| public Task DeleteAsync(RequestOptions options = null) | public Task DeleteAsync(RequestOptions options = null) | ||||
| => ChannelHelper.DeleteAsync(this, Discord, options); | => ChannelHelper.DeleteAsync(this, Discord, options); | ||||
| public OverwritePermissions? GetPermissionOverwrite(IUser user) | public OverwritePermissions? GetPermissionOverwrite(IUser user) | ||||
| { | { | ||||
| for (int i = 0; i < _overwrites.Length; i++) | for (int i = 0; i < _overwrites.Length; i++) | ||||
| @@ -139,20 +141,20 @@ namespace Discord.Rest | |||||
| => await GetInvitesAsync(options).ConfigureAwait(false); | => await GetInvitesAsync(options).ConfigureAwait(false); | ||||
| async Task<IInviteMetadata> IGuildChannel.CreateInviteAsync(int? maxAge, int? maxUses, bool isTemporary, bool isUnique, RequestOptions options) | async Task<IInviteMetadata> IGuildChannel.CreateInviteAsync(int? maxAge, int? maxUses, bool isTemporary, bool isUnique, RequestOptions options) | ||||
| => await CreateInviteAsync(maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); | => await CreateInviteAsync(maxAge, maxUses, isTemporary, isUnique, options).ConfigureAwait(false); | ||||
| OverwritePermissions? IGuildChannel.GetPermissionOverwrite(IRole role) | |||||
| OverwritePermissions? IGuildChannel.GetPermissionOverwrite(IRole role) | |||||
| => GetPermissionOverwrite(role); | => GetPermissionOverwrite(role); | ||||
| OverwritePermissions? IGuildChannel.GetPermissionOverwrite(IUser user) | OverwritePermissions? IGuildChannel.GetPermissionOverwrite(IUser user) | ||||
| => GetPermissionOverwrite(user); | => GetPermissionOverwrite(user); | ||||
| async Task IGuildChannel.AddPermissionOverwriteAsync(IRole role, OverwritePermissions permissions, RequestOptions options) | |||||
| async Task IGuildChannel.AddPermissionOverwriteAsync(IRole role, OverwritePermissions permissions, RequestOptions options) | |||||
| => await AddPermissionOverwriteAsync(role, permissions, options).ConfigureAwait(false); | => await AddPermissionOverwriteAsync(role, permissions, options).ConfigureAwait(false); | ||||
| async Task IGuildChannel.AddPermissionOverwriteAsync(IUser user, OverwritePermissions permissions, RequestOptions options) | |||||
| async Task IGuildChannel.AddPermissionOverwriteAsync(IUser user, OverwritePermissions permissions, RequestOptions options) | |||||
| => await AddPermissionOverwriteAsync(user, permissions, options).ConfigureAwait(false); | => await AddPermissionOverwriteAsync(user, permissions, options).ConfigureAwait(false); | ||||
| async Task IGuildChannel.RemovePermissionOverwriteAsync(IRole role, RequestOptions options) | |||||
| async Task IGuildChannel.RemovePermissionOverwriteAsync(IRole role, RequestOptions options) | |||||
| => await RemovePermissionOverwriteAsync(role, options).ConfigureAwait(false); | => await RemovePermissionOverwriteAsync(role, options).ConfigureAwait(false); | ||||
| async Task IGuildChannel.RemovePermissionOverwriteAsync(IUser user, RequestOptions options) | |||||
| async Task IGuildChannel.RemovePermissionOverwriteAsync(IUser user, RequestOptions options) | |||||
| => await RemovePermissionOverwriteAsync(user, options).ConfigureAwait(false); | => await RemovePermissionOverwriteAsync(user, options).ConfigureAwait(false); | ||||
| IAsyncEnumerable<IReadOnlyCollection<IGuildUser>> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options) | IAsyncEnumerable<IReadOnlyCollection<IGuildUser>> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options) | ||||
| => AsyncEnumerable.Empty<IReadOnlyCollection<IGuildUser>>(); //Overriden //Overriden in Text/Voice | => AsyncEnumerable.Empty<IReadOnlyCollection<IGuildUser>>(); //Overriden //Overriden in Text/Voice | ||||
| Task<IGuildUser> IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) | Task<IGuildUser> IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) | ||||
| @@ -0,0 +1,38 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Diagnostics; | |||||
| using System.IO; | |||||
| using System.Linq; | |||||
| using System.Threading.Tasks; | |||||
| using Model = Discord.API.Channel; | |||||
| namespace Discord.Rest | |||||
| { | |||||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||||
| public class RestGuildChannelCategory : RestGuildChannel, IGuildChannelCategory | |||||
| { | |||||
| public string Mention => MentionUtils.MentionChannel(Id); | |||||
| internal RestGuildChannelCategory(BaseDiscordClient discord, IGuild guild, ulong id) | |||||
| : base(discord, guild, id) | |||||
| { | |||||
| } | |||||
| internal new static RestGuildChannelCategory Create(BaseDiscordClient discord, IGuild guild, Model model) | |||||
| { | |||||
| var entity = new RestGuildChannelCategory(discord, guild, model.Id); | |||||
| entity.Update(model); | |||||
| return entity; | |||||
| } | |||||
| internal override void Update(Model model) | |||||
| { | |||||
| base.Update(model); | |||||
| } | |||||
| public Task<RestGuildUser> GetUserAsync(ulong id, RequestOptions options = null) | |||||
| => ChannelHelper.GetUserAsync(this, Guild, Discord, id, options); | |||||
| public IAsyncEnumerable<IReadOnlyCollection<RestGuildUser>> GetUsersAsync(RequestOptions options = null) | |||||
| => ChannelHelper.GetUsersAsync(this, Guild, Discord, null, null, options); | |||||
| private string DebuggerDisplay => $"{Name} ({Id}, Text)"; | |||||
| } | |||||
| } | |||||
| @@ -23,7 +23,7 @@ namespace Discord.Rest | |||||
| public VerificationLevel VerificationLevel { get; private set; } | public VerificationLevel VerificationLevel { get; private set; } | ||||
| public MfaLevel MfaLevel { get; private set; } | public MfaLevel MfaLevel { get; private set; } | ||||
| public DefaultMessageNotifications DefaultMessageNotifications { get; private set; } | public DefaultMessageNotifications DefaultMessageNotifications { get; private set; } | ||||
| public ulong? AFKChannelId { get; private set; } | public ulong? AFKChannelId { get; private set; } | ||||
| public ulong? EmbedChannelId { get; private set; } | public ulong? EmbedChannelId { get; private set; } | ||||
| public ulong? SystemChannelId { get; private set; } | public ulong? SystemChannelId { get; private set; } | ||||
| @@ -114,7 +114,7 @@ namespace Discord.Rest | |||||
| Update(model); | Update(model); | ||||
| } | } | ||||
| public async Task ModifyEmbedAsync(Action<GuildEmbedProperties> func, RequestOptions options = null) | public async Task ModifyEmbedAsync(Action<GuildEmbedProperties> func, RequestOptions options = null) | ||||
| { | |||||
| { | |||||
| var model = await GuildHelper.ModifyEmbedAsync(this, Discord, func, options).ConfigureAwait(false); | var model = await GuildHelper.ModifyEmbedAsync(this, Discord, func, options).ConfigureAwait(false); | ||||
| Update(model); | Update(model); | ||||
| } | } | ||||
| @@ -155,7 +155,7 @@ namespace Discord.Rest | |||||
| public Task<IReadOnlyCollection<RestGuildChannel>> GetChannelsAsync(RequestOptions options = null) | public Task<IReadOnlyCollection<RestGuildChannel>> GetChannelsAsync(RequestOptions options = null) | ||||
| => GuildHelper.GetChannelsAsync(this, Discord, options); | => GuildHelper.GetChannelsAsync(this, Discord, options); | ||||
| public Task<RestGuildChannel> GetChannelAsync(ulong id, RequestOptions options = null) | public Task<RestGuildChannel> GetChannelAsync(ulong id, RequestOptions options = null) | ||||
| => GuildHelper.GetChannelAsync(this, Discord, id, options); | |||||
| => GuildHelper.GetChannelAsync(this, Discord, id, options); | |||||
| public async Task<RestTextChannel> GetTextChannelAsync(ulong id, RequestOptions options = null) | public async Task<RestTextChannel> GetTextChannelAsync(ulong id, RequestOptions options = null) | ||||
| { | { | ||||
| var channel = await GuildHelper.GetChannelAsync(this, Discord, id, options).ConfigureAwait(false); | var channel = await GuildHelper.GetChannelAsync(this, Discord, id, options).ConfigureAwait(false); | ||||
| @@ -176,6 +176,11 @@ namespace Discord.Rest | |||||
| var channels = await GuildHelper.GetChannelsAsync(this, Discord, options).ConfigureAwait(false); | var channels = await GuildHelper.GetChannelsAsync(this, Discord, options).ConfigureAwait(false); | ||||
| return channels.Select(x => x as RestVoiceChannel).Where(x => x != null).ToImmutableArray(); | return channels.Select(x => x as RestVoiceChannel).Where(x => x != null).ToImmutableArray(); | ||||
| } | } | ||||
| public async Task<IReadOnlyCollection<RestGuildChannelCategory>> GetChannelCategoriesAsync(RequestOptions options = null) | |||||
| { | |||||
| var channels = await GuildHelper.GetChannelsAsync(this, Discord, options).ConfigureAwait(false); | |||||
| return channels.Select(x => x as RestGuildChannelCategory).Where(x => x != null).ToImmutableArray(); | |||||
| } | |||||
| public async Task<RestVoiceChannel> GetAFKChannelAsync(RequestOptions options = null) | public async Task<RestVoiceChannel> GetAFKChannelAsync(RequestOptions options = null) | ||||
| { | { | ||||
| @@ -199,7 +204,7 @@ namespace Discord.Rest | |||||
| public async Task<RestGuildChannel> GetEmbedChannelAsync(RequestOptions options = null) | public async Task<RestGuildChannel> GetEmbedChannelAsync(RequestOptions options = null) | ||||
| { | { | ||||
| var embedId = EmbedChannelId; | var embedId = EmbedChannelId; | ||||
| if (embedId.HasValue) | |||||
| if (embedId.HasValue) | |||||
| return await GuildHelper.GetChannelAsync(this, Discord, embedId.Value, options).ConfigureAwait(false); | return await GuildHelper.GetChannelAsync(this, Discord, embedId.Value, options).ConfigureAwait(false); | ||||
| return null; | return null; | ||||
| } | } | ||||
| @@ -236,7 +241,7 @@ namespace Discord.Rest | |||||
| return null; | return null; | ||||
| } | } | ||||
| public async Task<RestRole> CreateRoleAsync(string name, GuildPermissions? permissions = default(GuildPermissions?), Color? color = default(Color?), | |||||
| public async Task<RestRole> CreateRoleAsync(string name, GuildPermissions? permissions = default(GuildPermissions?), Color? color = default(Color?), | |||||
| bool isHoisted = false, RequestOptions options = null) | bool isHoisted = false, RequestOptions options = null) | ||||
| { | { | ||||
| var role = await GuildHelper.CreateRoleAsync(this, Discord, name, permissions, color, isHoisted, options).ConfigureAwait(false); | var role = await GuildHelper.CreateRoleAsync(this, Discord, name, permissions, color, isHoisted, options).ConfigureAwait(false); | ||||
| @@ -304,6 +309,13 @@ namespace Discord.Rest | |||||
| else | else | ||||
| return ImmutableArray.Create<IVoiceChannel>(); | return ImmutableArray.Create<IVoiceChannel>(); | ||||
| } | } | ||||
| async Task<IReadOnlyCollection<IGuildChannelCategory>> IGuild.GetChannelCategoriesAsync(CacheMode mode , RequestOptions options) | |||||
| { | |||||
| if (mode == CacheMode.AllowDownload) | |||||
| return await GetChannelCategoriesAsync(options).ConfigureAwait(false); | |||||
| else | |||||
| return null; | |||||
| } | |||||
| async Task<IVoiceChannel> IGuild.GetVoiceChannelAsync(ulong id, CacheMode mode, RequestOptions options) | async Task<IVoiceChannel> IGuild.GetVoiceChannelAsync(ulong id, CacheMode mode, RequestOptions options) | ||||
| { | { | ||||
| if (mode == CacheMode.AllowDownload) | if (mode == CacheMode.AllowDownload) | ||||
| @@ -352,7 +364,7 @@ namespace Discord.Rest | |||||
| async Task<IReadOnlyCollection<IInviteMetadata>> IGuild.GetInvitesAsync(RequestOptions options) | async Task<IReadOnlyCollection<IInviteMetadata>> IGuild.GetInvitesAsync(RequestOptions options) | ||||
| => await GetInvitesAsync(options).ConfigureAwait(false); | => await GetInvitesAsync(options).ConfigureAwait(false); | ||||
| IRole IGuild.GetRole(ulong id) | |||||
| IRole IGuild.GetRole(ulong id) | |||||
| => GetRole(id); | => GetRole(id); | ||||
| async Task<IRole> IGuild.CreateRoleAsync(string name, GuildPermissions? permissions, Color? color, bool isHoisted, RequestOptions options) | async Task<IRole> IGuild.CreateRoleAsync(string name, GuildPermissions? permissions, Color? color, bool isHoisted, RequestOptions options) | ||||
| => await CreateRoleAsync(name, permissions, color, isHoisted, options).ConfigureAwait(false); | => await CreateRoleAsync(name, permissions, color, isHoisted, options).ConfigureAwait(false); | ||||
| @@ -0,0 +1,38 @@ | |||||
| using Discord.Rest; | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Collections.Immutable; | |||||
| using System.Diagnostics; | |||||
| using System.IO; | |||||
| using System.Linq; | |||||
| using System.Threading.Tasks; | |||||
| using Model = Discord.API.Rpc.Channel; | |||||
| namespace Discord.Rpc | |||||
| { | |||||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||||
| public class RpcChannelCategory : RpcGuildChannel | |||||
| { | |||||
| public IReadOnlyCollection<RpcMessage> CachedMessages { get; private set; } | |||||
| public string Mention => MentionUtils.MentionChannel(Id); | |||||
| // TODO: Check if RPC includes the 'nsfw' field on Channel models | |||||
| public bool IsNsfw => ChannelHelper.IsNsfw(this); | |||||
| internal RpcChannelCategory(DiscordRpcClient discord, ulong id, ulong guildId) | |||||
| : base(discord, id, guildId) | |||||
| { | |||||
| } | |||||
| internal new static RpcChannelCategory Create(DiscordRpcClient discord, Model model) | |||||
| { | |||||
| var entity = new RpcChannelCategory(discord, model.Id, model.GuildId.Value); | |||||
| entity.Update(model); | |||||
| return entity; | |||||
| } | |||||
| internal override void Update(Model model) | |||||
| { | |||||
| base.Update(model); | |||||
| CachedMessages = model.Messages.Select(x => RpcMessage.Create(Discord, Id, x)).ToImmutableArray(); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -10,6 +10,7 @@ namespace Discord.Rpc | |||||
| { | { | ||||
| public ulong GuildId { get; } | public ulong GuildId { get; } | ||||
| public int Position { get; private set; } | public int Position { get; private set; } | ||||
| public ulong? ParentId { get; private set; } | |||||
| internal RpcGuildChannel(DiscordRpcClient discord, ulong id, ulong guildId) | internal RpcGuildChannel(DiscordRpcClient discord, ulong id, ulong guildId) | ||||
| : base(discord, id) | : base(discord, id) | ||||
| @@ -57,6 +58,12 @@ namespace Discord.Rpc | |||||
| public override string ToString() => Name; | public override string ToString() => Name; | ||||
| //IGuildChannel | //IGuildChannel | ||||
| public Task<IGuildChannel> GetParentChannelAsync() | |||||
| { | |||||
| //Always fails | |||||
| throw new InvalidOperationException("Unable to return this entity's parent unless it was fetched through that object."); | |||||
| } | |||||
| IGuild IGuildChannel.Guild | IGuild IGuildChannel.Guild | ||||
| { | { | ||||
| get | get | ||||
| @@ -17,6 +17,9 @@ namespace Discord.WebSocket | |||||
| public SocketGuild Guild { get; } | public SocketGuild Guild { get; } | ||||
| public string Name { get; private set; } | public string Name { get; private set; } | ||||
| public int Position { get; private set; } | public int Position { get; private set; } | ||||
| public ulong? ParentId { get; private set; } | |||||
| public IGuildChannel ParentChannel => ParentId == null ? null : Guild.GetChannel(ParentId.Value); | |||||
| public Task<IGuildChannel> GetParentChannelAsync() => Task.FromResult(ParentChannel); | |||||
| public IReadOnlyCollection<Overwrite> PermissionOverwrites => _overwrites; | public IReadOnlyCollection<Overwrite> PermissionOverwrites => _overwrites; | ||||
| public new virtual IReadOnlyCollection<SocketGuildUser> Users => ImmutableArray.Create<SocketGuildUser>(); | public new virtual IReadOnlyCollection<SocketGuildUser> Users => ImmutableArray.Create<SocketGuildUser>(); | ||||
| @@ -34,6 +37,8 @@ namespace Discord.WebSocket | |||||
| return SocketTextChannel.Create(guild, state, model); | return SocketTextChannel.Create(guild, state, model); | ||||
| case ChannelType.Voice: | case ChannelType.Voice: | ||||
| return SocketVoiceChannel.Create(guild, state, model); | return SocketVoiceChannel.Create(guild, state, model); | ||||
| case ChannelType.Category: | |||||
| return SocketGuildChannelCategory.Create(guild, state, model); | |||||
| default: | default: | ||||
| // TODO: Proper implementation for channel categories | // TODO: Proper implementation for channel categories | ||||
| return new SocketGuildChannel(guild.Discord, model.Id, guild); | return new SocketGuildChannel(guild.Discord, model.Id, guild); | ||||
| @@ -43,6 +48,7 @@ namespace Discord.WebSocket | |||||
| { | { | ||||
| Name = model.Name.Value; | Name = model.Name.Value; | ||||
| Position = model.Position.Value; | Position = model.Position.Value; | ||||
| ParentId = model.ParentId; | |||||
| var overwrites = model.PermissionOverwrites.Value; | var overwrites = model.PermissionOverwrites.Value; | ||||
| var newOverwrites = ImmutableArray.CreateBuilder<Overwrite>(overwrites.Length); | var newOverwrites = ImmutableArray.CreateBuilder<Overwrite>(overwrites.Length); | ||||
| @@ -0,0 +1,46 @@ | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Collections.Immutable; | |||||
| using System.Diagnostics; | |||||
| using System.Linq; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| using Discord.Audio; | |||||
| using Discord.Rest; | |||||
| using Model = Discord.API.Channel; | |||||
| namespace Discord.WebSocket | |||||
| { | |||||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||||
| public class SocketGuildChannelCategory : SocketGuildChannel, IGuildChannelCategory | |||||
| { | |||||
| public override IReadOnlyCollection<SocketGuildUser> Users | |||||
| => Guild.Users.Where(x => x.VoiceChannel?.Id == Id).ToImmutableArray(); | |||||
| internal SocketGuildChannelCategory(DiscordSocketClient discord, ulong id, SocketGuild guild) | |||||
| : base(discord, id, guild) | |||||
| { | |||||
| } | |||||
| internal new static SocketGuildChannelCategory Create(SocketGuild guild, ClientState state, Model model) | |||||
| { | |||||
| var entity = new SocketGuildChannelCategory(guild.Discord, model.Id, guild); | |||||
| entity.Update(state, model); | |||||
| return entity; | |||||
| } | |||||
| internal override void Update(ClientState state, Model model) | |||||
| { | |||||
| base.Update(state, model); | |||||
| } | |||||
| public override SocketGuildUser GetUser(ulong id) | |||||
| { | |||||
| var user = Guild.GetUser(id); | |||||
| if (user?.VoiceChannel?.Id == Id) | |||||
| return user; | |||||
| return null; | |||||
| } | |||||
| private string DebuggerDisplay => $"{Name} ({Id}, Category)"; | |||||
| internal new SocketGuildChannelCategory Clone() => MemberwiseClone() as SocketGuildChannelCategory; | |||||
| } | |||||
| } | |||||
| @@ -74,7 +74,7 @@ namespace Discord.WebSocket | |||||
| return id.HasValue ? GetVoiceChannel(id.Value) : null; | return id.HasValue ? GetVoiceChannel(id.Value) : null; | ||||
| } | } | ||||
| } | } | ||||
| public SocketGuildChannel EmbedChannel | |||||
| public SocketGuildChannel EmbedChannel | |||||
| { | { | ||||
| get | get | ||||
| { | { | ||||
| @@ -94,6 +94,8 @@ namespace Discord.WebSocket | |||||
| => Channels.Select(x => x as SocketTextChannel).Where(x => x != null).ToImmutableArray(); | => Channels.Select(x => x as SocketTextChannel).Where(x => x != null).ToImmutableArray(); | ||||
| public IReadOnlyCollection<SocketVoiceChannel> VoiceChannels | public IReadOnlyCollection<SocketVoiceChannel> VoiceChannels | ||||
| => Channels.Select(x => x as SocketVoiceChannel).Where(x => x != null).ToImmutableArray(); | => Channels.Select(x => x as SocketVoiceChannel).Where(x => x != null).ToImmutableArray(); | ||||
| public IReadOnlyCollection<SocketGuildChannelCategory> ChannelCategories | |||||
| => Channels.Select(x => x as SocketGuildChannelCategory).Where(x => x != null).ToImmutableArray(); | |||||
| public SocketGuildUser CurrentUser => _members.TryGetValue(Discord.CurrentUser.Id, out SocketGuildUser member) ? member : null; | public SocketGuildUser CurrentUser => _members.TryGetValue(Discord.CurrentUser.Id, out SocketGuildUser member) ? member : null; | ||||
| public SocketRole EveryoneRole => GetRole(Id); | public SocketRole EveryoneRole => GetRole(Id); | ||||
| public IReadOnlyCollection<SocketGuildChannel> Channels | public IReadOnlyCollection<SocketGuildChannel> Channels | ||||
| @@ -347,7 +349,7 @@ namespace Discord.WebSocket | |||||
| return value; | return value; | ||||
| return null; | return null; | ||||
| } | } | ||||
| public Task<RestRole> CreateRoleAsync(string name, GuildPermissions? permissions = default(GuildPermissions?), Color? color = default(Color?), | |||||
| public Task<RestRole> CreateRoleAsync(string name, GuildPermissions? permissions = default(GuildPermissions?), Color? color = default(Color?), | |||||
| bool isHoisted = false, RequestOptions options = null) | bool isHoisted = false, RequestOptions options = null) | ||||
| => GuildHelper.CreateRoleAsync(this, Discord, name, permissions, color, isHoisted, options); | => GuildHelper.CreateRoleAsync(this, Discord, name, permissions, color, isHoisted, options); | ||||
| internal SocketRole AddRole(RoleModel model) | internal SocketRole AddRole(RoleModel model) | ||||
| @@ -577,7 +579,7 @@ namespace Discord.WebSocket | |||||
| try | try | ||||
| { | { | ||||
| await RepopulateAudioStreamsAsync().ConfigureAwait(false); | await RepopulateAudioStreamsAsync().ConfigureAwait(false); | ||||
| await _audioClient.StartAsync(url, Discord.CurrentUser.Id, voiceState.VoiceSessionId, token).ConfigureAwait(false); | |||||
| await _audioClient.StartAsync(url, Discord.CurrentUser.Id, voiceState.VoiceSessionId, token).ConfigureAwait(false); | |||||
| } | } | ||||
| catch (OperationCanceledException) | catch (OperationCanceledException) | ||||
| { | { | ||||
| @@ -634,6 +636,8 @@ namespace Discord.WebSocket | |||||
| => Task.FromResult<ITextChannel>(GetTextChannel(id)); | => Task.FromResult<ITextChannel>(GetTextChannel(id)); | ||||
| Task<IReadOnlyCollection<IVoiceChannel>> IGuild.GetVoiceChannelsAsync(CacheMode mode, RequestOptions options) | Task<IReadOnlyCollection<IVoiceChannel>> IGuild.GetVoiceChannelsAsync(CacheMode mode, RequestOptions options) | ||||
| => Task.FromResult<IReadOnlyCollection<IVoiceChannel>>(VoiceChannels); | => Task.FromResult<IReadOnlyCollection<IVoiceChannel>>(VoiceChannels); | ||||
| Task<IReadOnlyCollection<IGuildChannelCategory>> IGuild.GetChannelCategoriesAsync(CacheMode mode , RequestOptions options) | |||||
| => Task.FromResult<IReadOnlyCollection<IGuildChannelCategory>>(ChannelCategories); | |||||
| Task<IVoiceChannel> IGuild.GetVoiceChannelAsync(ulong id, CacheMode mode, RequestOptions options) | Task<IVoiceChannel> IGuild.GetVoiceChannelAsync(ulong id, CacheMode mode, RequestOptions options) | ||||
| => Task.FromResult<IVoiceChannel>(GetVoiceChannel(id)); | => Task.FromResult<IVoiceChannel>(GetVoiceChannel(id)); | ||||
| Task<IVoiceChannel> IGuild.GetAFKChannelAsync(CacheMode mode, RequestOptions options) | Task<IVoiceChannel> IGuild.GetAFKChannelAsync(CacheMode mode, RequestOptions options) | ||||