Docs fixes and additions. Code structure fixes, optimizations
[ci skip]
This commit is contained in:
parent
b7b8f6167e
commit
c60864fab4
|
@ -15,7 +15,7 @@ class CommandContext {
|
|||
Guild? guild;
|
||||
|
||||
/// Returns author as guild member
|
||||
Member? get member => guild?.members[author!.id];
|
||||
IMember? get member => guild?.members[author!.id];
|
||||
|
||||
CommandContext._new(this.channel, this.author, this.guild, this.message);
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ class Commander {
|
|||
|
||||
Future<void> _handleMessage(MessageReceivedEvent event) async {
|
||||
/// TODO: Cache
|
||||
final context = CommandContext._new(event.message.channel!, event.message.author,
|
||||
final context = CommandContext._new(event.message.channel, event.message.author,
|
||||
event.message is GuildMessage ? (event.message as GuildMessage).guild : null, event.message);
|
||||
|
||||
final prefix = await _prefixHandler(context, event.message.content);
|
||||
|
|
|
@ -10,7 +10,7 @@ documentation: https://github.com/l7ssha/nyxx/wiki
|
|||
issue_tracker: https://github.com/l7ssha/nyxx/issue
|
||||
|
||||
environment:
|
||||
sdk: '>=2.9.0-2.0.dev <3.0.0'
|
||||
sdk: '>=2.9.0-10.0.dev <3.0.0'
|
||||
|
||||
dependencies:
|
||||
nyxx: "^1.0.0"
|
||||
|
|
|
@ -11,17 +11,17 @@ void main() {
|
|||
|
||||
bot.onMessageReceived.listen((event) async {
|
||||
if (event.message.content == "Test 1") {
|
||||
event.message.delete();
|
||||
event.message.delete(); // ignore: unawaited_futures
|
||||
}
|
||||
|
||||
if (event.message.content == "Test 2") {
|
||||
event.message.delete();
|
||||
event.message.delete(); // ignore: unawaited_futures
|
||||
}
|
||||
|
||||
if (event.message.content == "Test 10") {
|
||||
await event.message.delete();
|
||||
|
||||
await event.message.channel?.send(content: "Commander tests completed sucessfuly!");
|
||||
await event.message.channel.send(content: "Commander tests completed sucessfuly!");
|
||||
exit(0);
|
||||
}
|
||||
});
|
||||
|
@ -32,13 +32,13 @@ void main() {
|
|||
await channel.send(content: "Testing Commander");
|
||||
|
||||
final msg1 = await channel.send(content: "test>test1");
|
||||
msg1.delete();
|
||||
msg1.delete(); // ignore: unawaited_futures
|
||||
|
||||
final msg2 = await channel.send(content: "test>test2 arg1");
|
||||
msg2.delete();
|
||||
msg2.delete(); // ignore: unawaited_futures
|
||||
|
||||
final msg3 = await channel.send(content: "test>test3");
|
||||
msg3.delete();
|
||||
msg3.delete(); // ignore: unawaited_futures
|
||||
});
|
||||
|
||||
Commander(bot, prefix: "test>", beforeCommandHandler: (context, message) async {
|
||||
|
|
|
@ -12,7 +12,7 @@ Future<Map<Emoji, int>> createPoll(CachelessTextChannel channel, String title, M
|
|||
String? message,
|
||||
bool delete = false,
|
||||
dynamic Function(Map<Emoji, String> options, String message)? messageFactory}) async {
|
||||
var toSend;
|
||||
dynamic toSend;
|
||||
|
||||
if (messageFactory == null) {
|
||||
final buffer = StringBuffer();
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
part of nyxx.interactivity;
|
||||
|
||||
/// Utils for getting and manipulating emojis
|
||||
class EmojiUtils {
|
||||
/// Returns [UnicodeEmoji] instance of given emoji [name].
|
||||
static UnicodeEmoji? getEmoji(String name) {
|
||||
if (emojisUnicode.containsKey(name)) {
|
||||
return UnicodeEmoji(emojisUnicode[name]!);
|
||||
if (emojis.containsKey(name)) {
|
||||
return UnicodeEmoji(emojis[name]!);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Map of all emojis which discord uses. Key is unicode name of emoji and value actual emoji.
|
||||
static Map<String, String> emojisUnicode = {
|
||||
static Map<String, String> emojis = {
|
||||
"grinning": "😀",
|
||||
"grimacing": "😬",
|
||||
"grin": "😁",
|
||||
|
|
|
@ -33,20 +33,4 @@ class _Utils {
|
|||
|
||||
return split(str, len);
|
||||
}
|
||||
|
||||
/// Partition list into chunks
|
||||
static Iterable<List<T>> partition<T>(List<T> lst, int len) sync* {
|
||||
for (var i = 0; i < lst.length; i += len) {
|
||||
yield lst.sublist(i, i + len);
|
||||
}
|
||||
}
|
||||
|
||||
/// Divides list into equal pieces
|
||||
static Stream<List<T>> chunk<T>(List<T> list, int chunkSize) async* {
|
||||
final len = list.length;
|
||||
for (var i = 0; i < len; i += chunkSize) {
|
||||
final size = i + chunkSize;
|
||||
yield list.sublist(i, size > len ? len : size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ documentation: https://github.com/l7ssha/nyxx/wiki
|
|||
issue_tracker: https://github.com/l7ssha/nyxx/issue
|
||||
|
||||
environment:
|
||||
sdk: '>=2.9.0-2.0.dev <3.0.0'
|
||||
sdk: '>=2.9.0-10.0.dev <3.0.0'
|
||||
|
||||
dependencies:
|
||||
nyxx: "^1.0.0"
|
||||
|
|
|
@ -5,7 +5,6 @@ library nyxx;
|
|||
|
||||
import "dart:async";
|
||||
|
||||
import "dart:collection";
|
||||
import "dart:convert";
|
||||
import "dart:io";
|
||||
|
||||
|
@ -18,6 +17,8 @@ import "package:w_transport/vm.dart" as transport_vm show configureWTransportFor
|
|||
|
||||
import "package:path/path.dart" as path_utils;
|
||||
|
||||
import "package:http/http.dart" as http_client;
|
||||
|
||||
// BASE
|
||||
|
||||
part "src/Nyxx.dart";
|
||||
|
@ -111,6 +112,8 @@ part "src/core/channel/dm/GroupDMChannel.dart";
|
|||
part "src/core/channel/dm/DMChannel.dart";
|
||||
part "src/core/channel/Channel.dart";
|
||||
part "src/core/channel/MessageChannel.dart";
|
||||
part "src/core/channel/ITextChannel.dart";
|
||||
part "src/core/channel/DummyTextChannel.dart";
|
||||
|
||||
part "src/core/embed/EmbedField.dart";
|
||||
part "src/core/embed/EmbedAuthor.dart";
|
||||
|
|
|
@ -54,24 +54,57 @@ class ClientOptions {
|
|||
/// If you do not specify a certain intent, you will not receive any of the gateway events that are batched into that group.
|
||||
/// [Reference](https://discordapp.com/developers/docs/topics/gateway#gateway-intents)
|
||||
class GatewayIntents {
|
||||
/// Includes events: `GUILD_CREATE, GUILD_UPDATE, GUILD_DELETE, GUILD_ROLE_CREATE, GUILD_ROLE_UPDATE, GUILD_ROLE_DELETE, CHANNEL_DELETE, CHANNEL_CREATE, CHANNEL_UPDATE, CHANNEL_PINS_UPDATE`
|
||||
bool guilds = false;
|
||||
|
||||
/// Includes events: `GUILD_MEMBER_ADD, GUILD_MEMBER_UPDATE, GUILD_MEMBER_REMOVE`
|
||||
bool guildMembers = false;
|
||||
|
||||
/// Includes events: `GUILD_BAN_ADD, GUILD_BAN_REMOVE`
|
||||
bool guildBans = false;
|
||||
|
||||
/// Includes event: `GUILD_EMOJIS_UPDATE`
|
||||
bool guildEmojis = false;
|
||||
|
||||
/// Includes events: `GUILD_INTEGRATIONS_UPDATE`
|
||||
bool guildIntegrations = false;
|
||||
|
||||
/// Includes events: `WEBHOOKS_UPDATE`
|
||||
bool guildWebhooks = false;
|
||||
|
||||
/// Includes events: `INVITE_CREATE, INVITE_DELETE`
|
||||
bool guildInvites = false;
|
||||
|
||||
/// Includes events: `VOICE_STATE_UPDATE`
|
||||
bool guildVoiceState = false;
|
||||
|
||||
/// Includes events: `PRESENCE_UPDATE`
|
||||
bool guildPresences = false;
|
||||
|
||||
/// Include events: `MESSAGE_CREATE, MESSAGE_UPDATE, MESSAGE_DELETE, MESSAGE_DELETE_BULK`
|
||||
bool guildMessages = false;
|
||||
|
||||
/// Includes events: `MESSAGE_REACTION_ADD, MESSAGE_REACTION_REMOVE, MESSAGE_REACTION_REMOVE_ALL, MESSAGE_REACTION_REMOVE_EMOJI`
|
||||
bool guildMessageReactions = false;
|
||||
|
||||
/// Includes events: `TYPING_START`
|
||||
bool guildMessageTyping = false;
|
||||
|
||||
/// Includes events: `CHANNEL_CREATE, MESSAGE_CREATE, MESSAGE_UPDATE, MESSAGE_DELETE, CHANNEL_PINS_UPDATE`
|
||||
bool directMessages = false;
|
||||
|
||||
/// Includes events: `MESSAGE_REACTION_ADD, MESSAGE_REACTION_REMOVE, MESSAGE_REACTION_REMOVE_ALL, MESSAGE_REACTION_REMOVE_EMOJI`
|
||||
bool directMessageReactions = false;
|
||||
|
||||
/// Includes events: `TYPING_START`
|
||||
bool directMessageTyping = false;
|
||||
|
||||
bool _all = false;
|
||||
|
||||
/// Constructs intens config object
|
||||
GatewayIntents();
|
||||
|
||||
/// Return config with turned on all intents
|
||||
GatewayIntents.all() : _all = true;
|
||||
|
||||
int _calculate() {
|
||||
|
@ -88,8 +121,9 @@ class GatewayIntents {
|
|||
if (guildIntegrations) value += 1 << 4;
|
||||
if (guildWebhooks) value += 1 << 5;
|
||||
if (guildInvites) value += 1 << 6;
|
||||
if (guildVoiceState) value += 1 << 8;
|
||||
if (guildPresences) value += 1 << 9;
|
||||
if (guildVoiceState) value += 1 << 7;
|
||||
if (guildPresences) value += 1 << 8;
|
||||
if (guildMessages) value += 1 << 9;
|
||||
if (guildMessageReactions) value += 1 << 10;
|
||||
if (guildMessageTyping) value += 1 << 11;
|
||||
if (directMessages) value += 1 << 12;
|
||||
|
|
|
@ -12,13 +12,13 @@ class Shard implements Disposable {
|
|||
bool connected = false;
|
||||
|
||||
/// Emitted when the shard is ready.
|
||||
late Stream<Shard> onConnected;
|
||||
late Stream<Shard> onConnected = this._onConnect.stream;
|
||||
|
||||
/// Emitted when the shard encounters an error.
|
||||
late Stream<Shard> onDisconnect;
|
||||
late Stream<Shard> onDisconnect = this._onDisconnect.stream;
|
||||
|
||||
/// Emitted when shard receives member chunk.
|
||||
late Stream<MemberChunkEvent> onMemberChunk;
|
||||
late Stream<MemberChunkEvent> onMemberChunk = this._onMemberChunk.stream;
|
||||
|
||||
/// Number of events seen by shard
|
||||
int get eventsSeen => _sequence;
|
||||
|
@ -34,20 +34,11 @@ class Shard implements Disposable {
|
|||
late int _sequence;
|
||||
String? _sessionId;
|
||||
|
||||
late final StreamController<Shard> _onConnect;
|
||||
late final StreamController<Shard> _onDisconnect;
|
||||
late final StreamController<MemberChunkEvent> _onMemberChunk;
|
||||
final StreamController<Shard> _onConnect = StreamController<Shard>.broadcast();
|
||||
late final StreamController<Shard> _onDisconnect = StreamController<Shard>.broadcast();
|
||||
late final StreamController<MemberChunkEvent> _onMemberChunk = StreamController.broadcast();
|
||||
|
||||
Shard._new(this._ws, this.id) {
|
||||
this._onConnect = StreamController<Shard>.broadcast();
|
||||
this.onConnected = this._onConnect.stream;
|
||||
|
||||
this._onDisconnect = StreamController<Shard>.broadcast();
|
||||
this.onDisconnect = this._onDisconnect.stream;
|
||||
|
||||
this._onMemberChunk = StreamController.broadcast();
|
||||
this.onMemberChunk = this._onMemberChunk.stream;
|
||||
}
|
||||
Shard._new(this._ws, this.id);
|
||||
|
||||
/// Allows to set presence for current shard.
|
||||
void setPresence({UserStatus? status, bool? afk, Activity? game, DateTime? since}) {
|
||||
|
@ -157,7 +148,7 @@ class Shard implements Disposable {
|
|||
"\$device": "nyxx",
|
||||
},
|
||||
"large_threshold": this._ws._client._options.largeThreshold,
|
||||
"compress": true
|
||||
"compress": "zlib-stream"
|
||||
};
|
||||
|
||||
if (_ws._client._options.gatewayIntents != null) {
|
||||
|
@ -382,6 +373,7 @@ class Shard implements Disposable {
|
|||
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
this._heartbeatTimer.cancel();
|
||||
await this._socketSubscription?.cancel();
|
||||
await this._socket?.close(1000);
|
||||
this._socket = null;
|
||||
|
|
|
@ -30,6 +30,7 @@ class Invite {
|
|||
this.guild = client.guilds[Snowflake(raw["guild"]["id"])];
|
||||
}
|
||||
|
||||
// TODO: NNBD
|
||||
if (raw["channel"] != null) {
|
||||
this.channel = client.channels[Snowflake(raw["channel"]["id"])];
|
||||
}
|
||||
|
@ -41,7 +42,7 @@ class Invite {
|
|||
if (raw["inviter"] != null) {
|
||||
this.inviter = client.users[Snowflake(raw["inviter"]["id"])];
|
||||
}
|
||||
|
||||
|
||||
if (raw["target_user"] != null) {
|
||||
this.targetUser = client.users[Snowflake(raw["target_user"]["id"])];
|
||||
}
|
||||
|
|
|
@ -1,19 +1,26 @@
|
|||
part of nyxx;
|
||||
|
||||
class AppTeam extends SnowflakeEntity {
|
||||
/// Hash of team icon
|
||||
late final String? iconHash;
|
||||
|
||||
/// Id of Team owner
|
||||
late final Snowflake ownerId;
|
||||
|
||||
/// List of members of team
|
||||
late final List<AppTeamMember> members;
|
||||
|
||||
/// Returns instance of [AppTeamMember] of team owner
|
||||
AppTeamMember get ownerMember => this.members.firstWhere((element) => element.user.id == this.ownerId);
|
||||
|
||||
AppTeam._new(Map<String, dynamic> raw) : super(Snowflake(raw["id"])) {
|
||||
this.iconHash = raw["icon"] as String?;
|
||||
this.ownerId = Snowflake(raw["owner_user_id"]);
|
||||
|
||||
this.members = [];
|
||||
for (Map<String, dynamic> obj in raw["members"]) {
|
||||
this.members.add(AppTeamMember._new(obj));
|
||||
}
|
||||
this.members = [
|
||||
for (final rawMember in raw["members"])
|
||||
AppTeamMember._new(rawMember as Map<String, dynamic>)
|
||||
];
|
||||
}
|
||||
|
||||
/// Returns url to team icon
|
||||
|
@ -26,9 +33,8 @@ class AppTeam extends SnowflakeEntity {
|
|||
}
|
||||
}
|
||||
|
||||
/// Represent membership of user in [Team]
|
||||
/// Represent membership of user in [AppTeam]
|
||||
class AppTeamMember {
|
||||
|
||||
/// Basic information of user
|
||||
late final AppTeamUser user;
|
||||
|
||||
|
|
|
@ -23,54 +23,53 @@ class AuditLogEntry extends SnowflakeEntity {
|
|||
String? reason;
|
||||
|
||||
AuditLogEntry._new(Map<String, dynamic> raw, Nyxx client) : super(Snowflake(raw["id"] as String)) {
|
||||
targetId = raw["targetId"] as String;
|
||||
this.targetId = raw["targetId"] as String;
|
||||
|
||||
changes = [
|
||||
this.changes = [
|
||||
if (raw["changes"] != null)
|
||||
for (var o in raw["changes"]) AuditLogChange._new(o as Map<String, dynamic>)
|
||||
];
|
||||
|
||||
user = client.users[Snowflake(raw["user_id"])];
|
||||
type = AuditLogEntryType(raw["action_type"] as int);
|
||||
this.user = client.users[Snowflake(raw["user_id"])];
|
||||
this.type = AuditLogEntryType._create(raw["action_type"] as int);
|
||||
|
||||
if (raw["options"] != null) {
|
||||
options = raw["options"] as String;
|
||||
this.options = raw["options"] as String;
|
||||
}
|
||||
|
||||
reason = raw["reason"] as String;
|
||||
this.reason = raw["reason"] as String;
|
||||
}
|
||||
}
|
||||
|
||||
class AuditLogEntryType extends IEnum<int> {
|
||||
static const AuditLogEntryType guildUpdate = AuditLogEntryType._of(1);
|
||||
static const AuditLogEntryType channelCreate = AuditLogEntryType._of(10);
|
||||
static const AuditLogEntryType channelUpdate = AuditLogEntryType._of(11);
|
||||
static const AuditLogEntryType channelDelete = AuditLogEntryType._of(12);
|
||||
static const AuditLogEntryType channelOverwriteCreate = AuditLogEntryType._of(13);
|
||||
static const AuditLogEntryType channelOverwriteUpdate = AuditLogEntryType._of(14);
|
||||
static const AuditLogEntryType channelOverwriteDelete = AuditLogEntryType._of(15);
|
||||
static const AuditLogEntryType memberKick = AuditLogEntryType._of(20);
|
||||
static const AuditLogEntryType memberPrune = AuditLogEntryType._of(21);
|
||||
static const AuditLogEntryType memberBanAdd = AuditLogEntryType._of(22);
|
||||
static const AuditLogEntryType memberBanRemove = AuditLogEntryType._of(23);
|
||||
static const AuditLogEntryType memberUpdate = AuditLogEntryType._of(24);
|
||||
static const AuditLogEntryType memberRoleUpdate = AuditLogEntryType._of(25);
|
||||
static const AuditLogEntryType roleCreate = AuditLogEntryType._of(30);
|
||||
static const AuditLogEntryType roleUpdate = AuditLogEntryType._of(31);
|
||||
static const AuditLogEntryType roleDelete = AuditLogEntryType._of(32);
|
||||
static const AuditLogEntryType inviteCreate = AuditLogEntryType._of(40);
|
||||
static const AuditLogEntryType inviteUpdate = AuditLogEntryType._of(41);
|
||||
static const AuditLogEntryType inviteDelete = AuditLogEntryType._of(42);
|
||||
static const AuditLogEntryType webhookCreate = AuditLogEntryType._of(50);
|
||||
static const AuditLogEntryType webhookUpdate = AuditLogEntryType._of(51);
|
||||
static const AuditLogEntryType webhookDelete = AuditLogEntryType._of(52);
|
||||
static const AuditLogEntryType emojiCreate = AuditLogEntryType._of(60);
|
||||
static const AuditLogEntryType emojiUpdate = AuditLogEntryType._of(61);
|
||||
static const AuditLogEntryType emojiDelete = AuditLogEntryType._of(62);
|
||||
static const AuditLogEntryType messageDelete = AuditLogEntryType._of(72);
|
||||
static const AuditLogEntryType guildUpdate = AuditLogEntryType._create(1);
|
||||
static const AuditLogEntryType channelCreate = AuditLogEntryType._create(10);
|
||||
static const AuditLogEntryType channelUpdate = AuditLogEntryType._create(11);
|
||||
static const AuditLogEntryType channelDelete = AuditLogEntryType._create(12);
|
||||
static const AuditLogEntryType channelOverwriteCreate = AuditLogEntryType._create(13);
|
||||
static const AuditLogEntryType channelOverwriteUpdate = AuditLogEntryType._create(14);
|
||||
static const AuditLogEntryType channelOverwriteDelete = AuditLogEntryType._create(15);
|
||||
static const AuditLogEntryType memberKick = AuditLogEntryType._create(20);
|
||||
static const AuditLogEntryType memberPrune = AuditLogEntryType._create(21);
|
||||
static const AuditLogEntryType memberBanAdd = AuditLogEntryType._create(22);
|
||||
static const AuditLogEntryType memberBanRemove = AuditLogEntryType._create(23);
|
||||
static const AuditLogEntryType memberUpdate = AuditLogEntryType._create(24);
|
||||
static const AuditLogEntryType memberRoleUpdate = AuditLogEntryType._create(25);
|
||||
static const AuditLogEntryType roleCreate = AuditLogEntryType._create(30);
|
||||
static const AuditLogEntryType roleUpdate = AuditLogEntryType._create(31);
|
||||
static const AuditLogEntryType roleDelete = AuditLogEntryType._create(32);
|
||||
static const AuditLogEntryType inviteCreate = AuditLogEntryType._create(40);
|
||||
static const AuditLogEntryType inviteUpdate = AuditLogEntryType._create(41);
|
||||
static const AuditLogEntryType inviteDelete = AuditLogEntryType._create(42);
|
||||
static const AuditLogEntryType webhookCreate = AuditLogEntryType._create(50);
|
||||
static const AuditLogEntryType webhookUpdate = AuditLogEntryType._create(51);
|
||||
static const AuditLogEntryType webhookDelete = AuditLogEntryType._create(52);
|
||||
static const AuditLogEntryType emojiCreate = AuditLogEntryType._create(60);
|
||||
static const AuditLogEntryType emojiUpdate = AuditLogEntryType._create(61);
|
||||
static const AuditLogEntryType emojiDelete = AuditLogEntryType._create(62);
|
||||
static const AuditLogEntryType messageDelete = AuditLogEntryType._create(72);
|
||||
|
||||
const AuditLogEntryType._of(int value) : super(value);
|
||||
AuditLogEntryType(int value) : super(value);
|
||||
const AuditLogEntryType._create(int value) : super(value);
|
||||
|
||||
@override
|
||||
bool operator ==(other) {
|
||||
|
|
|
@ -2,7 +2,7 @@ part of nyxx;
|
|||
|
||||
/// A channel.
|
||||
/// Abstract base class that defines the base methods and/or properties for all Discord channel types.
|
||||
abstract class Channel extends SnowflakeEntity {
|
||||
class Channel extends SnowflakeEntity {
|
||||
/// The channel's type.
|
||||
/// https://discordapp.com/developers/docs/resources/channel#channel-object-channel-types
|
||||
final ChannelType type;
|
||||
|
|
5
nyxx/lib/src/core/channel/DummyTextChannel.dart
Normal file
5
nyxx/lib/src/core/channel/DummyTextChannel.dart
Normal file
|
@ -0,0 +1,5 @@
|
|||
part of nyxx;
|
||||
|
||||
class DummyTextChannel extends Channel with MessageChannel, ISend implements ITextChannel {
|
||||
DummyTextChannel._new(Map<String, dynamic> raw, int type, Nyxx client) : super._new(raw, type, client);
|
||||
}
|
77
nyxx/lib/src/core/channel/ITextChannel.dart
Normal file
77
nyxx/lib/src/core/channel/ITextChannel.dart
Normal file
|
@ -0,0 +1,77 @@
|
|||
part of nyxx;
|
||||
|
||||
/// Represents text channel. Can be either [CachelessTextChannel] or [DMChannel] or [GroupDMChannel]
|
||||
abstract class ITextChannel implements Channel, MessageChannel {
|
||||
/// Returns message with given [id]. Allows to force fetch message from api
|
||||
/// with [ignoreCache] property. By default it checks if message is in cache and fetches from api if not.
|
||||
Future<Message?> getMessage(Snowflake id, {bool ignoreCache = false});
|
||||
|
||||
/// Sends message to channel. Performs `toString()` on thing passed to [content]. Allows to send embeds with [embed] field.
|
||||
///
|
||||
/// ```
|
||||
/// await chan.send(content: "Very nice message!");
|
||||
/// ```
|
||||
///
|
||||
/// Can be used in combination with [Emoji]. Just run `toString()` on [Emoji] instance:
|
||||
/// ```
|
||||
/// var emoji = guild.emojis.values.firstWhere((e) => e.name.startsWith("dart"));
|
||||
/// await chan.send(content: "Dart is superb! ${emoji.toString()}");
|
||||
/// ```
|
||||
/// Embeds can be sent very easily:
|
||||
/// ```
|
||||
/// var embed = new EmbedBuilder()
|
||||
/// ..title = "Example Title"
|
||||
/// ..addField(name: "Memory usage", value: "${ProcessInfo.currentRss / 1024 / 1024}MB");
|
||||
///
|
||||
/// await chan.send(embed: embed);
|
||||
/// ```
|
||||
///
|
||||
///
|
||||
/// Method also allows to send file and optional [content] with [embed].
|
||||
/// Use `expandAttachment(String file)` method to expand file names in embed
|
||||
///
|
||||
/// ```
|
||||
/// await chan.send(files: [new File("kitten.png"), new File("kitten.jpg")], content: "Kittens ^-^"]);
|
||||
/// ```
|
||||
/// ```
|
||||
/// var embed = new nyxx.EmbedBuilder()
|
||||
/// ..title = "Example Title"
|
||||
/// ..thumbnailUrl = "${attach("kitten.jpg")}";
|
||||
///
|
||||
/// await e.message.channel
|
||||
/// .send(files: [new File("kitten.jpg")], embed: embed, content: "HEJKA!");
|
||||
/// ```
|
||||
@override
|
||||
Future<Message> send(
|
||||
{dynamic content,
|
||||
List<AttachmentBuilder>? files,
|
||||
EmbedBuilder? embed,
|
||||
bool? tts,
|
||||
AllowedMentions? allowedMentions,
|
||||
MessageBuilder? builder});
|
||||
|
||||
/// Starts typing.
|
||||
Future<void> startTyping();
|
||||
|
||||
/// Loops `startTyping` until `stopTypingLoop` is called.
|
||||
void startTypingLoop();
|
||||
|
||||
/// Stops a typing loop if one is running.
|
||||
void stopTypingLoop();
|
||||
|
||||
/// Bulk removes many messages by its ids. [messagesIds] is list of messages ids to delete.
|
||||
///
|
||||
/// ```
|
||||
/// var toDelete = chan.messages.keys.take(5);
|
||||
/// await chan.bulkRemoveMessages(toDelete);
|
||||
/// ```
|
||||
Future<void> bulkRemoveMessages(Iterable<Message> messagesIds);
|
||||
|
||||
/// Gets several [Message] objects from API. Only one of [after], [before], [around] can be specified,
|
||||
/// otherwise, it will throw.
|
||||
///
|
||||
/// ```
|
||||
/// var messages = await chan.getMessages(limit: 100, after: Snowflake("222078108977594368"));
|
||||
/// ```
|
||||
Stream<Message> getMessages({int limit = 50, Snowflake? after, Snowflake? before, Snowflake? around});
|
||||
}
|
|
@ -11,17 +11,21 @@ part of nyxx;
|
|||
/// print(message.author.id);
|
||||
/// }
|
||||
/// ```
|
||||
abstract class MessageChannel implements Channel, ISend {
|
||||
abstract class MessageChannel implements Channel, ISend, Disposable {
|
||||
Timer? _typing;
|
||||
|
||||
/// Sent when a new message is received.
|
||||
late final Stream<MessageReceivedEvent> onMessage;
|
||||
late final Stream<MessageReceivedEvent> onMessage = client.onMessageReceived.where((event) => event.message.channel == this);
|
||||
|
||||
/// Emitted when user starts typing.
|
||||
late final Stream<TypingEvent> onTyping;
|
||||
late final Stream<TypingEvent> onTyping = client.onTyping.where((event) => event.channel == this);
|
||||
|
||||
/// Emitted when channel pins are updated.
|
||||
late final Stream<ChannelPinsUpdateEvent> pinsUpdated = client.onChannelPinsUpdate.where((event) => event.channel == this);
|
||||
|
||||
/// A collection of messages sent to this channel.
|
||||
late final MessageCache messages;
|
||||
late final MessageCache messages = MessageCache._new(client._options.messageCacheSize);
|
||||
|
||||
|
||||
/// File upload limit for channel
|
||||
int get fileUploadLimit {
|
||||
|
@ -32,13 +36,6 @@ abstract class MessageChannel implements Channel, ISend {
|
|||
return 8 * 1024 * 1024;
|
||||
}
|
||||
|
||||
void _initialize(Map<String, dynamic> raw) {
|
||||
this.messages = MessageCache._new(client._options.messageCacheSize);
|
||||
|
||||
this.onTyping = client.onTyping.where((event) => event.channel == this);
|
||||
this.onMessage = client.onMessageReceived.where((event) => event.message.channel == this);
|
||||
}
|
||||
|
||||
/// Returns message with given [id]. Allows to force fetch message from api
|
||||
/// with [ignoreCache] property. By default it checks if message is in cache and fetches from api if not.
|
||||
Future<Message?> getMessage(Snowflake id, {bool ignoreCache = false}) async {
|
||||
|
@ -191,7 +188,7 @@ abstract class MessageChannel implements Channel, ISend {
|
|||
}
|
||||
}
|
||||
|
||||
@override
|
||||
/// Returns iterator for messages cache
|
||||
Iterator<Message> get iterator => messages.values.iterator;
|
||||
|
||||
@override
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
part of nyxx;
|
||||
|
||||
/// Represents channel with another user.
|
||||
class DMChannel extends Channel with MessageChannel, ISend {
|
||||
class DMChannel extends Channel with MessageChannel, ISend implements ITextChannel {
|
||||
/// The recipient.
|
||||
late User recipient;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
part of nyxx;
|
||||
|
||||
/// Represents group DM channel.
|
||||
class GroupDMChannel extends Channel with MessageChannel, ISend {
|
||||
class GroupDMChannel extends Channel with MessageChannel, ISend implements ITextChannel {
|
||||
/// The recipients of channel.
|
||||
late final List<User> recipients;
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
part of nyxx;
|
||||
|
||||
/// Represents channel which is part of guild.
|
||||
/// Can be represented by [CachelessGuildChannel] or [CacheGuildChannel]
|
||||
abstract class IGuildChannel extends Channel {
|
||||
/// The channel"s name.
|
||||
String get name;
|
||||
|
@ -16,7 +18,7 @@ abstract class IGuildChannel extends Channel {
|
|||
/// Indicates if channel is nsfw
|
||||
bool get isNsfw;
|
||||
|
||||
/// Returns list of [Member] objects who can see this channel
|
||||
/// Returns list of [CacheMember] objects who can see this channel
|
||||
List<PermissionsOverrides> get permissionOverrides;
|
||||
|
||||
IGuildChannel._new(Map<String, dynamic> raw, int type, Nyxx client) : super._new(raw, type, client);
|
||||
|
@ -44,6 +46,7 @@ abstract class IGuildChannel extends Channel {
|
|||
Future<Invite> createInvite({int? maxAge, int? maxUses, bool? temporary, bool? unique, String? auditReason});
|
||||
}
|
||||
|
||||
/// Guild channel which does not have access to cache.
|
||||
abstract class CachelessGuildChannel extends IGuildChannel {
|
||||
/// The channel"s name.
|
||||
@override
|
||||
|
@ -65,7 +68,7 @@ abstract class CachelessGuildChannel extends IGuildChannel {
|
|||
@override
|
||||
late final bool isNsfw;
|
||||
|
||||
/// Returns list of [Member] objects who can see this channel
|
||||
/// Returns list of [CacheMember] objects who can see this channel
|
||||
@override
|
||||
late final List<PermissionsOverrides> permissionOverrides;
|
||||
|
||||
|
@ -152,7 +155,7 @@ abstract class CachelessGuildChannel extends IGuildChannel {
|
|||
}
|
||||
}
|
||||
|
||||
/// Represents channel which is part of guild.
|
||||
/// Guild channel which does have access to cache.
|
||||
abstract class CacheGuildChannel extends CachelessGuildChannel {
|
||||
/// The guild that the channel is in.
|
||||
late Guild guild;
|
||||
|
@ -160,24 +163,17 @@ abstract class CacheGuildChannel extends CachelessGuildChannel {
|
|||
/// Parent channel id
|
||||
CategoryChannel? parentChannel;
|
||||
|
||||
/// Returns list of [Member] objects who can see this channel
|
||||
Iterable<Member> get users => this
|
||||
.guild
|
||||
.members
|
||||
.values
|
||||
.where((member) => this.effectivePermissions(member).hasPermission(PermissionsConstants.viewChannel));
|
||||
|
||||
CacheGuildChannel._new(Map<String, dynamic> raw, int type, Guild guild, Nyxx client) : super._new(raw, type, guild.id, client) {
|
||||
// ignore: prefer_initializing_formals
|
||||
this.guild = guild;
|
||||
/// Returns list of [CacheMember] objects who can see this channel
|
||||
Iterable<IMember> get users => this.guild.members.values.where((member) => member is CacheMember && this.effectivePermissions(member).hasPermission(PermissionsConstants.viewChannel));
|
||||
|
||||
CacheGuildChannel._new(Map<String, dynamic> raw, int type, this.guild, Nyxx client) : super._new(raw, type, guild.id, client) {
|
||||
if(this.parentChannelId != null) {
|
||||
this.parentChannel = guild.channels[this.parentChannelId!] as CategoryChannel?;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns effective permissions for [member] to this channel including channel overrides.
|
||||
Permissions effectivePermissions(Member member) {
|
||||
Permissions effectivePermissions(CacheMember member) {
|
||||
if (member.guild != this.guild) {
|
||||
return Permissions.empty();
|
||||
}
|
||||
|
@ -202,9 +198,11 @@ abstract class CacheGuildChannel extends CachelessGuildChannel {
|
|||
|
||||
/// Returns effective permissions for [role] to this channel including channel overrides.
|
||||
Permissions effectivePermissionForRole(Role role) {
|
||||
if (role.guild != this.guild) return Permissions.empty();
|
||||
if (role.guild != this.guild) {
|
||||
return Permissions.empty();
|
||||
}
|
||||
|
||||
var permissions = role.permissions.raw | guild.everyoneRole.permissions.raw;
|
||||
var permissions = role.permissions.raw | (guild.everyoneRole as Role).permissions.raw;
|
||||
|
||||
// TODO: NNBD: try-catch in where
|
||||
try {
|
||||
|
|
|
@ -2,10 +2,7 @@ part of nyxx;
|
|||
|
||||
/// [CachelessTextChannel] represents single text channel on [Guild].
|
||||
/// Inhertits from [MessageChannel] and mixes [CacheGuildChannel].
|
||||
class CachelessTextChannel extends CachelessGuildChannel with MessageChannel, ISend implements Mentionable {
|
||||
/// Emitted when channel pins are updated.
|
||||
late final Stream<ChannelPinsUpdateEvent> pinsUpdated;
|
||||
|
||||
class CachelessTextChannel extends CachelessGuildChannel with MessageChannel, ISend implements Mentionable, ITextChannel {
|
||||
/// The channel's topic.
|
||||
late final String? topic;
|
||||
|
||||
|
@ -22,12 +19,8 @@ class CachelessTextChannel extends CachelessGuildChannel with MessageChannel, IS
|
|||
"/${this.id.toString()}";
|
||||
|
||||
CachelessTextChannel._new(Map<String, dynamic> raw, Snowflake guildId, Nyxx client) : super._new(raw, 0, guildId, client) {
|
||||
_initialize(raw);
|
||||
|
||||
this.topic = raw["topic"] as String?;
|
||||
this.slowModeThreshold = raw["rate_limit_per_user"] as int? ?? 0;
|
||||
|
||||
pinsUpdated = client.onChannelPinsUpdate.where((event) => event.channel == this);
|
||||
}
|
||||
|
||||
/// Edits the channel.
|
||||
|
@ -65,9 +58,9 @@ class CachelessTextChannel extends CachelessGuildChannel with MessageChannel, IS
|
|||
/// Valid file types for [avatarFile] are jpeg, gif and png.
|
||||
///
|
||||
/// ```
|
||||
/// var webhook = await chan.createWebhook("!a Send nudes kek6407");
|
||||
/// var webhook = await channnel.createWebhook("!a Send nudes kek6407");
|
||||
/// ```
|
||||
Future<Webhook> createWebhook(String name, {File? avatarFile, String auditReason = ""}) async {
|
||||
Future<Webhook> createWebhook(String name, {File? avatarFile, String? auditReason}) async {
|
||||
if (name.isEmpty || name.length > 80) {
|
||||
return Future.error("Webhook's name cannot be shorter than 1 character and longer than 80 characters");
|
||||
}
|
||||
|
|
|
@ -13,9 +13,9 @@ class ClientUser extends User {
|
|||
this.mfa = data["mfa_enabled"] as bool;
|
||||
}
|
||||
|
||||
/// Allows to get [Member] objects for all guilds for bot user.
|
||||
Map<Guild, Member> getMembership() {
|
||||
final membershipCollection = <Guild, Member>{};
|
||||
/// Allows to get [CacheMember] objects for all guilds for bot user.
|
||||
Map<Guild, IMember> getMembership() {
|
||||
final membershipCollection = <Guild, IMember>{};
|
||||
|
||||
for (final guild in client.guilds.values) {
|
||||
final member = guild.members[this.id];
|
||||
|
|
|
@ -33,8 +33,8 @@ class Guild extends SnowflakeEntity implements Disposable {
|
|||
late final List<String> features;
|
||||
|
||||
/// The guild's afk channel ID, null if not set.
|
||||
late CacheVoiceChannel? afkChannel;
|
||||
|
||||
late VoiceChannel? afkChannel;
|
||||
|
||||
/// The guild's voice region.
|
||||
late String region;
|
||||
|
||||
|
@ -69,16 +69,16 @@ class Guild extends SnowflakeEntity implements Disposable {
|
|||
late final User? owner;
|
||||
|
||||
/// The guild's members.
|
||||
late final Cache<Snowflake, Member> members;
|
||||
late final Cache<Snowflake, IMember> members;
|
||||
|
||||
/// The guild's channels.
|
||||
late final ChannelCache channels;
|
||||
|
||||
/// The guild's roles.
|
||||
late final Cache<Snowflake, Role> roles;
|
||||
late final Cache<Snowflake, IRole> roles;
|
||||
|
||||
/// Guild custom emojis
|
||||
late final Cache<Snowflake, GuildEmoji> emojis;
|
||||
late final Cache<Snowflake, IGuildEmoji> emojis;
|
||||
|
||||
/// Boost level of guild
|
||||
late final PremiumTier premiumTier;
|
||||
|
@ -104,10 +104,10 @@ class Guild extends SnowflakeEntity implements Disposable {
|
|||
String get url => "https://discordapp.com/channels/${this.id.toString()}";
|
||||
|
||||
/// Getter for @everyone role
|
||||
Role get everyoneRole => roles.values.firstWhere((r) => r.name == "@everyone");
|
||||
IRole get everyoneRole => roles.values.firstWhere((r) => (r as Role).name == "@everyone");
|
||||
|
||||
/// Returns member object for bot user
|
||||
Member? get selfMember => members[client.self.id];
|
||||
IMember? get selfMember => members[client.self.id];
|
||||
|
||||
/// Upload limit for this guild in bytes
|
||||
int get fileUploadLimit {
|
||||
|
@ -200,7 +200,7 @@ class Guild extends SnowflakeEntity implements Disposable {
|
|||
|
||||
if (client._options.cacheMembers) {
|
||||
raw["members"].forEach((o) {
|
||||
final member = Member._standard(o as Map<String, dynamic>, this, client);
|
||||
final member = CacheMember._standard(o as Map<String, dynamic>, this, client);
|
||||
this.members[member.id] = member;
|
||||
client.users[member.id] = member;
|
||||
});
|
||||
|
@ -385,7 +385,7 @@ class Guild extends SnowflakeEntity implements Disposable {
|
|||
}
|
||||
|
||||
/// Change guild owner.
|
||||
Future<Guild> changeOwner(Member member, {String? auditReason}) async {
|
||||
Future<Guild> changeOwner(CacheMember member, {String? auditReason}) async {
|
||||
final response = await client._http._execute(
|
||||
BasicRequest._new("/guilds/$id", method: "PATCH", auditLog: auditReason, body: {"owner_id": member.id}));
|
||||
|
||||
|
@ -492,7 +492,7 @@ class Guild extends SnowflakeEntity implements Disposable {
|
|||
return Future.error(response);
|
||||
}
|
||||
|
||||
/// Adds [Role] to [Member]
|
||||
/// Adds [Role] to [CacheMember]
|
||||
///
|
||||
/// ```
|
||||
/// var role = guild.roles.values.first;
|
||||
|
@ -500,7 +500,7 @@ class Guild extends SnowflakeEntity implements Disposable {
|
|||
///
|
||||
/// await guild.addRoleToMember(member, role);
|
||||
/// ```
|
||||
Future<void> addRoleToMember(Member user, Role role) async =>
|
||||
Future<void> addRoleToMember(CacheMember user, Role role) async =>
|
||||
client._http._execute(BasicRequest._new("/guilds/$id/members/${user.id}/roles/${role.id}", method: "PUT"));
|
||||
|
||||
/// Returns list of available [CacheVoiceChannel]s
|
||||
|
@ -589,7 +589,7 @@ class Guild extends SnowflakeEntity implements Disposable {
|
|||
///
|
||||
/// await guild.ban(member);
|
||||
/// ```
|
||||
Future<void> ban(Member member, {int deleteMessageDays = 0, String? auditReason}) async =>
|
||||
Future<void> ban(CacheMember member, {int deleteMessageDays = 0, String? auditReason}) async =>
|
||||
client._http._execute(BasicRequest._new("/guilds/${this.id}/bans/${member.id.toString()}",
|
||||
method: "PUT", auditLog: auditReason, body: {"delete-message-days": deleteMessageDays}));
|
||||
|
||||
|
@ -598,7 +598,7 @@ class Guild extends SnowflakeEntity implements Disposable {
|
|||
/// ```
|
||||
/// await guild.kick(member);
|
||||
/// ```
|
||||
Future<void> kick(Member member, {String? auditReason}) async =>
|
||||
Future<void> kick(CacheMember member, {String? auditReason}) async =>
|
||||
client._http._execute(BasicRequest._new("/guilds/${this.id.toString()}/members/${member.id.toString()}",
|
||||
method: "DELTE", auditLog: auditReason));
|
||||
|
||||
|
@ -634,27 +634,27 @@ class Guild extends SnowflakeEntity implements Disposable {
|
|||
return Future.error(response);
|
||||
}
|
||||
|
||||
/// Gets a [Member] object. Caches fetched member if not cached.
|
||||
/// Gets a [CacheMember] object. Caches fetched member if not cached.
|
||||
///
|
||||
/// ```
|
||||
/// var member = guild.getMember(user);
|
||||
/// ```
|
||||
Future<Member> getMember(User user) async => getMemberById(user.id);
|
||||
Future<CacheMember> getMember(User user) async => getMemberById(user.id);
|
||||
|
||||
/// Gets a [Member] object by id. Caches fetched member if not cached.
|
||||
/// Gets a [CacheMember] object by id. Caches fetched member if not cached.
|
||||
///
|
||||
/// ```
|
||||
/// var member = guild.getMember(Snowflake("302359795648954380"));
|
||||
/// ```
|
||||
Future<Member> getMemberById(Snowflake id) async {
|
||||
Future<CacheMember> getMemberById(Snowflake id) async {
|
||||
if (this.members.hasKey(id)) {
|
||||
return this.members[id] as Member;
|
||||
return this.members[id] as CacheMember;
|
||||
}
|
||||
|
||||
final response = await client._http._execute(BasicRequest._new("/guilds/${this.id}/members/${id.toString()}"));
|
||||
|
||||
if (response is HttpResponseSuccess) {
|
||||
return Member._standard(response.jsonBody as Map<String, dynamic>, this, client);
|
||||
return CacheMember._standard(response.jsonBody as Map<String, dynamic>, this, client);
|
||||
}
|
||||
|
||||
return Future.error(response);
|
||||
|
@ -663,7 +663,7 @@ class Guild extends SnowflakeEntity implements Disposable {
|
|||
/// Allows to fetch guild members. In future will be restricted with `Priviliged Intents`.
|
||||
/// [after] is used to continue from specified user id.
|
||||
/// By default limits to one user - use [limit] paramter to change that behavior.
|
||||
Stream<Member> getMembers({int limit = 1, Snowflake? after}) async* {
|
||||
Stream<CacheMember> getMembers({int limit = 1, Snowflake? after}) async* {
|
||||
final request = this.client._http._execute(BasicRequest._new("/guilds/${this.id.toString()}/members",
|
||||
queryParams: {"limit": limit.toString(), if (after != null) "after": after.toString()}));
|
||||
|
||||
|
@ -672,13 +672,13 @@ class Guild extends SnowflakeEntity implements Disposable {
|
|||
}
|
||||
|
||||
for (final rawMember in (request as HttpResponseSuccess).jsonBody as List<dynamic>) {
|
||||
yield Member._standard(rawMember as Map<String, dynamic>, this, client);
|
||||
yield CacheMember._standard(rawMember as Map<String, dynamic>, this, client);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a [Stream] of [Member] objects whose username or nickname starts with a provided string.
|
||||
/// Returns a [Stream] of [CacheMember] objects whose username or nickname starts with a provided string.
|
||||
/// By default limits to one entry - can be changed with [limit] parameter.
|
||||
Stream<Member> searchMembers(String query, {int limit = 1}) async* {
|
||||
Stream<CacheMember> searchMembers(String query, {int limit = 1}) async* {
|
||||
final response = await client._http._execute(BasicRequest._new("/guilds/${this.id}/members/search",
|
||||
queryParams: {"query": query, "limit": limit.toString()}));
|
||||
|
||||
|
@ -687,13 +687,13 @@ class Guild extends SnowflakeEntity implements Disposable {
|
|||
}
|
||||
|
||||
for (final Map<String, dynamic> member in (response as HttpResponseSuccess).jsonBody) {
|
||||
yield Member._standard(member, this, client);
|
||||
yield CacheMember._standard(member, this, client);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a [Stream] of [Member] objects whose username or nickname starts with a provided string.
|
||||
/// Returns a [Stream] of [CacheMember] objects whose username or nickname starts with a provided string.
|
||||
/// By default limits to one entry - can be changed with [limit] parameter.
|
||||
Stream<Member> searchMembersGateway(String query, {int limit = 0}) async* {
|
||||
Stream<IMember> searchMembersGateway(String query, {int limit = 0}) async* {
|
||||
final nonce = "$query${id.toString()}";
|
||||
|
||||
this.client.shard.requestMembers(this.id, query: query, limit: limit, nonce: nonce);
|
||||
|
|
|
@ -1,7 +1,41 @@
|
|||
part of nyxx;
|
||||
|
||||
/// Represents [Guild] role.
|
||||
/// Interface allows basic operations on member but does not guarantee data to be valid or available
|
||||
class IRole extends SnowflakeEntity {
|
||||
/// Reference to client
|
||||
final Nyxx client;
|
||||
|
||||
/// Id of role's [Guild]
|
||||
final Snowflake guildId;
|
||||
|
||||
IRole._new(Snowflake id, this.guildId, this.client) : super(id);
|
||||
|
||||
/// Edits the role.
|
||||
Future<Role> edit(RoleBuilder role, {String? auditReason}) async {
|
||||
final response = await client._http._execute(BasicRequest._new("/guilds/${this.guildId}/roles/$id",
|
||||
method: "PATCH", body: role._build(), auditLog: auditReason));
|
||||
|
||||
if (response is HttpResponseSuccess) {
|
||||
return Role._new(response.jsonBody as Map<String, dynamic>, this.guildId, client);
|
||||
}
|
||||
|
||||
return Future.error(response);
|
||||
}
|
||||
|
||||
/// Deletes the role.
|
||||
Future<void> delete({String? auditReason}) =>
|
||||
client._http
|
||||
._execute(BasicRequest._new("/guilds/${this.guildId}/roles/$id", method: "DELETE", auditLog: auditReason));
|
||||
|
||||
/// Adds role to user.
|
||||
Future<void> addToUser(User user, {String? auditReason}) =>
|
||||
client._http._execute(
|
||||
BasicRequest._new("/guilds/${this.guildId}/members/${user.id}/roles/$id", method: "PUT", auditLog: auditReason));
|
||||
}
|
||||
|
||||
/// Represents a Discord guild role, which is used to assign priority, permissions, and a color to guild members
|
||||
class Role extends SnowflakeEntity implements Mentionable, GuildEntity {
|
||||
class Role extends IRole implements Mentionable, GuildEntity {
|
||||
/// The role's name.
|
||||
late final String name;
|
||||
|
||||
|
@ -24,10 +58,6 @@ class Role extends SnowflakeEntity implements Mentionable, GuildEntity {
|
|||
@override
|
||||
late final Guild? guild;
|
||||
|
||||
@override
|
||||
/// The role's guild id.
|
||||
late final Snowflake guildId;
|
||||
|
||||
/// The role's permissions.
|
||||
late final Permissions permissions;
|
||||
|
||||
|
@ -36,10 +66,7 @@ class Role extends SnowflakeEntity implements Mentionable, GuildEntity {
|
|||
/// Mention of role. If role cannot be mentioned it returns name of role (@name)
|
||||
String get mention => mentionable ? "<@&${this.id}>" : "@$name";
|
||||
|
||||
/// Reference to [Nyxx] instance
|
||||
Nyxx client;
|
||||
|
||||
Role._new(Map<String, dynamic> raw, this.guildId, this.client) : super(Snowflake(raw["id"] as String)) {
|
||||
Role._new(Map<String, dynamic> raw, Snowflake guildId, Nyxx client) : super._new(Snowflake(raw["id"]), guildId, client) {
|
||||
this.name = raw["name"] as String;
|
||||
this.position = raw["position"] as int;
|
||||
this.hoist = raw["hoist"] as bool;
|
||||
|
@ -51,28 +78,6 @@ class Role extends SnowflakeEntity implements Mentionable, GuildEntity {
|
|||
this.guild = client.guilds[this.guildId];
|
||||
}
|
||||
|
||||
/// Edits the role.
|
||||
Future<Role> edit(RoleBuilder role, {String? auditReason}) async {
|
||||
final response = await client._http._execute(BasicRequest._new("/guilds/${this.guildId}/roles/$id",
|
||||
method: "PATCH", body: role._build(), auditLog: auditReason));
|
||||
|
||||
if (response is HttpResponseSuccess) {
|
||||
return Role._new(response.jsonBody as Map<String, dynamic>, this.guildId, client);
|
||||
}
|
||||
|
||||
return Future.error(response);
|
||||
}
|
||||
|
||||
/// Deletes the role.
|
||||
Future<void> delete({String? auditReason}) =>
|
||||
client._http
|
||||
._execute(BasicRequest._new("/guilds/${this.guildId}/roles/$id", method: "DELETE", auditLog: auditReason));
|
||||
|
||||
/// Adds role to user.
|
||||
Future<void> addToUser(User user, {String? auditReason}) =>
|
||||
client._http._execute(
|
||||
BasicRequest._new("/guilds/${this.guildId}/members/${user.id}/roles/$id", method: "PUT", auditLog: auditReason));
|
||||
|
||||
/// Returns a mention of role. If role cannot be mentioned it returns name of role.
|
||||
@override
|
||||
String toString() => mention;
|
||||
|
|
|
@ -3,7 +3,10 @@ part of nyxx;
|
|||
/// Type of webhook. Either [incoming] if it its normal webhook executable with token,
|
||||
/// or [channelFollower] if its discord internal webhook
|
||||
class WebhookType extends IEnum<int> {
|
||||
/// Incoming Webhooks can post messages to channels with a generated token
|
||||
static const WebhookType incoming = WebhookType._create(1);
|
||||
|
||||
/// Channel Follower Webhooks are internal webhooks used with Channel Following to post new messages into channels
|
||||
static const WebhookType channelFollower = WebhookType._create(2);
|
||||
|
||||
const WebhookType._create(int? value) : super(value ?? 0);
|
||||
|
@ -89,7 +92,7 @@ class Webhook extends SnowflakeEntity implements IMessageAuthor {
|
|||
}
|
||||
|
||||
/// Edits the webhook.
|
||||
Future<Webhook> edit({String? name, CachelessTextChannel? channel, File? avatar, String? encodedAvatar, String? auditReason}) async {
|
||||
Future<Webhook> edit({String? name, ITextChannel? channel, File? avatar, String? encodedAvatar, String? auditReason}) async {
|
||||
final body = <String, dynamic>{
|
||||
if (name != null) "name": name,
|
||||
if (channel != null) "channel_id": channel.id.toString()
|
||||
|
|
|
@ -4,8 +4,8 @@ part of nyxx;
|
|||
abstract class Emoji {
|
||||
/// Emojis name.
|
||||
String name;
|
||||
|
||||
Emoji(this.name);
|
||||
|
||||
Emoji._new(this.name);
|
||||
|
||||
// TODO: Emojis stuff
|
||||
factory Emoji._deserialize(Map<String, dynamic> raw) {
|
||||
|
|
|
@ -4,7 +4,7 @@ abstract class IGuildEmoji extends Emoji {
|
|||
/// True if emoji is partial.
|
||||
final bool partial;
|
||||
|
||||
IGuildEmoji._new(String name, this.partial) : super(name);
|
||||
IGuildEmoji._new(String name, this.partial) : super._new(name);
|
||||
}
|
||||
|
||||
/// Emoji object. Handles Unicode emojis and custom ones.
|
||||
|
@ -26,20 +26,8 @@ class GuildEmoji extends IGuildEmoji implements SnowflakeEntity, GuildEntity {
|
|||
@override
|
||||
late final Snowflake id;
|
||||
|
||||
late final List<Snowflake> _roles;
|
||||
|
||||
/// Roles this emoji is whitelisted to
|
||||
Iterable<Role> get roles sync* {
|
||||
if(this.guild != null) {
|
||||
for(final roleId in this._roles) {
|
||||
final role = this.guild!.roles[roleId];
|
||||
|
||||
if(role != null) {
|
||||
yield role;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Roles which can use this emote
|
||||
late final Iterable<IRole> roles;
|
||||
|
||||
/// whether this emoji must be wrapped in colons
|
||||
late final bool requireColons;
|
||||
|
@ -50,10 +38,6 @@ class GuildEmoji extends IGuildEmoji implements SnowflakeEntity, GuildEntity {
|
|||
/// whether this emoji is animated
|
||||
late final bool animated;
|
||||
|
||||
/// True if emoji is partial.
|
||||
/// Always check before accessing fields or methods, due any of field can be null or empty
|
||||
late final bool partial;
|
||||
|
||||
/// Creates full emoji object
|
||||
GuildEmoji._new(Map<String, dynamic> raw, this.guildId, this.client) : super._new(raw["name"] as String, false) {
|
||||
this.id = Snowflake(raw["id"] as String);
|
||||
|
@ -63,10 +47,10 @@ class GuildEmoji extends IGuildEmoji implements SnowflakeEntity, GuildEntity {
|
|||
this.managed = raw["managed"] as bool? ?? false;
|
||||
this.animated = raw["animated"] as bool? ?? false;
|
||||
|
||||
this._roles = [
|
||||
this.roles = [
|
||||
if (raw["roles"] != null)
|
||||
for (final roleId in raw["roles"])
|
||||
Snowflake(roleId)
|
||||
IRole._new(Snowflake(roleId), this.guildId, client)
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ class GuildMessage extends Message implements GuildEntity {
|
|||
String get url => "https://discordapp.com/channels/${this.guildId}"
|
||||
"/${this.channelId}/${this.id}";
|
||||
|
||||
/// The message's author. Can be instance of [Member] or [Webhook]
|
||||
/// The message's author. Can be instance of [CacheMember] or [Webhook]
|
||||
@override
|
||||
late final IMessageAuthor author;
|
||||
|
||||
|
@ -50,20 +50,7 @@ class GuildMessage extends Message implements GuildEntity {
|
|||
/// True if message is sent by a webhook
|
||||
bool get isByWebhook => author is Webhook;
|
||||
|
||||
late List<Snowflake> _roleMentions;
|
||||
|
||||
/// A list of IDs for the role mentions in the message.
|
||||
Iterable<Role> get roleMentions sync* {
|
||||
if(this.guild != null) {
|
||||
for (final roleId in _roleMentions) {
|
||||
final role = this.guild!.roles[roleId];
|
||||
|
||||
if(role != null) {
|
||||
yield role;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
late final List<IRole> roleMentions;
|
||||
|
||||
GuildMessage._new(Map<String, dynamic> raw, Nyxx client) : super._new(raw, client) {
|
||||
if (raw["message_reference"] != null) {
|
||||
|
@ -85,9 +72,8 @@ class GuildMessage extends Message implements GuildEntity {
|
|||
final authorData = raw["author"] as Map<String, dynamic>;
|
||||
final memberData = raw["member"] as Map<String, dynamic>;
|
||||
|
||||
final author =
|
||||
Member._fromUser(authorData, memberData, client.guilds[Snowflake(raw["guild_id"])] as Guild, client);
|
||||
|
||||
final author = this.guild == null ? CachelessMember._fromUser(authorData, memberData, guildId, client) : CacheMember._fromUser(authorData, memberData, this.guild!, client);
|
||||
|
||||
client.users[author.id] = author;
|
||||
guild?.members[author.id] = author;
|
||||
this.author = author;
|
||||
|
@ -97,9 +83,10 @@ class GuildMessage extends Message implements GuildEntity {
|
|||
}
|
||||
}
|
||||
|
||||
this._roleMentions = [
|
||||
this.roleMentions = [
|
||||
if (raw["mention_roles"] != null)
|
||||
for (var r in raw["mention_roles"]) Snowflake(r)
|
||||
for (var roleId in raw["mention_roles"])
|
||||
this.guild == null ? IRole ._new(Snowflake(roleId), guildId, client) : guild!.roles[Snowflake(roleId)]!
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -121,7 +108,7 @@ abstract class Message extends SnowflakeEntity implements Disposable {
|
|||
late String content;
|
||||
|
||||
/// Channel in which message was sent
|
||||
late final MessageChannel? channel;
|
||||
late final ITextChannel channel;
|
||||
|
||||
/// Id of channel in which message was sent
|
||||
late final Snowflake channelId;
|
||||
|
@ -129,10 +116,10 @@ abstract class Message extends SnowflakeEntity implements Disposable {
|
|||
/// The timestamp of when the message was last edited, null if not edited.
|
||||
late final DateTime? editedTimestamp;
|
||||
|
||||
/// The message's author. Can be instance of [Member]
|
||||
/// The message's author. Can be instance of [CacheMember]
|
||||
IMessageAuthor get author;
|
||||
|
||||
/// The mentions in the message. [User] value of this map can be [Member]
|
||||
/// The mentions in the message. [User] value of this map can be [CacheMember]
|
||||
late List<User> mentions;
|
||||
|
||||
/// A collection of the embeds in the message.
|
||||
|
@ -174,7 +161,14 @@ abstract class Message extends SnowflakeEntity implements Disposable {
|
|||
this.content = raw["content"] as String;
|
||||
|
||||
this.channelId = Snowflake(raw["channel_id"]);
|
||||
this.channel = client.channels[this.channelId] as MessageChannel?;
|
||||
final channel = client.channels[this.channelId] as ITextChannel?;
|
||||
|
||||
if(channel == null) {
|
||||
// TODO: channel stuff
|
||||
this.channel = DummyTextChannel._new({"id" : raw["channel_id"]}, -1, client);
|
||||
} else {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
this.pinned = raw["pinned"] as bool;
|
||||
this.tts = raw["tts"] as bool;
|
||||
|
|
|
@ -2,7 +2,8 @@ part of nyxx;
|
|||
|
||||
/// Represents unicode emoji. Contains only emoji code.
|
||||
class UnicodeEmoji extends Emoji {
|
||||
UnicodeEmoji(String code) : super(code);
|
||||
/// Create unicode emoji from given code
|
||||
UnicodeEmoji(String code) : super._new(code);
|
||||
|
||||
/// Returns Emoji
|
||||
String get code => this.name;
|
||||
|
|
|
@ -1,7 +1,35 @@
|
|||
part of nyxx;
|
||||
|
||||
/// A user with [Guild] context.
|
||||
class Member extends User implements GuildEntity {
|
||||
/// Represents [Guild] member. Can be either [CachelessMember] or [CacheMember] depending on client config and cache state.
|
||||
/// Interface allows basic operations on member but does not guarantee data to be valid or available
|
||||
abstract class IMember extends User {
|
||||
IMember._new(Map<String, dynamic> raw, Nyxx client) : super._new(raw, client);
|
||||
|
||||
/// Checks if member has specified role. Returns true if user is assigned to given role.
|
||||
bool hasRole(bool Function(IRole role) func);
|
||||
|
||||
/// Bans the member and optionally deletes [deleteMessageDays] days worth of messages.
|
||||
Future<void> ban({int? deleteMessageDays, String? reason, String? auditReason});
|
||||
|
||||
/// Adds role to user
|
||||
///
|
||||
/// ```
|
||||
/// var r = guild.roles.values.first;
|
||||
/// await member.addRole(r);
|
||||
/// ```
|
||||
Future<void> addRole(IRole role, {String? auditReason});
|
||||
|
||||
/// Removes [role] from user.
|
||||
Future<void> removeRole(IRole role, {String? auditReason});
|
||||
/// Kicks the member from guild
|
||||
Future<void> kick({String? auditReason});
|
||||
|
||||
/// Edits members. Allows to move user in voice channel, mute or deaf, change nick, roles.
|
||||
Future<void> edit({String? nick, List<IRole>? roles, bool? mute, bool? deaf, VoiceChannel? channel, String? auditReason});
|
||||
}
|
||||
|
||||
/// Stateless [IMember] instance. Does not have reference to guild.
|
||||
class CachelessMember extends IMember {
|
||||
/// The members nickname, null if not set.
|
||||
String? nickname;
|
||||
|
||||
|
@ -14,61 +42,32 @@ class Member extends User implements GuildEntity {
|
|||
/// Weather or not the member is muted.
|
||||
late final bool mute;
|
||||
|
||||
/// A list of [Role]s the member has.
|
||||
late List<Role> roles;
|
||||
/// Id of guild
|
||||
final Snowflake guildId;
|
||||
|
||||
/// The highest displayed role that a member has, null if they dont have any
|
||||
Role? hoistedRole;
|
||||
/// Roles of member. It will contain instance of [IRole] if [CachelessMember] or instance of [Role] if instance of [CacheMember]
|
||||
late Iterable<IRole> roles;
|
||||
|
||||
@override
|
||||
/// Highest role of member
|
||||
late IRole? hoistedRole;
|
||||
|
||||
/// The guild that the member is a part of.
|
||||
Guild guild;
|
||||
factory CachelessMember._standard(Map<String, dynamic> data, Snowflake guildId, Nyxx client) =>
|
||||
CachelessMember._new(data, data["user"] as Map<String, dynamic>, guildId, client);
|
||||
|
||||
/// Returns highest role for member
|
||||
Role get highestRole => roles.isEmpty ? guild.everyoneRole : roles.reduce((f, s) => f.position > s.position ? f : s);
|
||||
factory CachelessMember._fromUser(Map<String, dynamic> dataUser, Map<String, dynamic> dataMember, Snowflake guildId, Nyxx client) =>
|
||||
CachelessMember._new(dataMember, dataUser, guildId, client);
|
||||
|
||||
/// Color of highest role of user
|
||||
DiscordColor get color => highestRole.color;
|
||||
|
||||
/// Voice state of member
|
||||
VoiceState? get voiceState => guild.voiceStates[this.id];
|
||||
|
||||
/// Returns total permissions of user.
|
||||
Permissions get effectivePermissions {
|
||||
if (this == guild.owner) {
|
||||
return Permissions.all();
|
||||
}
|
||||
|
||||
var total = guild.everyoneRole.permissions.raw;
|
||||
for (final role in roles) {
|
||||
total |= role.permissions.raw;
|
||||
|
||||
if (PermissionsUtils.isApplied(total, PermissionsConstants.administrator)) {
|
||||
return Permissions.fromInt(PermissionsConstants.allPermissions);
|
||||
}
|
||||
}
|
||||
|
||||
return Permissions.fromInt(total);
|
||||
}
|
||||
|
||||
factory Member._standard(Map<String, dynamic> data, Guild guild, Nyxx client) =>
|
||||
Member._new(data, data["user"] as Map<String, dynamic>, guild, client);
|
||||
|
||||
factory Member._fromUser(Map<String, dynamic> dataUser, Map<String, dynamic> dataMember, Guild guild, Nyxx client) =>
|
||||
Member._new(dataMember, dataUser, guild, client);
|
||||
|
||||
Member._new(Map<String, dynamic> raw, Map<String, dynamic> user, this.guild, Nyxx client) : super._new(user, client) {
|
||||
CachelessMember._new(Map<String, dynamic> raw, Map<String, dynamic> userRaw, this.guildId, Nyxx client) : super._new(userRaw, client) {
|
||||
this.nickname = raw["nick"] as String?;
|
||||
this.deaf = raw["deaf"] as bool;
|
||||
this.mute = raw["mute"] as bool;
|
||||
|
||||
this.roles = [for (var id in raw["roles"]) guild.roles[Snowflake(id)] as Role];
|
||||
this.roles = [for (var id in raw["roles"]) IRole._new(Snowflake(id), this.guildId, client)];
|
||||
|
||||
if (raw["hoisted_role"] != null && roles.isNotEmpty) {
|
||||
// TODO: NNBD: try-catch in where
|
||||
try {
|
||||
this.hoistedRole = this.roles.firstWhere((element) => element.id == Snowflake(raw["hoisted_role"]));
|
||||
this.hoistedRole = this.roles.firstWhere((element) => element.id == IRole._new(Snowflake(raw["hoisted_role"]), this.guildId, client));
|
||||
} on Exception {
|
||||
this.hoistedRole = null;
|
||||
}
|
||||
|
@ -83,7 +82,7 @@ class Member extends User implements GuildEntity {
|
|||
}
|
||||
}
|
||||
|
||||
bool _updateMember(String? nickname, List<Role> roles) {
|
||||
bool _updateMember(String? nickname, List<IRole> roles) {
|
||||
var changed = false;
|
||||
|
||||
if (this.nickname != nickname) {
|
||||
|
@ -100,16 +99,18 @@ class Member extends User implements GuildEntity {
|
|||
}
|
||||
|
||||
/// Checks if member has specified role. Returns true if user is assigned to given role.
|
||||
bool hasRole(bool Function(Role role) func) => this.roles.any(func);
|
||||
@override
|
||||
bool hasRole(bool Function(IRole role) func) => this.roles.any(func);
|
||||
|
||||
/// Bans the member and optionally deletes [deleteMessageDays] days worth of messages.
|
||||
@override
|
||||
Future<void> ban({int? deleteMessageDays, String? reason, String? auditReason}) async {
|
||||
final body = <String, dynamic>{
|
||||
if (deleteMessageDays != null) "delete-message-days": deleteMessageDays,
|
||||
if (reason != null) "reason": reason
|
||||
};
|
||||
|
||||
return client._http._execute(BasicRequest._new("/guilds/${this.guild.id}/bans/${this.id}",
|
||||
return client._http._execute(BasicRequest._new("/guilds/${this.guildId}/bans/${this.id}",
|
||||
method: "PUT", auditLog: auditReason, body: body));
|
||||
}
|
||||
|
||||
|
@ -119,25 +120,29 @@ class Member extends User implements GuildEntity {
|
|||
/// var r = guild.roles.values.first;
|
||||
/// await member.addRole(r);
|
||||
/// ```
|
||||
Future<void> addRole(Role role, {String? auditReason}) =>
|
||||
client._http._execute(BasicRequest._new("/guilds/${guild.id}/members/${this.id}/roles/${role.id}",
|
||||
method: "PUT", auditLog: auditReason));
|
||||
@override
|
||||
Future<void> addRole(IRole role, {String? auditReason}) =>
|
||||
client._http._execute(BasicRequest._new("/guilds/$guildId/members/${this.id}/roles/${role.id}",
|
||||
method: "PUT", auditLog: auditReason));
|
||||
|
||||
/// Removes [role] from user.
|
||||
Future<void> removeRole(Role role, {String? auditReason}) =>
|
||||
client._http._execute(BasicRequest._new(
|
||||
"/guilds/${this.guild.id.toString()}/members/${this.id.toString()}/roles/${role.id.toString()}",
|
||||
method: "DELETE",
|
||||
auditLog: auditReason));
|
||||
@override
|
||||
Future<void> removeRole(IRole role, {String? auditReason}) =>
|
||||
client._http._execute(BasicRequest._new(
|
||||
"/guilds/${this.guildId.toString()}/members/${this.id.toString()}/roles/${role.id.toString()}",
|
||||
method: "DELETE",
|
||||
auditLog: auditReason));
|
||||
|
||||
/// Kicks the member from guild
|
||||
@override
|
||||
Future<void> kick({String? auditReason}) =>
|
||||
client._http._execute(
|
||||
BasicRequest._new("/guilds/${this.guild.id}/members/${this.id}", method: "DELETE", auditLog: auditReason));
|
||||
client._http._execute(
|
||||
BasicRequest._new("/guilds/${this.guildId}/members/${this.id}", method: "DELETE", auditLog: auditReason));
|
||||
|
||||
/// Edits members. Allows to move user in voice channel, mute or deaf, change nick, roles.
|
||||
@override
|
||||
Future<void> edit(
|
||||
{String? nick, List<Role>? roles, bool? mute, bool? deaf, CacheVoiceChannel? channel, String? auditReason}) {
|
||||
{String? nick, List<IRole>? roles, bool? mute, bool? deaf, VoiceChannel? channel, String? auditReason}) {
|
||||
final body = <String, dynamic>{
|
||||
if (nick != null) "nick": nick,
|
||||
if (roles != null) "roles": roles.map((f) => f.id.toString()).toList(),
|
||||
|
@ -146,10 +151,66 @@ class Member extends User implements GuildEntity {
|
|||
if (channel != null) "channel_id": channel.id.toString()
|
||||
};
|
||||
|
||||
return client._http._execute(BasicRequest._new("/guilds/${this.guild.id.toString()}/members/${this.id.toString()}",
|
||||
return client._http._execute(BasicRequest._new("/guilds/${this.guildId.toString()}/members/${this.id.toString()}",
|
||||
method: "PATCH", auditLog: auditReason, body: body));
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => super.toString();
|
||||
}
|
||||
|
||||
/// A user with [Guild] context.
|
||||
class CacheMember extends CachelessMember implements GuildEntity {
|
||||
/// The guild that the member is a part of.
|
||||
@override
|
||||
Guild guild;
|
||||
|
||||
/// Returns highest role for member
|
||||
IRole get highestRole => this.roles.isEmpty ? guild.everyoneRole : roles.reduce((f, s) => (f as Role).position > (s as Role).position ? f : s);
|
||||
|
||||
/// Color of highest role of user
|
||||
DiscordColor get color => (highestRole as Role).color;
|
||||
|
||||
/// Voice state of member
|
||||
VoiceState? get voiceState => guild.voiceStates[this.id];
|
||||
|
||||
/// Returns total permissions of user.
|
||||
Permissions get effectivePermissions {
|
||||
if (this == guild.owner) {
|
||||
return Permissions.all();
|
||||
}
|
||||
|
||||
var total = (guild.everyoneRole as Role).permissions.raw;
|
||||
for (final role in roles) {
|
||||
if(role is! Role) {
|
||||
continue;
|
||||
}
|
||||
|
||||
total |= role.permissions.raw;
|
||||
|
||||
if (PermissionsUtils.isApplied(total, PermissionsConstants.administrator)) {
|
||||
return Permissions.fromInt(PermissionsConstants.allPermissions);
|
||||
}
|
||||
}
|
||||
|
||||
return Permissions.fromInt(total);
|
||||
}
|
||||
|
||||
// TODO: Remove duplicate
|
||||
@override
|
||||
bool _updateMember(String? nickname, List<IRole> roles) => super._updateMember(nickname, roles);
|
||||
|
||||
factory CacheMember._standard(Map<String, dynamic> data, Guild guild, Nyxx client) =>
|
||||
CacheMember._new(data, data["user"] as Map<String, dynamic>, guild, client);
|
||||
|
||||
factory CacheMember._fromUser(Map<String, dynamic> dataUser, Map<String, dynamic> dataMember, Guild guild, Nyxx client) =>
|
||||
CacheMember._new(dataMember, dataUser, guild, client);
|
||||
|
||||
CacheMember._new(Map<String, dynamic> raw, Map<String, dynamic> user, this.guild, Nyxx client) : super._new(raw, user, guild.id, client) {
|
||||
this.roles = [
|
||||
for(final role in this.roles)
|
||||
// TODO: NNBD
|
||||
this.guild.roles[role.id]!
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ class ChannelPinsUpdateEvent {
|
|||
this.lastPingTimestamp = DateTime.parse(raw["d"]["last_pin_timestamp"] as String);
|
||||
}
|
||||
|
||||
this.channel = client.channels[Snowflake(raw["d"]["channel_id"])] as CachelessTextChannel;
|
||||
this.channel = client.channels[Snowflake(raw["d"]["channel_id"])] as CachelessTextChannel?;
|
||||
|
||||
if (raw["d"]["guild_id"] != null) {
|
||||
this.guildId = Snowflake(raw["d"]["guild_id"]);
|
||||
|
|
|
@ -89,7 +89,7 @@ class GuildMemberRemoveEvent {
|
|||
/// Sent when a member is updated.
|
||||
class GuildMemberUpdateEvent {
|
||||
/// The member after the update if member is updated.
|
||||
late final Member? member;
|
||||
late final CacheMember? member;
|
||||
|
||||
/// User if user is updated. Will be null if member is not null.
|
||||
late final User? user;
|
||||
|
@ -110,7 +110,7 @@ class GuildMemberUpdateEvent {
|
|||
final nickname = raw["d"]["nickname"] as String?;
|
||||
final roles = (raw["d"]["roles"] as List<dynamic>).map((str) => guild.roles[Snowflake(str)]!).toList();
|
||||
|
||||
if (member._updateMember(nickname, roles)) {
|
||||
if (this.member!._updateMember(nickname, roles)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -122,7 +122,7 @@ class GuildMemberUpdateEvent {
|
|||
/// Sent when a member joins a guild.
|
||||
class GuildMemberAddEvent {
|
||||
/// The member that joined.
|
||||
late final Member? member;
|
||||
late final CacheMember? member;
|
||||
|
||||
GuildMemberAddEvent._new(Map<String, dynamic> raw, Nyxx client) {
|
||||
final guild = client.guilds[Snowflake(raw["d"]["guild_id"])];
|
||||
|
@ -131,7 +131,7 @@ class GuildMemberAddEvent {
|
|||
return;
|
||||
}
|
||||
|
||||
this.member = Member._standard(raw["d"] as Map<String, dynamic>, guild, client);
|
||||
this.member = CacheMember._standard(raw["d"] as Map<String, dynamic>, guild, client);
|
||||
|
||||
guild.members[member!.id] = member!;
|
||||
if (!client.users.hasKey(member!.id)) {
|
||||
|
@ -207,8 +207,10 @@ class GuildEmojisUpdateEvent {
|
|||
/// New list of changes emojis
|
||||
final Map<Snowflake, GuildEmoji> emojis = {};
|
||||
|
||||
/// Id of guild where event happend
|
||||
late final Snowflake guildId;
|
||||
|
||||
/// Instance of guild if available
|
||||
late final Guild? guild;
|
||||
|
||||
GuildEmojisUpdateEvent._new(Map<String, dynamic> json, Nyxx client) {
|
||||
|
@ -233,8 +235,10 @@ class RoleCreateEvent {
|
|||
/// The role that was created.
|
||||
late final Role role;
|
||||
|
||||
/// Id of guild where event happend
|
||||
late final Snowflake guildId;
|
||||
|
||||
/// Instance of [Guild] if available
|
||||
late final Guild? guild;
|
||||
|
||||
RoleCreateEvent._new(Map<String, dynamic> json, Nyxx client) {
|
||||
|
@ -243,20 +247,23 @@ class RoleCreateEvent {
|
|||
|
||||
this.role = Role._new(json["d"]["role"] as Map<String, dynamic>, guildId, client);
|
||||
if (guild != null) {
|
||||
guild!.roles[role!.id] = role!;
|
||||
guild!.roles[role.id] = role;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sent when a role is deleted.
|
||||
class RoleDeleteEvent {
|
||||
/// The role that was deleted.
|
||||
Role? role;
|
||||
/// The role that was deleted, if available
|
||||
IRole? role;
|
||||
|
||||
/// Id of tole that was deleted
|
||||
late final Snowflake roleId;
|
||||
|
||||
/// Id of guild where event happend
|
||||
late final Snowflake guildId;
|
||||
|
||||
/// Instance of [Guild] if available
|
||||
late final Guild? guild;
|
||||
|
||||
RoleDeleteEvent._new(Map<String, dynamic> json, Nyxx client) {
|
||||
|
@ -275,9 +282,10 @@ class RoleDeleteEvent {
|
|||
class RoleUpdateEvent {
|
||||
/// The role after the update.
|
||||
late final Role role;
|
||||
|
||||
/// Id of guild where event happend
|
||||
late final Snowflake guildId;
|
||||
|
||||
/// Instance of [Guild] if available
|
||||
late final Guild? guild;
|
||||
|
||||
RoleUpdateEvent._new(Map<String, dynamic> json, Nyxx client) {
|
||||
|
|
|
@ -4,7 +4,7 @@ part of nyxx;
|
|||
/// You can use the `chunk_index` and `chunk_count` to calculate how many chunks are left for your request.
|
||||
class MemberChunkEvent {
|
||||
/// Guild members
|
||||
late final Iterable<Member> members;
|
||||
late final Iterable<IMember> members;
|
||||
|
||||
/// Id of guild
|
||||
late final Snowflake guildId;
|
||||
|
@ -44,7 +44,7 @@ class MemberChunkEvent {
|
|||
|
||||
this.members = [
|
||||
for (var memberRaw in raw["d"]["members"])
|
||||
Member._standard(memberRaw as Map<String, dynamic>, this.guild!, client)
|
||||
CacheMember._standard(memberRaw as Map<String, dynamic>, this.guild!, client)
|
||||
];
|
||||
|
||||
// TODO: Thats probably redundant
|
||||
|
|
|
@ -7,7 +7,7 @@ class MessageReceivedEvent {
|
|||
|
||||
MessageReceivedEvent._new(Map<String, dynamic> raw, Nyxx client) {
|
||||
this.message = Message._deserialize(raw["d"] as Map<String, dynamic>, client);
|
||||
message.channel?.messages.put(this.message);
|
||||
message.channel.messages.put(this.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ class MessageDeleteEvent {
|
|||
|
||||
if (message != null) {
|
||||
this.message = message;
|
||||
message.channel?.messages.remove(this.messageId);
|
||||
message.channel.messages.remove(this.messageId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ part of nyxx;
|
|||
/// Sent when a user starts typing.
|
||||
class TypingEvent {
|
||||
/// The channel that the user is typing in.
|
||||
MessageChannel? channel;
|
||||
ITextChannel? channel;
|
||||
|
||||
/// Id of the channel that the user is typing in.
|
||||
late final Snowflake channelId;
|
||||
|
@ -19,7 +19,7 @@ class TypingEvent {
|
|||
|
||||
TypingEvent._new(Map<String, dynamic> json, Nyxx client) {
|
||||
this.channelId = Snowflake(json["d"]["channel_id"]);
|
||||
this.channel = client.channels[channelId] as MessageChannel?;
|
||||
this.channel = client.channels[channelId] as ITextChannel?;
|
||||
|
||||
this.userId = Snowflake(json["d"]["user_id"]);
|
||||
this.user = client.users[this.userId];
|
||||
|
|
|
@ -2,7 +2,6 @@ part of nyxx;
|
|||
|
||||
/// Emitted when guild's voice server changes
|
||||
class VoiceServerUpdateEvent {
|
||||
|
||||
/// Raw websocket event payload
|
||||
final Map<String, dynamic> raw;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
part of nyxx;
|
||||
|
||||
//TODO: Consider what should be here and what should not
|
||||
/// Could be either [User], [Member] or [Webhook].
|
||||
/// Could be either [User], [CacheMember] or [Webhook].
|
||||
/// [Webhook] will have most of field missing.
|
||||
abstract class IMessageAuthor implements SnowflakeEntity {
|
||||
/// User name
|
||||
|
|
|
@ -3,19 +3,19 @@ part of nyxx;
|
|||
/// Util function for manipulating permissions
|
||||
class PermissionsUtils {
|
||||
/// Allows to check if [issueMember] or [issueRole] can interact with [targetMember] or [targetRole].
|
||||
static bool canInteract({Member? issueMember, Role? issueRole, Member? targetMember, Role? targetRole}) {
|
||||
static bool canInteract({CacheMember? issueMember, Role? issueRole, CacheMember? targetMember, Role? targetRole}) {
|
||||
bool canInter(Role role1, Role role2) => role1.position > role2.position;
|
||||
|
||||
if (issueMember != null && targetMember != null) {
|
||||
if (issueMember.guild != targetMember.guild) return false;
|
||||
|
||||
return canInter(issueMember.highestRole, targetMember.highestRole);
|
||||
return canInter(issueMember.highestRole as Role, targetMember.highestRole as Role);
|
||||
}
|
||||
|
||||
if (issueMember != null && targetRole != null) {
|
||||
if (issueMember.guild != targetRole.guild) return false;
|
||||
|
||||
return canInter(issueMember.highestRole, targetRole);
|
||||
return canInter(issueMember.highestRole as Role, targetRole);
|
||||
}
|
||||
|
||||
if (issueRole != null && targetRole != null) {
|
||||
|
@ -28,7 +28,7 @@ class PermissionsUtils {
|
|||
}
|
||||
|
||||
/// Returns List of [channel] permissions overrides for given [member].
|
||||
static List<int> getOverrides(Member member, CacheGuildChannel channel) {
|
||||
static List<int> getOverrides(CacheMember member, CacheGuildChannel channel) {
|
||||
var allowRaw = 0;
|
||||
var denyRaw = 0;
|
||||
|
||||
|
|
|
@ -10,11 +10,12 @@ documentation: https://github.com/l7ssha/nyxx/wiki
|
|||
issue_tracker: https://github.com/l7ssha/nyxx/issue
|
||||
|
||||
environment:
|
||||
sdk: '>=2.9.0-2.0.dev <3.0.0'
|
||||
sdk: '>=2.9.0-11.0.dev <3.0.0'
|
||||
|
||||
dependencies:
|
||||
logging: "^0.11.4"
|
||||
w_transport: "^3.2.8"
|
||||
http: "^0.12.1"
|
||||
|
||||
dev_dependencies:
|
||||
dart_style:
|
||||
|
|
|
@ -124,7 +124,7 @@ void main() {
|
|||
final field = embed.fields.first;
|
||||
|
||||
if (field.name == "Test field" && field.content == "Test value" && !field.inline!) {
|
||||
await e.message.channel?.send(content: "Tests completed successfully!");
|
||||
await e.message.channel.send(content: "Tests completed successfully!");
|
||||
print("Nyxx tests completed successfully!");
|
||||
exit(0);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue