From 5c1a93281cc239a7dc9cd15bff764f52de7bba4d Mon Sep 17 00:00:00 2001 From: CoocooFroggy <45371102+CoocooFroggy@users.noreply.github.com> Date: Mon, 3 Apr 2023 16:17:44 -0400 Subject: [PATCH 01/18] documentation: Guild members --- lib/src/core/guild/guild.dart | 8 ++++---- lib/src/internal/http_endpoints.dart | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/src/core/guild/guild.dart b/lib/src/core/guild/guild.dart index 4881018d7..bacaea2ca 100644 --- a/lib/src/core/guild/guild.dart +++ b/lib/src/core/guild/guild.dart @@ -309,9 +309,9 @@ abstract class IGuild implements SnowflakeEntity { /// Fetches member from API Future fetchMember(Snowflake memberId); - /// Allows to fetch guild members. In future will be restricted with `Privileged Intents`. + /// Allows to fetch guild members. Restricted with [GatewayIntents.guildMembers]. /// [after] is used to continue from specified user id. - /// By default limits to one user - use [limit] parameter to change that behavior. + /// By default limits to one user—use [limit] parameter to change that behavior. Stream fetchMembers({int limit = 1, Snowflake? after}); /// Returns a [Stream] of [Member]s objects whose username or nickname starts with a provided string. @@ -320,7 +320,7 @@ abstract class IGuild implements SnowflakeEntity { /// Returns a [Stream] of [Member]s objects whose username or nickname starts with a provided string. /// By default limits to one entry - can be changed with [limit] parameter. - Stream searchMembersGateway(String query, {int limit = 0}); + Stream searchMembersGateway(String query, {int limit = 1}); /// Fetches guild preview for this guild. Allows to download approx member count in guild Future fetchGuildPreview(); @@ -915,7 +915,7 @@ class Guild extends SnowflakeEntity implements IGuild { /// Returns a [Stream] of [IMember]s objects whose username or nickname starts with a provided string. /// By default limits to one entry - can be changed with [limit] parameter. @override - Stream searchMembersGateway(String query, {int limit = 0}) async* { + Stream searchMembersGateway(String query, {int limit = 1}) async* { final nonce = "$query${id.toString()}"; shard.requestMembers(id, query: query, limit: limit, nonce: nonce); diff --git a/lib/src/internal/http_endpoints.dart b/lib/src/internal/http_endpoints.dart index 475abeed6..fde850838 100644 --- a/lib/src/internal/http_endpoints.dart +++ b/lib/src/internal/http_endpoints.dart @@ -127,7 +127,7 @@ abstract class IHttpEndpoints { /// Returns list of all voice regions that guild has access to Stream fetchGuildVoiceRegions(Snowflake guildId); - /// Moves guild channel in hierachy. + /// Moves guild channel in hierarchy. Future moveGuildChannel(Snowflake guildId, Snowflake channelId, int position, {String? auditReason}); /// Ban user with given id @@ -146,11 +146,13 @@ abstract class IHttpEndpoints { Future fetchGuildMember(Snowflake guildId, Snowflake memberId); /// Fetches list of members from guild. - /// Requires GUILD_MEMBERS intent to work properly. + /// Restricted with [GatewayIntents.guildMembers]. + /// [after] is used to continue from specified user id. + /// By default limits to one user—use [limit] parameter to change that behavior. Stream fetchGuildMembers(Snowflake guildId, {int limit = 1, Snowflake? after}); /// Searches guild for user with [query] parameter - /// Requires GUILD_MEMBERS intent to work properly. + /// Requires [GatewayIntents.guildMembers] intent to work properly. Stream searchGuildMembers(Snowflake guildId, String query, {int limit = 1}); /// Returns all [Webhook]s in given channel From 136cff7c7173360814da801f0ebb5cb11c0af9c0 Mon Sep 17 00:00:00 2001 From: CoocooFroggy <45371102+CoocooFroggy@users.noreply.github.com> Date: Mon, 3 Apr 2023 16:46:55 -0400 Subject: [PATCH 02/18] Revert em dash --- lib/src/internal/http_endpoints.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/internal/http_endpoints.dart b/lib/src/internal/http_endpoints.dart index fde850838..36a5f4b53 100644 --- a/lib/src/internal/http_endpoints.dart +++ b/lib/src/internal/http_endpoints.dart @@ -148,7 +148,7 @@ abstract class IHttpEndpoints { /// Fetches list of members from guild. /// Restricted with [GatewayIntents.guildMembers]. /// [after] is used to continue from specified user id. - /// By default limits to one user—use [limit] parameter to change that behavior. + /// By default limits to one user - use [limit] parameter to change that behavior. Stream fetchGuildMembers(Snowflake guildId, {int limit = 1, Snowflake? after}); /// Searches guild for user with [query] parameter From 341d69d6b49bbdec50a7fe1e509aabd91237297c Mon Sep 17 00:00:00 2001 From: Abitofevrything Date: Mon, 3 Apr 2023 22:50:27 +0200 Subject: [PATCH 03/18] Revert em dash in guild --- lib/src/core/guild/guild.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/core/guild/guild.dart b/lib/src/core/guild/guild.dart index bacaea2ca..315ec1894 100644 --- a/lib/src/core/guild/guild.dart +++ b/lib/src/core/guild/guild.dart @@ -311,7 +311,7 @@ abstract class IGuild implements SnowflakeEntity { /// Allows to fetch guild members. Restricted with [GatewayIntents.guildMembers]. /// [after] is used to continue from specified user id. - /// By default limits to one user—use [limit] parameter to change that behavior. + /// By default limits to one user - use [limit] parameter to change that behavior. Stream fetchMembers({int limit = 1, Snowflake? after}); /// Returns a [Stream] of [Member]s objects whose username or nickname starts with a provided string. From b3fd26f6a7077debf3a13f4f0a402cc89360b11d Mon Sep 17 00:00:00 2001 From: chromium <55208871+chromium122@users.noreply.github.com> Date: Sat, 8 Apr 2023 10:09:45 +0200 Subject: [PATCH 04/18] add videoQualityMode to VoiceChannelBuilder and rateLimitPerUser to TextChannelBuilder --- lib/src/utils/builders/channel_builder.dart | 28 ++++++++++++++++----- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/lib/src/utils/builders/channel_builder.dart b/lib/src/utils/builders/channel_builder.dart index 9d3b9572d..2f48a0a84 100644 --- a/lib/src/utils/builders/channel_builder.dart +++ b/lib/src/utils/builders/channel_builder.dart @@ -49,7 +49,9 @@ abstract class ChannelBuilder implements Builder { if (type != null) "type": type!.value, if (position != null) "position": position, if (parentChannel != null) "parent_id": parentChannel!.id.toString(), - if (permissionOverrides != null) "permission_overwrites": permissionOverrides!.map((e) => e.build()).toList(), + if (permissionOverrides != null) + "permission_overwrites": + permissionOverrides!.map((e) => e.build()).toList(), }; } @@ -72,6 +74,8 @@ class VoiceChannelBuilder extends ChannelBuilder { /// Channel voice region id, automatic when set to null String? rtcRegion = ""; + VideoQualityMode? videoQualityMode; + VoiceChannelBuilder({ super.id, super.name, @@ -82,6 +86,7 @@ class VoiceChannelBuilder extends ChannelBuilder { this.rateLimitPerUser, this.rtcRegion, this.userLimit, + this.videoQualityMode, }) : super._(); @override @@ -91,6 +96,8 @@ class VoiceChannelBuilder extends ChannelBuilder { if (userLimit != null) "user_limit": userLimit, if (rateLimitPerUser != null) "rate_limit_per_user": rateLimitPerUser, if (rtcRegion != "") "rtc_region": rtcRegion, + if (videoQualityMode != null) + "video_quality_mode": videoQualityMode!.value, }; } @@ -108,6 +115,8 @@ class TextChannelBuilder extends ChannelBuilder { VideoQualityMode? videoQualityMode; + int? rateLimitPerUser; + TextChannelBuilder({ super.id, super.name, @@ -116,6 +125,7 @@ class TextChannelBuilder extends ChannelBuilder { super.position, this.nsfw, this.topic, + this.rateLimitPerUser, }) : super._(); factory TextChannelBuilder.create(String name) { final builder = TextChannelBuilder(); @@ -128,7 +138,9 @@ class TextChannelBuilder extends ChannelBuilder { ...super.build(), if (topic != null) "topic": topic, if (nsfw != null) "nsfw": nsfw, - if (videoQualityMode != null) "video_quality_mode": videoQualityMode!.value, + if (videoQualityMode != null) + "video_quality_mode": videoQualityMode!.value, + if (rateLimitPerUser != null) "rate_limit_per_user": rateLimitPerUser, }; } @@ -151,12 +163,16 @@ class ForumChannelBuilder extends TextChannelBuilder { @override RawApiMap build() => { ...super.build(), - if (defaultSortOrder != null) "default_sort_order": defaultSortOrder!.value, + if (defaultSortOrder != null) + "default_sort_order": defaultSortOrder!.value, if (defaultReactionEmoji != null) "default_reaction_emoji": { - if (defaultReactionEmoji is UnicodeEmoji) "emoji_name": defaultReactionEmoji!.encodeForAPI(), - if (defaultReactionEmoji is BaseGuildEmoji) "emoji_id": (defaultReactionEmoji as BaseGuildEmoji).id + if (defaultReactionEmoji is UnicodeEmoji) + "emoji_name": defaultReactionEmoji!.encodeForAPI(), + if (defaultReactionEmoji is BaseGuildEmoji) + "emoji_id": (defaultReactionEmoji as BaseGuildEmoji).id }, - if (availableTags != null) "available_tags": availableTags!.map((e) => e.build()).toList() + if (availableTags != null) + "available_tags": availableTags!.map((e) => e.build()).toList() }; } From 5faa44fc8b8aca967233310024e9c90a82b8be63 Mon Sep 17 00:00:00 2001 From: chromium <55208871+chromium122@users.noreply.github.com> Date: Sat, 8 Apr 2023 10:12:25 +0200 Subject: [PATCH 05/18] deprecate incorrect properties of VoiceChannelBuilder and TextChannelBuilder --- lib/src/utils/builders/channel_builder.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/src/utils/builders/channel_builder.dart b/lib/src/utils/builders/channel_builder.dart index 2f48a0a84..c72b8cddd 100644 --- a/lib/src/utils/builders/channel_builder.dart +++ b/lib/src/utils/builders/channel_builder.dart @@ -69,6 +69,7 @@ class VoiceChannelBuilder extends ChannelBuilder { /// Amount of seconds a user has to wait before sending another message (0-21600); /// bots, as well as users with the permission manage_messages or manage_channel, are unaffected + @Deprecated("Use TextChannelBuilder instead") int? rateLimitPerUser; /// Channel voice region id, automatic when set to null @@ -113,6 +114,7 @@ class TextChannelBuilder extends ChannelBuilder { /// Whether the channel is nsfw bool? nsfw; + @Deprecated("Use VoiceChannelBuilder instead") VideoQualityMode? videoQualityMode; int? rateLimitPerUser; From 7c9add1f63ba2303ce039f65d2d21c58e6453361 Mon Sep 17 00:00:00 2001 From: chromium <55208871+chromium122@users.noreply.github.com> Date: Sat, 8 Apr 2023 10:15:44 +0200 Subject: [PATCH 06/18] formatting --- lib/src/utils/builders/channel_builder.dart | 22 +++++++-------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/lib/src/utils/builders/channel_builder.dart b/lib/src/utils/builders/channel_builder.dart index c72b8cddd..a3544cd74 100644 --- a/lib/src/utils/builders/channel_builder.dart +++ b/lib/src/utils/builders/channel_builder.dart @@ -49,9 +49,7 @@ abstract class ChannelBuilder implements Builder { if (type != null) "type": type!.value, if (position != null) "position": position, if (parentChannel != null) "parent_id": parentChannel!.id.toString(), - if (permissionOverrides != null) - "permission_overwrites": - permissionOverrides!.map((e) => e.build()).toList(), + if (permissionOverrides != null) "permission_overwrites": permissionOverrides!.map((e) => e.build()).toList(), }; } @@ -97,8 +95,7 @@ class VoiceChannelBuilder extends ChannelBuilder { if (userLimit != null) "user_limit": userLimit, if (rateLimitPerUser != null) "rate_limit_per_user": rateLimitPerUser, if (rtcRegion != "") "rtc_region": rtcRegion, - if (videoQualityMode != null) - "video_quality_mode": videoQualityMode!.value, + if (videoQualityMode != null) "video_quality_mode": videoQualityMode!.value, }; } @@ -140,8 +137,7 @@ class TextChannelBuilder extends ChannelBuilder { ...super.build(), if (topic != null) "topic": topic, if (nsfw != null) "nsfw": nsfw, - if (videoQualityMode != null) - "video_quality_mode": videoQualityMode!.value, + if (videoQualityMode != null) "video_quality_mode": videoQualityMode!.value, if (rateLimitPerUser != null) "rate_limit_per_user": rateLimitPerUser, }; } @@ -165,16 +161,12 @@ class ForumChannelBuilder extends TextChannelBuilder { @override RawApiMap build() => { ...super.build(), - if (defaultSortOrder != null) - "default_sort_order": defaultSortOrder!.value, + if (defaultSortOrder != null) "default_sort_order": defaultSortOrder!.value, if (defaultReactionEmoji != null) "default_reaction_emoji": { - if (defaultReactionEmoji is UnicodeEmoji) - "emoji_name": defaultReactionEmoji!.encodeForAPI(), - if (defaultReactionEmoji is BaseGuildEmoji) - "emoji_id": (defaultReactionEmoji as BaseGuildEmoji).id + if (defaultReactionEmoji is UnicodeEmoji) "emoji_name": defaultReactionEmoji!.encodeForAPI(), + if (defaultReactionEmoji is BaseGuildEmoji) "emoji_id": (defaultReactionEmoji as BaseGuildEmoji).id }, - if (availableTags != null) - "available_tags": availableTags!.map((e) => e.build()).toList() + if (availableTags != null) "available_tags": availableTags!.map((e) => e.build()).toList() }; } From e3d8d83d5eeed81e2306bce0f9cba62ded2b370c Mon Sep 17 00:00:00 2001 From: Abitofevrything Date: Sat, 8 Apr 2023 11:21:15 +0200 Subject: [PATCH 07/18] Release 5.0.2 --- CHANGELOG.md | 6 ++++++ lib/src/internal/constants.dart | 2 +- pubspec.yaml | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab6b6b475..bb06d6fdf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 5.0.2 +__08.04.2023__ + +- bug: TextChannelBuilder and VoiceChannel builder had rateLimitPerUser and videoQualityMode swapped (#471) +- documentation: Guild members (#470) + ## 5.0.1 __18.03.2023__ diff --git a/lib/src/internal/constants.dart b/lib/src/internal/constants.dart index 18f793cb5..c43c4be87 100644 --- a/lib/src/internal/constants.dart +++ b/lib/src/internal/constants.dart @@ -33,7 +33,7 @@ class Constants { static const int apiVersion = 10; /// Version of Nyxx - static const String version = "5.0.1"; + static const String version = "5.0.2"; /// Url to Nyxx repo static const String repoUrl = "https://github.com/nyxx-discord/nyxx"; diff --git a/pubspec.yaml b/pubspec.yaml index 33609a066..b436346c8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: nyxx -version: 5.0.1 +version: 5.0.2 description: A Discord library for Dart. Simple, robust framework for creating discord bots for Dart language. homepage: https://github.com/nyxx-discord/nyxx repository: https://github.com/nyxx-discord/nyxx From b9827532c9d83c2cd99efb5003df1f5cb23ef306 Mon Sep 17 00:00:00 2001 From: Abitofevrything Date: Tue, 11 Apr 2023 10:40:34 +0200 Subject: [PATCH 08/18] Initialize guild caches even when guild is not from a create event --- lib/src/core/guild/guild.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/core/guild/guild.dart b/lib/src/core/guild/guild.dart index 315ec1894..f933d42ab 100644 --- a/lib/src/core/guild/guild.dart +++ b/lib/src/core/guild/guild.dart @@ -678,6 +678,9 @@ class Guild extends SnowflakeEntity implements IGuild { for (final rawSticker in raw["stickers"] as RawApiList) GuildSticker(rawSticker as RawApiMap, client) ]; + autoModerationRules = SnowflakeCache(); + scheduledEvents = SnowflakeCache(); + if (!guildCreate) return; raw["channels"].forEach((o) { @@ -722,9 +725,6 @@ class Guild extends SnowflakeEntity implements IGuild { if (raw["stage_instances"] != null) for (final rawInstance in raw["stage_instances"] as RawApiList) StageChannelInstance(client, rawInstance as RawApiMap) ]; - - autoModerationRules = SnowflakeCache(); - scheduledEvents = SnowflakeCache(); } /// The guild's icon, represented as URL. From 3ec76d86b974d8b90dc68ee118e6743f6bb845b1 Mon Sep 17 00:00:00 2001 From: Abitofevrything Date: Tue, 11 Apr 2023 10:43:49 +0200 Subject: [PATCH 09/18] Release 5.0.3 --- CHANGELOG.md | 5 +++++ lib/src/internal/constants.dart | 2 +- pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb06d6fdf..7af6ff3e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 5.0.3 +__11.04.2023__ + +- bug: Always initialize guild caches + ## 5.0.2 __08.04.2023__ diff --git a/lib/src/internal/constants.dart b/lib/src/internal/constants.dart index c43c4be87..5d84b90ec 100644 --- a/lib/src/internal/constants.dart +++ b/lib/src/internal/constants.dart @@ -33,7 +33,7 @@ class Constants { static const int apiVersion = 10; /// Version of Nyxx - static const String version = "5.0.2"; + static const String version = "5.0.3"; /// Url to Nyxx repo static const String repoUrl = "https://github.com/nyxx-discord/nyxx"; diff --git a/pubspec.yaml b/pubspec.yaml index b436346c8..84800e876 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: nyxx -version: 5.0.2 +version: 5.0.3 description: A Discord library for Dart. Simple, robust framework for creating discord bots for Dart language. homepage: https://github.com/nyxx-discord/nyxx repository: https://github.com/nyxx-discord/nyxx From 20c1bc8e4c123f61b07db2091b351ecdb0f9972d Mon Sep 17 00:00:00 2001 From: Ventus <29584664+V3ntus@users.noreply.github.com> Date: Tue, 11 Apr 2023 10:57:27 -0500 Subject: [PATCH 10/18] ref: nullable `animated` for icon/avatar/splash URL properties (#475) feat: animated icon/avatar/splash URL helpers on null --- lib/src/core/guild/guild.dart | 12 ++++++++---- lib/src/core/guild/guild_preview.dart | 6 ++++-- lib/src/core/guild/webhook.dart | 6 ++++-- lib/src/core/user/member.dart | 6 ++++-- lib/src/core/user/user.dart | 10 +++++++--- lib/src/internal/interfaces/message_author.dart | 2 +- 6 files changed, 28 insertions(+), 14 deletions(-) diff --git a/lib/src/core/guild/guild.dart b/lib/src/core/guild/guild.dart index 315ec1894..1962e4ef0 100644 --- a/lib/src/core/guild/guild.dart +++ b/lib/src/core/guild/guild.dart @@ -199,7 +199,7 @@ abstract class IGuild implements SnowflakeEntity { /// The guild's icon, represented as URL. /// If guild doesn't have icon it returns null. - String? iconUrl({String format = 'webp', int? size, bool animated = false}); + String? iconUrl({String format = 'webp', int? size, bool? animated}); /// URL to guild's splash. /// If guild doesn't have splash it returns null. @@ -211,7 +211,7 @@ abstract class IGuild implements SnowflakeEntity { /// URL to guild's banner. /// If guild doesn't have banner it returns null. - String? bannerUrl({String format = 'webp', int? size, bool animated = false}); + String? bannerUrl({String format = 'webp', int? size, bool? animated}); /// Allows to download [IGuild] widget aka advert png /// Possible options for [style]: shield (default), banner1, banner2, banner3, banner4 @@ -730,11 +730,13 @@ class Guild extends SnowflakeEntity implements IGuild { /// The guild's icon, represented as URL. /// If guild doesn't have icon it returns null. @override - String? iconUrl({String format = 'webp', int? size, bool animated = false}) { + String? iconUrl({String format = 'webp', int? size, bool? animated}) { if (icon == null) { return null; } + animated ??= icon?.startsWith("a_") ?? false; + return client.cdnHttpEndpoints.icon(id, icon!, format: format, size: size, animated: animated); } @@ -768,11 +770,13 @@ class Guild extends SnowflakeEntity implements IGuild { /// Returns the URL to guild's banner. /// If guild doesn't have banner it returns null. @override - String? bannerUrl({String format = 'webp', int? size, bool animated = false}) { + String? bannerUrl({String format = 'webp', int? size, bool? animated}) { if (banner == null) { return null; } + animated ??= banner?.startsWith("a_") ?? false; + return client.cdnHttpEndpoints.banner(id, banner!, format: format, size: size, animated: animated); } diff --git a/lib/src/core/guild/guild_preview.dart b/lib/src/core/guild/guild_preview.dart index e0e559e97..4c697d9ed 100644 --- a/lib/src/core/guild/guild_preview.dart +++ b/lib/src/core/guild/guild_preview.dart @@ -38,7 +38,7 @@ abstract class IGuildPreview implements SnowflakeEntity { /// The guild's icon, represented as URL. /// If guild doesn't have icon it returns null. - String? iconUrl({String format = 'webp', int? size, bool animated = false}); + String? iconUrl({String format = 'webp', int? size, bool? animated}); /// URL to guild's splash. /// If guild doesn't have splash it returns null. @@ -115,11 +115,13 @@ class GuildPreview extends SnowflakeEntity implements IGuildPreview { /// The guild's icon, represented as URL. /// If guild doesn't have icon it returns null. @override - String? iconUrl({String format = 'webp', int? size, bool animated = false}) { + String? iconUrl({String format = 'webp', int? size, bool? animated}) { if (iconHash == null) { return null; } + animated ??= iconHash?.startsWith("a_") ?? false; + return client.cdnHttpEndpoints.icon(id, iconHash!, format: format, size: size, animated: animated); } diff --git a/lib/src/core/guild/webhook.dart b/lib/src/core/guild/webhook.dart index 10883d104..86b639206 100644 --- a/lib/src/core/guild/webhook.dart +++ b/lib/src/core/guild/webhook.dart @@ -79,7 +79,7 @@ abstract class IWebhook implements SnowflakeEntity, IMessageAuthor { Future execute(MessageBuilder builder, {bool wait = true, Snowflake? threadId, String? threadName, String? avatarUrl, String? username}); @override - String avatarUrl({String format = 'webp', int? size, bool animated = false}); + String avatarUrl({String format = 'webp', int? size, bool? animated}); /// Edits the webhook. Future edit({String? name, SnowflakeEntity? channel, AttachmentBuilder? avatarAttachment, String? auditReason}); @@ -187,11 +187,13 @@ class Webhook extends SnowflakeEntity implements IWebhook { .executeWebhook(id, builder, token: token, threadId: threadId, username: username, wait: wait, avatarUrl: avatarUrl, threadName: threadName); @override - String avatarUrl({String format = 'webp', int? size, bool animated = false}) { + String avatarUrl({String format = 'webp', int? size, bool? animated}) { if (avatarHash == null) { return client.cdnHttpEndpoints.defaultAvatar(defaultAvatarId); } + animated ??= avatarHash?.startsWith("a_") ?? false; + return client.cdnHttpEndpoints.avatar(id, avatarHash!, format: format, size: size, animated: animated); } diff --git a/lib/src/core/user/member.dart b/lib/src/core/user/member.dart index 24f8ad688..899e7b35f 100644 --- a/lib/src/core/user/member.dart +++ b/lib/src/core/user/member.dart @@ -72,7 +72,7 @@ abstract class IMember implements SnowflakeEntity, Mentionable { /// The member's avatar, represented as URL. With given [format] and [size]. /// If [animated] is set as `true`, if available, the url will be a gif, otherwise the [format] or fallback to "webp". - String? avatarUrl({String format = 'webp', int? size, bool animated = false}); + String? avatarUrl({String format = 'webp', int? size, bool? animated}); /// Bans the member and optionally deletes [deleteMessageDays] days worth of messages. Future ban({int? deleteMessageDays, String? reason, String? auditReason}); @@ -208,11 +208,13 @@ class Member extends SnowflakeEntity implements IMember { /// Returns url to member avatar @override - String? avatarUrl({String format = 'webp', int? size, bool animated = false}) { + String? avatarUrl({String format = 'webp', int? size, bool? animated}) { if (avatarHash == null) { return null; } + animated ??= avatarHash?.startsWith("a_") ?? false; + return client.cdnHttpEndpoints.memberAvatar(guild.id, id, avatarHash!, format: format, size: size, animated: animated); } diff --git a/lib/src/core/user/user.dart b/lib/src/core/user/user.dart index e32b8f016..ee3fd7ea9 100644 --- a/lib/src/core/user/user.dart +++ b/lib/src/core/user/user.dart @@ -52,7 +52,7 @@ abstract class IUser implements SnowflakeEntity, ISend, Mentionable, IMessageAut String? avatarDecorationHash; /// The user's banner url. - String? bannerUrl({String format = 'webp', int? size, bool animated = false}); + String? bannerUrl({String format = 'webp', int? size, bool? animated}); /// The user's avatar decoration url, if any. String? avatarDecorationUrl({int size}); @@ -170,21 +170,25 @@ class User extends SnowflakeEntity implements IUser { /// The user's avatar, represented as URL. /// In case if user does not have avatar, default discord avatar will be returned with specified size and png format. @override - String avatarUrl({String format = 'webp', int? size, bool animated = false}) { + String avatarUrl({String format = 'webp', int? size, bool? animated}) { if (avatar == null) { return client.cdnHttpEndpoints.defaultAvatar(discriminator); } + animated ??= avatar?.startsWith("a_") ?? false; + return client.cdnHttpEndpoints.avatar(id, avatar!, format: format, size: size, animated: animated); } /// The user's banner url. @override - String? bannerUrl({String format = 'webp', int? size, bool animated = false}) { + String? bannerUrl({String format = 'webp', int? size, bool? animated}) { if (bannerHash == null) { return null; } + animated ??= bannerHash?.startsWith("a_") ?? false; + return client.cdnHttpEndpoints.banner(id, bannerHash!, format: format, size: size, animated: animated); } diff --git a/lib/src/internal/interfaces/message_author.dart b/lib/src/internal/interfaces/message_author.dart index b7c9ff35e..609af4d8f 100644 --- a/lib/src/internal/interfaces/message_author.dart +++ b/lib/src/internal/interfaces/message_author.dart @@ -24,5 +24,5 @@ abstract class IMessageAuthor implements SnowflakeEntity { /// The user's avatar, represented as URL. /// In case if user does not have avatar, default discord avatar will be returned; [format], [size] and [animated] will no longer affectng this URL. /// If [animated] is set as `true`, if available, the url will be a gif, otherwise the [format]. - String avatarUrl({String format = 'webp', int? size, bool animated = false}); + String avatarUrl({String format = 'webp', int? size, bool? animated}); } From ce85712fd830e9fc175003052afda124ec0ec3c4 Mon Sep 17 00:00:00 2001 From: Rapougnac <74512338+Rapougnac@users.noreply.github.com> Date: Wed, 12 Apr 2023 06:47:56 +0200 Subject: [PATCH 11/18] Revert #475 (#476) * Revert "ref: nullable `animated` for icon/avatar/splash URL properties (#475)" This reverts commit 20c1bc8e4c123f61b07db2091b351ecdb0f9972d. * fix: remove ifs * Make `true` default value for `animated` prop * [ci skip] fmt --- lib/src/core/application/app_team_user.dart | 2 +- lib/src/core/guild/guild.dart | 12 +++----- lib/src/core/guild/guild_preview.dart | 6 ++-- lib/src/core/guild/webhook.dart | 6 ++-- lib/src/core/message/guild_emoji.dart | 4 +-- lib/src/core/user/member.dart | 6 ++-- lib/src/core/user/user.dart | 10 ++----- lib/src/internal/cdn_http_endpoints.dart | 29 ++++++++----------- .../internal/interfaces/message_author.dart | 2 +- 9 files changed, 29 insertions(+), 48 deletions(-) diff --git a/lib/src/core/application/app_team_user.dart b/lib/src/core/application/app_team_user.dart index a7a75d172..3ac67fc12 100644 --- a/lib/src/core/application/app_team_user.dart +++ b/lib/src/core/application/app_team_user.dart @@ -47,7 +47,7 @@ class AppTeamUser extends SnowflakeEntity implements IAppTeamUser { } @override - String avatarUrl({String format = 'webp', int? size, bool animated = false}) { + String avatarUrl({String format = 'webp', int? size, bool animated = true}) { if (avatar == null) { return client.cdnHttpEndpoints.defaultAvatar(int.tryParse(discriminator) ?? 0); } diff --git a/lib/src/core/guild/guild.dart b/lib/src/core/guild/guild.dart index 1962e4ef0..5a3c2ed0f 100644 --- a/lib/src/core/guild/guild.dart +++ b/lib/src/core/guild/guild.dart @@ -199,7 +199,7 @@ abstract class IGuild implements SnowflakeEntity { /// The guild's icon, represented as URL. /// If guild doesn't have icon it returns null. - String? iconUrl({String format = 'webp', int? size, bool? animated}); + String? iconUrl({String format = 'webp', int? size, bool animated = true}); /// URL to guild's splash. /// If guild doesn't have splash it returns null. @@ -211,7 +211,7 @@ abstract class IGuild implements SnowflakeEntity { /// URL to guild's banner. /// If guild doesn't have banner it returns null. - String? bannerUrl({String format = 'webp', int? size, bool? animated}); + String? bannerUrl({String format = 'webp', int? size, bool animated = true}); /// Allows to download [IGuild] widget aka advert png /// Possible options for [style]: shield (default), banner1, banner2, banner3, banner4 @@ -730,13 +730,11 @@ class Guild extends SnowflakeEntity implements IGuild { /// The guild's icon, represented as URL. /// If guild doesn't have icon it returns null. @override - String? iconUrl({String format = 'webp', int? size, bool? animated}) { + String? iconUrl({String format = 'webp', int? size, bool animated = true}) { if (icon == null) { return null; } - animated ??= icon?.startsWith("a_") ?? false; - return client.cdnHttpEndpoints.icon(id, icon!, format: format, size: size, animated: animated); } @@ -770,13 +768,11 @@ class Guild extends SnowflakeEntity implements IGuild { /// Returns the URL to guild's banner. /// If guild doesn't have banner it returns null. @override - String? bannerUrl({String format = 'webp', int? size, bool? animated}) { + String? bannerUrl({String format = 'webp', int? size, bool animated = true}) { if (banner == null) { return null; } - animated ??= banner?.startsWith("a_") ?? false; - return client.cdnHttpEndpoints.banner(id, banner!, format: format, size: size, animated: animated); } diff --git a/lib/src/core/guild/guild_preview.dart b/lib/src/core/guild/guild_preview.dart index 4c697d9ed..a28021822 100644 --- a/lib/src/core/guild/guild_preview.dart +++ b/lib/src/core/guild/guild_preview.dart @@ -38,7 +38,7 @@ abstract class IGuildPreview implements SnowflakeEntity { /// The guild's icon, represented as URL. /// If guild doesn't have icon it returns null. - String? iconUrl({String format = 'webp', int? size, bool? animated}); + String? iconUrl({String format = 'webp', int? size, bool animated = true}); /// URL to guild's splash. /// If guild doesn't have splash it returns null. @@ -115,13 +115,11 @@ class GuildPreview extends SnowflakeEntity implements IGuildPreview { /// The guild's icon, represented as URL. /// If guild doesn't have icon it returns null. @override - String? iconUrl({String format = 'webp', int? size, bool? animated}) { + String? iconUrl({String format = 'webp', int? size, bool animated = true}) { if (iconHash == null) { return null; } - animated ??= iconHash?.startsWith("a_") ?? false; - return client.cdnHttpEndpoints.icon(id, iconHash!, format: format, size: size, animated: animated); } diff --git a/lib/src/core/guild/webhook.dart b/lib/src/core/guild/webhook.dart index 86b639206..25a17f657 100644 --- a/lib/src/core/guild/webhook.dart +++ b/lib/src/core/guild/webhook.dart @@ -79,7 +79,7 @@ abstract class IWebhook implements SnowflakeEntity, IMessageAuthor { Future execute(MessageBuilder builder, {bool wait = true, Snowflake? threadId, String? threadName, String? avatarUrl, String? username}); @override - String avatarUrl({String format = 'webp', int? size, bool? animated}); + String avatarUrl({String format = 'webp', int? size, bool animated = true}); /// Edits the webhook. Future edit({String? name, SnowflakeEntity? channel, AttachmentBuilder? avatarAttachment, String? auditReason}); @@ -187,13 +187,11 @@ class Webhook extends SnowflakeEntity implements IWebhook { .executeWebhook(id, builder, token: token, threadId: threadId, username: username, wait: wait, avatarUrl: avatarUrl, threadName: threadName); @override - String avatarUrl({String format = 'webp', int? size, bool? animated}) { + String avatarUrl({String format = 'webp', int? size, bool animated = true}) { if (avatarHash == null) { return client.cdnHttpEndpoints.defaultAvatar(defaultAvatarId); } - animated ??= avatarHash?.startsWith("a_") ?? false; - return client.cdnHttpEndpoints.avatar(id, avatarHash!, format: format, size: size, animated: animated); } diff --git a/lib/src/core/message/guild_emoji.dart b/lib/src/core/message/guild_emoji.dart index f85200960..1e46a153e 100644 --- a/lib/src/core/message/guild_emoji.dart +++ b/lib/src/core/message/guild_emoji.dart @@ -26,7 +26,7 @@ abstract class IBaseGuildEmoji implements SnowflakeEntity, IEmoji { /// Returns the CDN URL for this emoji with given [format] and [size]. /// If [animated] is set as `true`, an animated version of the emoji (if applicable) will be displayed. - String cdnUrl({String format = 'webp', int? size, bool animated = false}); + String cdnUrl({String format = 'webp', int? size, bool animated = true}); } abstract class BaseGuildEmoji extends SnowflakeEntity implements IBaseGuildEmoji { @@ -50,7 +50,7 @@ abstract class BaseGuildEmoji extends SnowflakeEntity implements IBaseGuildEmoji /// Returns cdn url to emoji @override - String cdnUrl({String format = 'webp', int? size, bool animated = false}) { + String cdnUrl({String format = 'webp', int? size, bool animated = true}) { return client.cdnHttpEndpoints.emoji(id, format: this.animated && animated ? 'gif' : format, size: size); } diff --git a/lib/src/core/user/member.dart b/lib/src/core/user/member.dart index 899e7b35f..74ba19d51 100644 --- a/lib/src/core/user/member.dart +++ b/lib/src/core/user/member.dart @@ -72,7 +72,7 @@ abstract class IMember implements SnowflakeEntity, Mentionable { /// The member's avatar, represented as URL. With given [format] and [size]. /// If [animated] is set as `true`, if available, the url will be a gif, otherwise the [format] or fallback to "webp". - String? avatarUrl({String format = 'webp', int? size, bool? animated}); + String? avatarUrl({String format = 'webp', int? size, bool animated = true}); /// Bans the member and optionally deletes [deleteMessageDays] days worth of messages. Future ban({int? deleteMessageDays, String? reason, String? auditReason}); @@ -208,13 +208,11 @@ class Member extends SnowflakeEntity implements IMember { /// Returns url to member avatar @override - String? avatarUrl({String format = 'webp', int? size, bool? animated}) { + String? avatarUrl({String format = 'webp', int? size, bool animated = true}) { if (avatarHash == null) { return null; } - animated ??= avatarHash?.startsWith("a_") ?? false; - return client.cdnHttpEndpoints.memberAvatar(guild.id, id, avatarHash!, format: format, size: size, animated: animated); } diff --git a/lib/src/core/user/user.dart b/lib/src/core/user/user.dart index ee3fd7ea9..78bd829f4 100644 --- a/lib/src/core/user/user.dart +++ b/lib/src/core/user/user.dart @@ -52,7 +52,7 @@ abstract class IUser implements SnowflakeEntity, ISend, Mentionable, IMessageAut String? avatarDecorationHash; /// The user's banner url. - String? bannerUrl({String format = 'webp', int? size, bool? animated}); + String? bannerUrl({String format = 'webp', int? size, bool animated = true}); /// The user's avatar decoration url, if any. String? avatarDecorationUrl({int size}); @@ -170,25 +170,21 @@ class User extends SnowflakeEntity implements IUser { /// The user's avatar, represented as URL. /// In case if user does not have avatar, default discord avatar will be returned with specified size and png format. @override - String avatarUrl({String format = 'webp', int? size, bool? animated}) { + String avatarUrl({String format = 'webp', int? size, bool animated = true}) { if (avatar == null) { return client.cdnHttpEndpoints.defaultAvatar(discriminator); } - animated ??= avatar?.startsWith("a_") ?? false; - return client.cdnHttpEndpoints.avatar(id, avatar!, format: format, size: size, animated: animated); } /// The user's banner url. @override - String? bannerUrl({String format = 'webp', int? size, bool? animated}) { + String? bannerUrl({String format = 'webp', int? size, bool animated = true}) { if (bannerHash == null) { return null; } - animated ??= bannerHash?.startsWith("a_") ?? false; - return client.cdnHttpEndpoints.banner(id, bannerHash!, format: format, size: size, animated: animated); } diff --git a/lib/src/internal/cdn_http_endpoints.dart b/lib/src/internal/cdn_http_endpoints.dart index 02420899d..c33684d8d 100644 --- a/lib/src/internal/cdn_http_endpoints.dart +++ b/lib/src/internal/cdn_http_endpoints.dart @@ -19,11 +19,11 @@ abstract class ICdnHttpEndpoints { /// Returns URL to ``/avatars/[avatarHash]``. /// With given [format], [size] and whether or not returns the animated version (if applicable) of this URL with [animated]. - String avatar(Snowflake id, String avatarHash, {String format = 'webp', int? size, bool animated = false}); + String avatar(Snowflake id, String avatarHash, {String format = 'webp', int? size, bool animated = true}); /// Returns URL to ``/banners/[bannerHash]``. /// With given [format], [size] and whether or not returns the animated version (if applicable) of this URL with [animated]. - String banner(Snowflake guildOrUserId, String hash, {String format = 'webp', int? size, bool animated = false}); + String banner(Snowflake guildOrUserId, String hash, {String format = 'webp', int? size, bool animated = true}); /// Returns URL to ``/channel-icons/[iconHash]``. /// With given [format] and [size]. @@ -49,11 +49,11 @@ abstract class ICdnHttpEndpoints { /// Returns URL to ``/guilds/[guildId]/users/[userId]/[avatarHash]``. /// With given [format], [size] and whether or not returns the animated version (if applicable) of this URL with [animated]. - String memberAvatar(Snowflake guildId, Snowflake userId, String avatarHash, {String format = 'webp', int? size, bool animated = false}); + String memberAvatar(Snowflake guildId, Snowflake userId, String avatarHash, {String format = 'webp', int? size, bool animated = true}); /// Returns URL tp ``/icons/[iconHash]``. /// With given [format], [size] and whether or not returns the animated version (if applicable) of this URL with [animated]. - String icon(Snowflake id, String iconHash, {String format = 'webp', int? size, bool animated = false}); + String icon(Snowflake id, String iconHash, {String format = 'webp', int? size, bool animated = true}); /// Returns URL to ``/role-icons/[roleIconHash]``. /// With given [format] and [size]. @@ -85,17 +85,13 @@ abstract class ICdnHttpEndpoints { } class CdnHttpEndpoints implements ICdnHttpEndpoints { - String _makeAnimatedCdnUrl(ICdnHttpRoute fragment, String hash, {String format = 'webp', int? size, bool animated = false}) { - if (hash.startsWith('a_') && animated) { - animated = true; - } else { - animated = false; - } + String _makeAnimatedCdnUrl(ICdnHttpRoute fragment, String hash, {String format = 'webp', int? size, bool animated = true}) { + final isAnimated = animated && hash.startsWith('a_'); - return _makeCdnUrl(fragment, format: format, size: size, animated: animated); + return _makeCdnUrl(fragment, format: format, size: size, animated: isAnimated); } - String _makeCdnUrl(ICdnHttpRoute fragments, {String format = 'webp', int? size, bool animated = false}) { + String _makeCdnUrl(ICdnHttpRoute fragments, {String format = 'webp', int? size, bool animated = true}) { if (!CdnConstants.allowedExtensions.contains(format)) { throw Exception('Invalid extension provided, must be one of ${CdnConstants.allowedExtensions.and()}; given: $format'); } @@ -136,7 +132,7 @@ class CdnHttpEndpoints implements ICdnHttpEndpoints { ); @override - String avatar(Snowflake id, String avatarHash, {String format = 'webp', int? size, bool animated = false}) => _makeAnimatedCdnUrl( + String avatar(Snowflake id, String avatarHash, {String format = 'webp', int? size, bool animated = true}) => _makeAnimatedCdnUrl( ICdnHttpRoute() ..avatars(id: id.toString()) ..addHash(hash: avatarHash), @@ -147,7 +143,7 @@ class CdnHttpEndpoints implements ICdnHttpEndpoints { ); @override - String banner(Snowflake guildOrUserId, String hash, {String format = 'webp', int? size, bool animated = false}) => _makeAnimatedCdnUrl( + String banner(Snowflake guildOrUserId, String hash, {String format = 'webp', int? size, bool animated = true}) => _makeAnimatedCdnUrl( ICdnHttpRoute() ..banners(id: guildOrUserId.toString()) ..addHash(hash: hash), @@ -185,8 +181,7 @@ class CdnHttpEndpoints implements ICdnHttpEndpoints { ); @override - String memberAvatar(Snowflake guildId, Snowflake userId, String avatarHash, {String format = 'webp', int? size, bool animated = false}) => - _makeAnimatedCdnUrl( + String memberAvatar(Snowflake guildId, Snowflake userId, String avatarHash, {String format = 'webp', int? size, bool animated = true}) => _makeAnimatedCdnUrl( ICdnHttpRoute() ..guilds(id: guildId.toString()) ..users(id: userId.toString()) @@ -202,7 +197,7 @@ class CdnHttpEndpoints implements ICdnHttpEndpoints { _makeCdnUrl(ICdnHttpRoute()..emojis(id: emojiId.toString()), format: format, size: size); @override - String icon(Snowflake id, String iconHash, {String format = 'webp', int? size, bool animated = false}) => _makeAnimatedCdnUrl( + String icon(Snowflake id, String iconHash, {String format = 'webp', int? size, bool animated = true}) => _makeAnimatedCdnUrl( ICdnHttpRoute() ..icons(id: id.toString()) ..addHash(hash: iconHash), diff --git a/lib/src/internal/interfaces/message_author.dart b/lib/src/internal/interfaces/message_author.dart index 609af4d8f..805aa791b 100644 --- a/lib/src/internal/interfaces/message_author.dart +++ b/lib/src/internal/interfaces/message_author.dart @@ -24,5 +24,5 @@ abstract class IMessageAuthor implements SnowflakeEntity { /// The user's avatar, represented as URL. /// In case if user does not have avatar, default discord avatar will be returned; [format], [size] and [animated] will no longer affectng this URL. /// If [animated] is set as `true`, if available, the url will be a gif, otherwise the [format]. - String avatarUrl({String format = 'webp', int? size, bool? animated}); + String avatarUrl({String format = 'webp', int? size, bool animated = true}); } From 37c432a3c1dd719984d89e54da4995806fb0db3f Mon Sep 17 00:00:00 2001 From: Abitofevrything <54505189+abitofevrything@users.noreply.github.com> Date: Sun, 4 Jun 2023 10:45:35 +0200 Subject: [PATCH 12/18] Fix invalid casts when fetching channels from cache (#483) * ref: nullable `animated` for icon/avatar/splash URL properties (#475) feat: animated icon/avatar/splash URL helpers on null * Revert #475 (#476) * Revert "ref: nullable `animated` for icon/avatar/splash URL properties (#475)" This reverts commit 20c1bc8e4c123f61b07db2091b351ecdb0f9972d. * fix: remove ifs * Make `true` default value for `animated` prop * [ci skip] fmt * Fix invalid casts * Release 5.0.4 * Default animated to false for CDN urls * Format files --------- Co-authored-by: Ventus <29584664+V3ntus@users.noreply.github.com> Co-authored-by: Rapougnac <74512338+Rapougnac@users.noreply.github.com> --- CHANGELOG.md | 5 +++++ lib/src/core/channel/cacheable_text_channel.dart | 10 +++++++++- lib/src/core/user/user.dart | 2 +- lib/src/internal/cache/cacheable.dart | 10 +++++++++- lib/src/internal/cdn_http_endpoints.dart | 8 ++------ lib/src/internal/constants.dart | 2 +- pubspec.yaml | 2 +- 7 files changed, 28 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7af6ff3e4..6bd0c3bda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 5.0.4 +__04.06.2023__ + +- bug: Fix invalid casts + ## 5.0.3 __11.04.2023__ diff --git a/lib/src/core/channel/cacheable_text_channel.dart b/lib/src/core/channel/cacheable_text_channel.dart index 30e1bd5b4..d49f8ce74 100644 --- a/lib/src/core/channel/cacheable_text_channel.dart +++ b/lib/src/core/channel/cacheable_text_channel.dart @@ -23,7 +23,15 @@ class CacheableTextChannel extends Channel implements IC CacheableTextChannel(INyxx client, Snowflake id, [ChannelType type = ChannelType.unknown]) : super.raw(client, id, type); @override - S? getFromCache() => client.channels[id] as S?; + S? getFromCache() { + final cached = client.channels[id]; + + if (cached is S) { + return cached; + } + + return null; + } @override Future download() => client.httpEndpoints.fetchChannel(id); diff --git a/lib/src/core/user/user.dart b/lib/src/core/user/user.dart index e32b8f016..88222adbb 100644 --- a/lib/src/core/user/user.dart +++ b/lib/src/core/user/user.dart @@ -161,7 +161,7 @@ class User extends SnowflakeEntity implements IUser { @override FutureOr get dmChannel { try { - return client.channels.values.firstWhere((item) => item is IDMChannel && item.participants.contains(this)) as Future; + return client.channels.values.firstWhere((item) => item is IDMChannel && item.participants.contains(this)) as IDMChannel; } on StateError { return client.httpEndpoints.createDMChannel(id); } diff --git a/lib/src/internal/cache/cacheable.dart b/lib/src/internal/cache/cacheable.dart index 14b5fa6e6..bd113b37c 100644 --- a/lib/src/internal/cache/cacheable.dart +++ b/lib/src/internal/cache/cacheable.dart @@ -91,7 +91,15 @@ class ChannelCacheable extends Cacheable { ChannelCacheable(INyxx client, Snowflake id) : super(client, id); @override - T? getFromCache() => client.channels[id] as T?; + T? getFromCache() { + final cached = client.channels[id]; + + if (cached is T) { + return cached; + } + + return null; + } @override Future download() => client.httpEndpoints.fetchChannel(id); diff --git a/lib/src/internal/cdn_http_endpoints.dart b/lib/src/internal/cdn_http_endpoints.dart index 02420899d..1818943e6 100644 --- a/lib/src/internal/cdn_http_endpoints.dart +++ b/lib/src/internal/cdn_http_endpoints.dart @@ -86,13 +86,9 @@ abstract class ICdnHttpEndpoints { class CdnHttpEndpoints implements ICdnHttpEndpoints { String _makeAnimatedCdnUrl(ICdnHttpRoute fragment, String hash, {String format = 'webp', int? size, bool animated = false}) { - if (hash.startsWith('a_') && animated) { - animated = true; - } else { - animated = false; - } + final isAnimated = animated && hash.startsWith('a_'); - return _makeCdnUrl(fragment, format: format, size: size, animated: animated); + return _makeCdnUrl(fragment, format: format, size: size, animated: isAnimated); } String _makeCdnUrl(ICdnHttpRoute fragments, {String format = 'webp', int? size, bool animated = false}) { diff --git a/lib/src/internal/constants.dart b/lib/src/internal/constants.dart index 5d84b90ec..d7b410176 100644 --- a/lib/src/internal/constants.dart +++ b/lib/src/internal/constants.dart @@ -33,7 +33,7 @@ class Constants { static const int apiVersion = 10; /// Version of Nyxx - static const String version = "5.0.3"; + static const String version = "5.0.4"; /// Url to Nyxx repo static const String repoUrl = "https://github.com/nyxx-discord/nyxx"; diff --git a/pubspec.yaml b/pubspec.yaml index 84800e876..1c69671ac 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: nyxx -version: 5.0.3 +version: 5.0.4 description: A Discord library for Dart. Simple, robust framework for creating discord bots for Dart language. homepage: https://github.com/nyxx-discord/nyxx repository: https://github.com/nyxx-discord/nyxx From 9e7b2e89d5b29b1bed241dab9f458a2f3526f781 Mon Sep 17 00:00:00 2001 From: Rapougnac <74512338+Rapougnac@users.noreply.github.com> Date: Fri, 16 Jun 2023 21:47:53 +0200 Subject: [PATCH 13/18] feat: new username system (#497) * feat: new username system * Bad idea to put true animated here * new release * fix test * new release fix test Release 5.1.0 --- CHANGELOG.md | 6 +++++ lib/src/core/application/app_team_user.dart | 2 +- lib/src/core/guild/webhook.dart | 2 +- lib/src/core/user/user.dart | 21 ++++++++++++---- lib/src/internal/cdn_http_endpoints.dart | 28 +++++++++++++-------- lib/src/internal/constants.dart | 2 +- pubspec.yaml | 2 +- test/integration/integration.dart | 2 +- 8 files changed, 44 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bd0c3bda..ab92cb91f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 5.1.0 +__16.06.2023__ + +- feature: Support the new unique username system with global display names. +- bug: remove the `!` in the mention string as it has been deprecated. + ## 5.0.4 __04.06.2023__ diff --git a/lib/src/core/application/app_team_user.dart b/lib/src/core/application/app_team_user.dart index a7a75d172..a02897a95 100644 --- a/lib/src/core/application/app_team_user.dart +++ b/lib/src/core/application/app_team_user.dart @@ -49,7 +49,7 @@ class AppTeamUser extends SnowflakeEntity implements IAppTeamUser { @override String avatarUrl({String format = 'webp', int? size, bool animated = false}) { if (avatar == null) { - return client.cdnHttpEndpoints.defaultAvatar(int.tryParse(discriminator) ?? 0); + return client.cdnHttpEndpoints.defaultAvatar(int.tryParse(discriminator) ?? 0, id.id); } return client.cdnHttpEndpoints.avatar(id, avatar!, format: format, size: size, animated: animated); diff --git a/lib/src/core/guild/webhook.dart b/lib/src/core/guild/webhook.dart index 10883d104..1570c34cc 100644 --- a/lib/src/core/guild/webhook.dart +++ b/lib/src/core/guild/webhook.dart @@ -189,7 +189,7 @@ class Webhook extends SnowflakeEntity implements IWebhook { @override String avatarUrl({String format = 'webp', int? size, bool animated = false}) { if (avatarHash == null) { - return client.cdnHttpEndpoints.defaultAvatar(defaultAvatarId); + return client.cdnHttpEndpoints.defaultAvatar(defaultAvatarId, id.id); } return client.cdnHttpEndpoints.avatar(id, avatarHash!, format: format, size: size, animated: animated); diff --git a/lib/src/core/user/user.dart b/lib/src/core/user/user.dart index 88222adbb..2d2219390 100644 --- a/lib/src/core/user/user.dart +++ b/lib/src/core/user/user.dart @@ -49,7 +49,10 @@ abstract class IUser implements SnowflakeEntity, ISend, Mentionable, IMessageAut FutureOr get dmChannel; /// The hash of the user's avatar decoration. - String? avatarDecorationHash; + String? get avatarDecorationHash; + + /// The user's display name, if it set. + String? get globalName; /// The user's banner url. String? bannerUrl({String format = 'webp', int? size, bool animated = false}); @@ -82,11 +85,15 @@ class User extends SnowflakeEntity implements IUser { /// The string to mention the user. @override - String get mention => "<@!$id>"; + String get mention => "<@$id>"; - /// Returns String with username#discriminator + /// Returns the complete username of user with discriminator for non-migrated users on the new username system (e.g. `Username#0001`). + /// For migrated users it returns the global name if it's set, otherwise it returns the username. @override - String get tag => "$username#$formattedDiscriminator"; + String get tag { + final isPomelo = discriminator == 0; + return isPomelo ? (globalName ?? username) : "$username#$formattedDiscriminator"; + } /// Whether the user belongs to an OAuth2 application @override @@ -127,6 +134,9 @@ class User extends SnowflakeEntity implements IUser { @override late final String? avatarDecorationHash; + @override + late final String? globalName; + /// Creates an instance of [User] User(this.client, RawApiMap raw) : super(Snowflake(raw["id"])) { username = raw["username"] as String; @@ -134,6 +144,7 @@ class User extends SnowflakeEntity implements IUser { avatar = raw["avatar"] as String?; bot = raw["bot"] as bool? ?? false; system = raw["system"] as bool? ?? false; + globalName = raw["global_name"] as String?; if (raw["public_flags"] != null) { userFlags = UserFlags(raw["public_flags"] as int); @@ -172,7 +183,7 @@ class User extends SnowflakeEntity implements IUser { @override String avatarUrl({String format = 'webp', int? size, bool animated = false}) { if (avatar == null) { - return client.cdnHttpEndpoints.defaultAvatar(discriminator); + return client.cdnHttpEndpoints.defaultAvatar(discriminator, id.id); } return client.cdnHttpEndpoints.avatar(id, avatar!, format: format, size: size, animated: animated); diff --git a/lib/src/internal/cdn_http_endpoints.dart b/lib/src/internal/cdn_http_endpoints.dart index 1818943e6..c5d1eab20 100644 --- a/lib/src/internal/cdn_http_endpoints.dart +++ b/lib/src/internal/cdn_http_endpoints.dart @@ -29,15 +29,16 @@ abstract class ICdnHttpEndpoints { /// With given [format] and [size]. String channelIcon(Snowflake channelId, String iconHash, {String format = 'webp', int? size}); - /// Returns URL to ``/embed/avatars/[discriminator]``. + /// Returns URL to ``/embed/avatars/{index}``. /// - /// The [discriminator] is passed as modulo 5 (`% 5`); and will lead to 0,1,2,3,4. (There's 5, but 5 modulo 5 will never give 5). + /// For non-migrated users to the new username system, the [discriminator] is passed as modulo 5 (`% 5`); and will lead to 0,1,2,3,4. (There's 5, but 5 modulo 5 will never give 5). + /// For migrated users, the [id] is passed and is left shifted by 22 bits and then the result is modulo 6 (`% 6`). (For pink avatar). /// /// E.g: /// ```dart - /// client.cdnHttpEndpoints.defaultAvatar(6712); // https://cdn.discordapp.com/embed/avatars/2.png + /// client.cdnHttpEndpoints.defaultAvatar(6712, 123456789123456789); // https://cdn.discordapp.com/embed/avatars/2.png /// ``` - String defaultAvatar(int discriminator); + String defaultAvatar(int discriminator, int id); /// Returns URL to ``/emojis/[emojiId]``. /// With given [format] and [size]. @@ -163,13 +164,18 @@ class CdnHttpEndpoints implements ICdnHttpEndpoints { ); @override - String defaultAvatar(int discriminator) => _makeCdnUrl( - ICdnHttpRoute() - ..embed() - ..avatars() - ..addHash(hash: (discriminator % 5).toString()), - format: 'png', - ); + // TODO: Remove [discriminator] once migration is done? + String defaultAvatar(int discriminator, int id) { + final isPomelo = discriminator == 0; + final index = isPomelo ? (id >> 22) % 6 : discriminator % 5; + + return _makeCdnUrl( + ICdnHttpRoute() + ..embed() + ..avatars(id: index.toString()), + format: 'png', + ); + } @override String discoverySplash(Snowflake guildId, String splashHash, {String format = 'webp', int? size}) => _makeCdnUrl( diff --git a/lib/src/internal/constants.dart b/lib/src/internal/constants.dart index d7b410176..df6cce36c 100644 --- a/lib/src/internal/constants.dart +++ b/lib/src/internal/constants.dart @@ -33,7 +33,7 @@ class Constants { static const int apiVersion = 10; /// Version of Nyxx - static const String version = "5.0.4"; + static const String version = "5.1.0"; /// Url to Nyxx repo static const String repoUrl = "https://github.com/nyxx-discord/nyxx"; diff --git a/pubspec.yaml b/pubspec.yaml index 1c69671ac..08ab7b4cd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: nyxx -version: 5.0.4 +version: 5.1.0 description: A Discord library for Dart. Simple, robust framework for creating discord bots for Dart language. homepage: https://github.com/nyxx-discord/nyxx repository: https://github.com/nyxx-discord/nyxx diff --git a/test/integration/integration.dart b/test/integration/integration.dart index d4428c3a4..98f028a50 100644 --- a/test/integration/integration.dart +++ b/test/integration/integration.dart @@ -138,7 +138,7 @@ main() async { expect(userBot.discriminator, equals(1759)); expect(userBot.formattedDiscriminator, equals("1759")); expect(userBot.bot, isTrue); - expect(userBot.mention, "<@!${testUserBotSnowflake.toString()}>"); + expect(userBot.mention, "<@${testUserBotSnowflake.toString()}>"); expect(userBot.tag, equals("Running on Dart#1759")); expect(userBot.avatarUrl(), equals('https://cdn.discordapp.com/avatars/476603965396746242/be6107505d7b9d15292da4e54d88836e.webp')); }); From c7d1fa5f482ba9b9b97ab5210789b232b2348256 Mon Sep 17 00:00:00 2001 From: Szymon Uglis Date: Fri, 11 Aug 2023 22:30:38 +0200 Subject: [PATCH 14/18] bug: Error on ThreadMemberUpdateEvent due invalid event deserialization --- lib/src/events/thread_members_update_event.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/src/events/thread_members_update_event.dart b/lib/src/events/thread_members_update_event.dart index 6518adb3f..93cff4983 100644 --- a/lib/src/events/thread_members_update_event.dart +++ b/lib/src/events/thread_members_update_event.dart @@ -77,10 +77,12 @@ class ThreadMemberUpdateEvent implements IThreadMemberUpdateEvent { late final ThreadMember member; ThreadMemberUpdateEvent(RawApiMap raw, INyxx client) { + final data = raw["d"] as RawApiMap; + member = ThreadMember( client, - raw, - GuildCacheable(client, Snowflake(raw['guild_id'])), + data, + GuildCacheable(client, Snowflake(data['guild_id'])), ); } } From fc6537c4df038e5e1a25fe5af557344871481d52 Mon Sep 17 00:00:00 2001 From: Szymon Uglis Date: Fri, 11 Aug 2023 22:31:20 +0200 Subject: [PATCH 15/18] changelog/5.1.1 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab92cb91f..672e5e677 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 5.1.1 +__11.08.2023__ + +- bug: Error on ThreadMemberUpdateEvent due invalid event deserialization + ## 5.1.0 __16.06.2023__ From 6b634bfaaf52257ecaf9ac70828c8cd8f1862f86 Mon Sep 17 00:00:00 2001 From: Szymon Uglis Date: Fri, 11 Aug 2023 22:36:04 +0200 Subject: [PATCH 16/18] maintenance: Fix tests --- lib/src/internal/cdn_http_endpoints.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/internal/cdn_http_endpoints.dart b/lib/src/internal/cdn_http_endpoints.dart index 788c6a102..6ad8cc9ca 100644 --- a/lib/src/internal/cdn_http_endpoints.dart +++ b/lib/src/internal/cdn_http_endpoints.dart @@ -86,7 +86,7 @@ abstract class ICdnHttpEndpoints { } class CdnHttpEndpoints implements ICdnHttpEndpoints { - String _makeAnimatedCdnUrl(ICdnHttpRoute fragment, String hash, {String format = 'webp', int? size, bool animated = true}) { + String _makeAnimatedCdnUrl(ICdnHttpRoute fragment, String hash, {String format = 'webp', int? size, bool animated = false}) { final isAnimated = animated && hash.startsWith('a_'); return _makeCdnUrl(fragment, format: format, size: size, animated: isAnimated); From 0d5fd336d9e7efb905e1675b6031517e863b1346 Mon Sep 17 00:00:00 2001 From: Szymon Uglis Date: Fri, 11 Aug 2023 22:43:54 +0200 Subject: [PATCH 17/18] maintenance: Fix tests --- lib/src/internal/cdn_http_endpoints.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/internal/cdn_http_endpoints.dart b/lib/src/internal/cdn_http_endpoints.dart index 6ad8cc9ca..0ef0caf49 100644 --- a/lib/src/internal/cdn_http_endpoints.dart +++ b/lib/src/internal/cdn_http_endpoints.dart @@ -86,13 +86,13 @@ abstract class ICdnHttpEndpoints { } class CdnHttpEndpoints implements ICdnHttpEndpoints { - String _makeAnimatedCdnUrl(ICdnHttpRoute fragment, String hash, {String format = 'webp', int? size, bool animated = false}) { + String _makeAnimatedCdnUrl(ICdnHttpRoute fragment, String hash, {String format = 'webp', int? size, bool animated = true}) { final isAnimated = animated && hash.startsWith('a_'); return _makeCdnUrl(fragment, format: format, size: size, animated: isAnimated); } - String _makeCdnUrl(ICdnHttpRoute fragments, {String format = 'webp', int? size, bool animated = true}) { + String _makeCdnUrl(ICdnHttpRoute fragments, {String format = 'webp', int? size, bool animated = false}) { if (!CdnConstants.allowedExtensions.contains(format)) { throw Exception('Invalid extension provided, must be one of ${CdnConstants.allowedExtensions.and()}; given: $format'); } From a928e2b38a007695e5916eb68e50ae3f53160894 Mon Sep 17 00:00:00 2001 From: Szymon Uglis Date: Fri, 11 Aug 2023 22:51:06 +0200 Subject: [PATCH 18/18] Release 5.1.1 --- lib/src/internal/constants.dart | 2 +- pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/internal/constants.dart b/lib/src/internal/constants.dart index df6cce36c..5e7a2d61a 100644 --- a/lib/src/internal/constants.dart +++ b/lib/src/internal/constants.dart @@ -33,7 +33,7 @@ class Constants { static const int apiVersion = 10; /// Version of Nyxx - static const String version = "5.1.0"; + static const String version = "5.1.1"; /// Url to Nyxx repo static const String repoUrl = "https://github.com/nyxx-discord/nyxx"; diff --git a/pubspec.yaml b/pubspec.yaml index 08ab7b4cd..9bcf0cbbb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: nyxx -version: 5.1.0 +version: 5.1.1 description: A Discord library for Dart. Simple, robust framework for creating discord bots for Dart language. homepage: https://github.com/nyxx-discord/nyxx repository: https://github.com/nyxx-discord/nyxx