discorb 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +56 -0
  3. data/.yardopts +6 -0
  4. data/Changelog.md +5 -0
  5. data/Gemfile +23 -0
  6. data/Gemfile.lock +70 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +53 -0
  9. data/Rakefile +46 -0
  10. data/bin/console +15 -0
  11. data/bin/setup +8 -0
  12. data/discorb.gemspec +37 -0
  13. data/docs/Examples.md +26 -0
  14. data/docs/events.md +480 -0
  15. data/docs/voice_events.md +283 -0
  16. data/examples/components/authorization_button.rb +43 -0
  17. data/examples/components/select_menu.rb +61 -0
  18. data/examples/extension/main.rb +12 -0
  19. data/examples/extension/message_expander.rb +41 -0
  20. data/examples/simple/eval.rb +32 -0
  21. data/examples/simple/ping_pong.rb +16 -0
  22. data/examples/simple/rolepanel.rb +65 -0
  23. data/examples/simple/wait_for_message.rb +30 -0
  24. data/lib/discorb/application.rb +157 -0
  25. data/lib/discorb/asset.rb +57 -0
  26. data/lib/discorb/audit_logs.rb +323 -0
  27. data/lib/discorb/channel.rb +1101 -0
  28. data/lib/discorb/client.rb +363 -0
  29. data/lib/discorb/color.rb +173 -0
  30. data/lib/discorb/common.rb +123 -0
  31. data/lib/discorb/components.rb +290 -0
  32. data/lib/discorb/dictionary.rb +119 -0
  33. data/lib/discorb/embed.rb +345 -0
  34. data/lib/discorb/emoji.rb +218 -0
  35. data/lib/discorb/emoji_table.rb +3799 -0
  36. data/lib/discorb/error.rb +98 -0
  37. data/lib/discorb/event.rb +35 -0
  38. data/lib/discorb/extend.rb +18 -0
  39. data/lib/discorb/extension.rb +54 -0
  40. data/lib/discorb/file.rb +69 -0
  41. data/lib/discorb/flag.rb +109 -0
  42. data/lib/discorb/gateway.rb +967 -0
  43. data/lib/discorb/gateway_requests.rb +47 -0
  44. data/lib/discorb/guild.rb +1244 -0
  45. data/lib/discorb/guild_template.rb +211 -0
  46. data/lib/discorb/image.rb +43 -0
  47. data/lib/discorb/integration.rb +111 -0
  48. data/lib/discorb/intents.rb +137 -0
  49. data/lib/discorb/interaction.rb +333 -0
  50. data/lib/discorb/internet.rb +285 -0
  51. data/lib/discorb/invite.rb +145 -0
  52. data/lib/discorb/log.rb +70 -0
  53. data/lib/discorb/member.rb +232 -0
  54. data/lib/discorb/message.rb +583 -0
  55. data/lib/discorb/modules.rb +138 -0
  56. data/lib/discorb/permission.rb +270 -0
  57. data/lib/discorb/presence.rb +308 -0
  58. data/lib/discorb/reaction.rb +48 -0
  59. data/lib/discorb/role.rb +189 -0
  60. data/lib/discorb/sticker.rb +157 -0
  61. data/lib/discorb/user.rb +163 -0
  62. data/lib/discorb/utils.rb +16 -0
  63. data/lib/discorb/voice_state.rb +251 -0
  64. data/lib/discorb/webhook.rb +420 -0
  65. data/lib/discorb.rb +51 -0
  66. metadata +120 -0
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Discorb
4
+ #
5
+ # Module for sending and reading messages.
6
+ #
7
+ module Messageable
8
+ #
9
+ # Post a message to the channel.
10
+ #
11
+ # @param [String] content The message content.
12
+ # @param [Boolean] tts Whether the message is tts.
13
+ # @param [Discorb::Embed] embed The embed to send.
14
+ # @param [Array<Discorb::Embed>] embeds The embeds to send.
15
+ # @param [Discorb::AllowedMentions] allowed_mentions The allowed mentions.
16
+ # @param [Discorb::Message, Discorb::Message::Reference] reference The message to reply to.
17
+ # @param [Array<Discorb::Components>, Array<Array<Discorb::Components>>] components The components to send.
18
+ # @param [Discorb::File] file The file to send.
19
+ # @param [Array<Discorb::File>] files The files to send.
20
+ #
21
+ # @return [Discorb::Message] The message sent.
22
+ #
23
+ def post(content = nil, tts: false, embed: nil, embeds: nil, allowed_mentions: nil,
24
+ reference: nil, components: nil, file: nil, files: nil)
25
+ Async do |_task|
26
+ payload = {}
27
+ payload[:content] = content if content
28
+ payload[:tts] = tts
29
+ tmp_embed = if embed
30
+ [embed]
31
+ elsif embeds
32
+ embeds
33
+ end
34
+ payload[:embeds] = tmp_embed.map(&:to_hash) if tmp_embed
35
+ payload[:allowed_mentions] =
36
+ allowed_mentions ? allowed_mentions.to_hash(@client.allowed_mentions) : @client.allowed_mentions.to_hash
37
+ payload[:message_reference] = reference.to_reference if reference
38
+ if components
39
+ tmp_components = []
40
+ tmp_row = []
41
+ components.each do |c|
42
+ case c
43
+ when Array
44
+ tmp_components << tmp_row
45
+ tmp_row = []
46
+ tmp_components << c
47
+ when SelectMenu
48
+ tmp_components << tmp_row
49
+ tmp_row = []
50
+ tmp_components << [c]
51
+ else
52
+ tmp_row << c
53
+ end
54
+ end
55
+ tmp_components << tmp_row
56
+ payload[:components] = tmp_components.filter { |c| c.length.positive? }.map { |c| { type: 1, components: c.map(&:to_hash) } }
57
+ end
58
+ files = [file] if file
59
+ if files
60
+ headers, payload = Internet.multipart(payload, files)
61
+ else
62
+ headers = {}
63
+ end
64
+ _resp, data = @client.internet.post("#{base_url.wait}/messages", payload, headers: headers).wait
65
+ Message.new(@client, data.merge({ guild_id: @guild_id.to_s }))
66
+ end
67
+ end
68
+
69
+ #
70
+ # Fetch a message from ID.
71
+ #
72
+ # @param [Discorb::Snowflake] id The ID of the message.
73
+ #
74
+ # @return [Discorb::Message] The message.
75
+ # @raise [Discorb::NotFoundError] If the message is not found.
76
+ #
77
+ def fetch_message(id)
78
+ Async do
79
+ _resp, data = @client.internet.get("#{base_url.wait}/messages/#{id}").wait
80
+ Message.new(@client, data.merge({ guild_id: @guild_id.to_s }))
81
+ end
82
+ end
83
+
84
+ #
85
+ # Fetch a message history.
86
+ #
87
+ # @param [Integer] limit The number of messages to fetch.
88
+ # @param [Discorb::Snowflake] before The ID of the message to fetch before.
89
+ # @param [Discorb::Snowflake] after The ID of the message to fetch after.
90
+ # @param [Discorb::Snowflake] around The ID of the message to fetch around.
91
+ #
92
+ # @return [Array<Discorb::Message>] The messages.
93
+ #
94
+ def fetch_messages(limit = 50, before: nil, after: nil, around: nil)
95
+ Async do
96
+ params = {
97
+ limit: limit,
98
+ before: Discorb::Utils.try(after, :id),
99
+ after: Discorb::Utils.try(around, :id),
100
+ around: Discorb::Utils.try(before, :id),
101
+ }.filter { |_k, v| !v.nil? }.to_h
102
+ _resp, messages = @client.internet.get("#{base_url.wait}/messages?#{URI.encode_www_form(params)}").wait
103
+ messages.map { |m| Message.new(@client, m.merge({ guild_id: @guild_id.to_s })) }
104
+ end
105
+ end
106
+
107
+ #
108
+ # Trigger the typing indicator in the channel.
109
+ # @macro async
110
+ # @macro http
111
+ #
112
+ # If block is given, trigger typing indicator during executing block.
113
+ # @example
114
+ # channel.typing do
115
+ # channel.post("Waiting for 60 seconds...")
116
+ # sleep 60
117
+ # channel.post("Done!")
118
+ # end
119
+ #
120
+ def typing
121
+ Async do |task|
122
+ if block_given?
123
+ begin
124
+ post_task = task.async do
125
+ @client.internet.post("/channels/#{@id}/typing", {})
126
+ sleep(5)
127
+ end
128
+ yield
129
+ ensure
130
+ post_task.stop
131
+ end
132
+ else
133
+ @client.internet.post("/channels/#{@id}/typing", {})
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,270 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Discorb
4
+ #
5
+ # Represents a permission per guild.
6
+ # ## Flag fields
7
+ # |`1 << 0`|`:create_instant_invite`|
8
+ # |`1 << 1`|`:kick_members`|
9
+ # |`1 << 2`|`:ban_members`|
10
+ # |`1 << 3`|`:administrator`|
11
+ # |`1 << 4`|`:manage_channels`|
12
+ # |`1 << 5`|`:manage_guild`|
13
+ # |`1 << 6`|`:add_reactions`|
14
+ # |`1 << 7`|`:view_audit_log`|
15
+ # |`1 << 8`|`:priority_speaker`|
16
+ # |`1 << 9`|`:stream`|
17
+ # |`1 << 10`|`:view_channel`|
18
+ # |`1 << 11`|`:send_messages`|
19
+ # |`1 << 12`|`:send_tts_messages`|
20
+ # |`1 << 13`|`:manage_messages`|
21
+ # |`1 << 14`|`:embed_links`|
22
+ # |`1 << 15`|`:attach_files`|
23
+ # |`1 << 16`|`:read_message_history`|
24
+ # |`1 << 17`|`:mention_everyone`|
25
+ # |`1 << 18`|`:use_external_emojis`|
26
+ # |`1 << 19`|`:view_guild_insights`|
27
+ # |`1 << 20`|`:connect`|
28
+ # |`1 << 21`|`:speak`|
29
+ # |`1 << 22`|`:mute_members`|
30
+ # |`1 << 23`|`:deafen_members`|
31
+ # |`1 << 24`|`:move_members`|
32
+ # |`1 << 25`|`:use_vad`|
33
+ # |`1 << 26`|`:change_nickname`|
34
+ # |`1 << 27`|`:manage_nicknames`|
35
+ # |`1 << 28`|`:manage_roles`|
36
+ # |`1 << 29`|`:manage_webhooks`|
37
+ # |`1 << 30`|`:manage_emojis`|
38
+ # |`1 << 31`|`:use_slash_commands`|
39
+ # |`1 << 32`|`:request_to_speak`|
40
+ # |`1 << 34`|`:manage_threads`|
41
+ # |`1 << 35`|`:use_public_threads`|
42
+ # |`1 << 36`|`:use_private_threads`|
43
+ #
44
+ class Permission < Flag
45
+ @bits = {
46
+ create_instant_invite: 0,
47
+ kick_members: 1,
48
+ ban_members: 2,
49
+ administrator: 3,
50
+ manage_channels: 4,
51
+ manage_guild: 5,
52
+ add_reactions: 6,
53
+ view_audit_log: 7,
54
+ priority_speaker: 8,
55
+ stream: 9,
56
+ view_channel: 10,
57
+ send_messages: 11,
58
+ send_tts_messages: 12,
59
+ manage_messages: 13,
60
+ embed_links: 14,
61
+ attach_files: 15,
62
+ read_message_history: 16,
63
+ mention_everyone: 17,
64
+ use_external_emojis: 18,
65
+ view_guild_insights: 19,
66
+ connect: 20,
67
+ speak: 21,
68
+ mute_members: 22,
69
+ deafen_members: 23,
70
+ move_members: 24,
71
+ use_vad: 25,
72
+ change_nickname: 26,
73
+ manage_nicknames: 27,
74
+ manage_roles: 28,
75
+ manage_webhooks: 29,
76
+ manage_emojis: 30,
77
+ use_slash_commands: 31,
78
+ request_to_speak: 32,
79
+ manage_threads: 34,
80
+ use_public_threads: 35,
81
+ use_private_threads: 36,
82
+ }.freeze
83
+ end
84
+
85
+ #
86
+ # Represents a permission per channel.
87
+ #
88
+ class PermissionOverwrite
89
+ # @!attribute [r] allow
90
+ # @return [Discorb::Permission] The allowed permissions.
91
+ # @!attribute [r] deny
92
+ # @return [Discorb::Permission] The denied permissions.
93
+ # @!attribute [r] allow_value
94
+ # @return [Integer] The allowed permissions as an integer.
95
+ # @!attribute [r] deny_value
96
+ # @return [Integer] The denied permissions as an integer.
97
+
98
+ @raw_bits = {
99
+ create_instant_invite: 0,
100
+ kick_members: 1,
101
+ ban_members: 2,
102
+ administrator: 3,
103
+ manage_channels: 4,
104
+ manage_guild: 5,
105
+ add_reactions: 6,
106
+ view_audit_log: 7,
107
+ priority_speaker: 8,
108
+ stream: 9,
109
+ view_channel: 10,
110
+ send_messages: 11,
111
+ send_tts_messages: 12,
112
+ manage_messages: 13,
113
+ embed_links: 14,
114
+ attach_files: 15,
115
+ read_message_history: 16,
116
+ mention_everyone: 17,
117
+ use_external_emojis: 18,
118
+ view_guild_insights: 19,
119
+ connect: 20,
120
+ speak: 21,
121
+ mute_members: 22,
122
+ deafen_members: 23,
123
+ move_members: 24,
124
+ use_vad: 25,
125
+ change_nickname: 26,
126
+ manage_nicknames: 27,
127
+ manage_roles: 28,
128
+ manage_webhooks: 29,
129
+ manage_emojis: 30,
130
+ use_slash_commands: 31,
131
+ request_to_speak: 32,
132
+ manage_threads: 34,
133
+ use_public_threads: 35,
134
+ use_private_threads: 36,
135
+ }.freeze
136
+ @bits = @raw_bits.transform_values { |v| 1 << v }.freeze
137
+
138
+ # @!visibility private
139
+ def initialize(allow, deny)
140
+ @allow = allow
141
+ @deny = deny
142
+ end
143
+
144
+ def allow
145
+ self.class.bits.keys.filter { |field| @allow & self.class.bits[field] != 0 }
146
+ end
147
+
148
+ alias +@ allow
149
+
150
+ def deny
151
+ self.class.bits.keys.filter { |field| @deny & self.class.bits[field] != 0 }
152
+ end
153
+
154
+ alias -@ deny
155
+
156
+ def allow_value
157
+ @allow
158
+ end
159
+
160
+ def deny_value
161
+ @deny
162
+ end
163
+
164
+ #
165
+ # Converts the permission overwrite to a hash.
166
+ #
167
+ # @return [Hash] The permission overwrite as a hash.
168
+ #
169
+ def to_hash
170
+ self.class.bits.keys.map do |field|
171
+ [field, if @allow & self.class.bits[field] != 0
172
+ true
173
+ elsif @deny & self.class.bits[method] != 0
174
+ false
175
+ end]
176
+ end.to_h
177
+ end
178
+
179
+ #
180
+ # Union of the permission overwrites.
181
+ #
182
+ # @param [Discorb::PermissionOverwrite] other The other permission overwrite.
183
+ #
184
+ # @return [Discorb::PermissionOverwrite] The union of the permission overwrites.
185
+ #
186
+ def +(other)
187
+ result = to_hash
188
+ self.class.bits.each_key do |field|
189
+ result[field] = other[field] unless other[field].nil?
190
+ end
191
+ self.class.from_hash(result)
192
+ end
193
+
194
+ #
195
+ # Returns whether overwrite of the given field.
196
+ #
197
+ # @param [Symbol] field The field to check.
198
+ #
199
+ # @return [true, false, nil] Whether the field is allowed, denied or not set.
200
+ #
201
+ def [](field)
202
+ if @allow & self.class.bits[field] != 0
203
+ true
204
+ elsif @deny & self.class.bits[field] != 0
205
+ false
206
+ end
207
+ end
208
+
209
+ #
210
+ # Sets the given field to the given value.
211
+ #
212
+ # @param [Symbol] key The field to set.
213
+ # @param [Boolean] bool The value to set.
214
+ #
215
+ def []=(key, bool)
216
+ case bool
217
+ when true
218
+ @allow |= self.class.bits[key]
219
+ @deny &= ~self.class.bits[key]
220
+ when false
221
+ @allow &= ~self.class.bits[key]
222
+ @deny |= self.class.bits[key]
223
+ else
224
+ @allow &= ~self.class.bits[key]
225
+ @deny &= ~self.class.bits[key]
226
+ end
227
+ end
228
+
229
+ def method_missing(method, bool = nil)
230
+ if self.class.bits.key?(method)
231
+ self[method]
232
+ elsif self.class.bits.key?(method.to_s.delete_suffix("=").to_sym)
233
+ key = method.to_s.delete_suffix("=").to_sym
234
+ self[key] = bool
235
+ else
236
+ super
237
+ end
238
+ end
239
+
240
+ def respond_to_missing?(method, _arg)
241
+ self.class.bits.key?(method.to_s.delete_suffix("=").to_sym) ? true : super
242
+ end
243
+
244
+ class << self
245
+ # @!visibility private
246
+ attr_reader :bits
247
+
248
+ #
249
+ # Initializes a permission overwrite from a hash.
250
+ #
251
+ # @param [Hash] hash The hash to initialize the permission overwrite from.
252
+ #
253
+ # @return [Discorb::PermissionOverwrite] The permission overwrite.
254
+ #
255
+ def from_hash(hash)
256
+ allow = 0
257
+ deny = 0
258
+ hash.filter { |k, v| self.class.bits.keys.include?(k) && [true, false].include?(v) }.each do |k, v|
259
+ if v
260
+ allow += self.class.bits[k]
261
+ else
262
+ deny += self.class.bits[k]
263
+ end
264
+ end
265
+
266
+ new(allow, deny)
267
+ end
268
+ end
269
+ end
270
+ end
@@ -0,0 +1,308 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Discorb
4
+ #
5
+ # Represents a presence of user.
6
+ #
7
+ class Presence < DiscordModel
8
+ # @return [:online, :idle, :dnd, :offline] The status of the user.
9
+ attr_reader :status
10
+ # @return [Array<Discorb::Presence::Activity>] The activities of the user.
11
+ attr_reader :activities
12
+ # @return [Discorb::Presence::ClientStatus] The client status of the user.
13
+ attr_reader :client_status
14
+
15
+ # @!attribute [r] user
16
+ # @return [Discorb::User] The user of the presence.
17
+ # @!attribute [r] guild
18
+ # @return [Discorb::Guild] The guild of the presence.
19
+ # @!attribute [r] activity
20
+ # @return [Discorb::Presence::Activity] The activity of the presence.
21
+
22
+ # @!visibility private
23
+ def initialize(client, data)
24
+ @client = client
25
+ @data = data
26
+ _set_data(data)
27
+ end
28
+
29
+ def user
30
+ @client.users[@user_id]
31
+ end
32
+
33
+ def guild
34
+ @client.guilds[@guild_id]
35
+ end
36
+
37
+ def activity
38
+ @activities[0]
39
+ end
40
+
41
+ def inspect
42
+ "#<#{self.class} @status=#{@status.inspect} @activity=#{activity.inspect}>"
43
+ end
44
+
45
+ #
46
+ # Represents an activity of a user.
47
+ #
48
+ class Activity < DiscordModel
49
+ # @return [String] The name of the activity.
50
+ attr_reader :name
51
+ # @return [:game, :streaming, :listening, :watching, :custom, :competing] The type of the activity.
52
+ attr_reader :type
53
+ # @return [String] The url of the activity.
54
+ attr_reader :url
55
+ # @return [Time] The time the activity was created.
56
+ attr_reader :created_at
57
+ alias started_at created_at
58
+ # @return [Discorb::Presence::Activity::Timestamps] The timestamps of the activity.
59
+ attr_reader :timestamps
60
+ # @return [Discorb::Snowflake] The application id of the activity.
61
+ attr_reader :application_id
62
+ # @return [String] The details of the activity.
63
+ attr_reader :details
64
+ # @return [String] The state of party.
65
+ attr_reader :state
66
+ # @return [Discorb::Emoji] The emoji of the activity.
67
+ attr_reader :emoji
68
+ # @return [Discorb::Presence::Activity::Party] The party of the activity.
69
+ # @return [nil] If the activity is not a party activity.
70
+ attr_reader :party
71
+ # @return [Discorb::Presence::Activity::Asset] The assets of the activity.
72
+ # @return [nil] If the activity has no assets.
73
+ attr_reader :assets
74
+ # @return [Discorb::StageInstance] The instance of the activity.
75
+ # @return [nil] If the activity is not a stage activity.
76
+ attr_reader :instance
77
+ # @return [Array<Discorb::Presence::Activity::Button>] The buttons of the activity.
78
+ # @return [nil] If the activity has no buttons.
79
+ attr_reader :buttons
80
+ # @return [Discorb::Presence::Activity::Flag] The flags of the activity.
81
+ attr_reader :flags
82
+
83
+ @activity_types = {
84
+ 0 => :game,
85
+ 1 => :streaming,
86
+ 2 => :listening,
87
+ 3 => :watching,
88
+ 4 => :custom,
89
+ 5 => :competing,
90
+ }
91
+
92
+ # @!visibility private
93
+ def initialize(data)
94
+ @name = data[:name]
95
+ @type = self.class.activity_types[data[:type]]
96
+ @url = data[:url]
97
+ @created_at = Time.at(data[:created_at])
98
+ @timestamps = data[:timestamps] && Timestamps.new(data[:timestamps])
99
+ @application_id = data[:application_id] && Snowflake.new(data[:application_id])
100
+ @details = data[:details]
101
+ @state = data[:state]
102
+ @emoji = if data[:emoji]
103
+ data[:emoji][:id].nil? ? UnicodeEmoji.new(data[:emoji][:name]) : PartialEmoji.new(data[:emoji])
104
+ end
105
+ @party = data[:party] && Party.new(data[:party])
106
+ @assets = data[:assets] && Asset.new(data[:assets])
107
+ @instance = data[:instance]
108
+ @buttons = data[:buttons] && data[:buttons].map { |b| Button.new(b) }
109
+ @flags = data[:flags] && Flag.new(data[:flags])
110
+ end
111
+
112
+ #
113
+ # Convert the activity to a string.
114
+ #
115
+ # @return [String] The string representation of the activity.
116
+ #
117
+ def to_s
118
+ case @type
119
+ when :game
120
+ "Playing #{@name}"
121
+ when :streaming
122
+ "Streaming #{@details}"
123
+ when :listening
124
+ "Listening to #{@name}"
125
+ when :watching
126
+ "Watching #{@name}"
127
+ when :custom
128
+ "#{@emoji} #{@state}"
129
+ when :competing
130
+ "Competing in #{@name}"
131
+ end
132
+ end
133
+
134
+ #
135
+ # Represents the timestamps of an activity.
136
+ #
137
+ class Timestamps < DiscordModel
138
+ # @return [Time] The start time of the activity.
139
+ attr_reader :start
140
+ # @return [Time] The end time of the activity.
141
+ attr_reader :end
142
+
143
+ # @!visibility private
144
+ def initialize(data)
145
+ @start = data[:start] && Time.at(data[:start])
146
+ @end = data[:end] && Time.at(data[:end])
147
+ end
148
+ end
149
+
150
+ class Party < DiscordModel
151
+ # @return [String] The id of the party.
152
+ attr_reader :id
153
+
154
+ # @!attribute [r] current_size
155
+ # @return [Integer] The current size of the party.
156
+ # @!attribute [r] max_size
157
+ # @return [Integer] The max size of the party.
158
+
159
+ # @!visibility private
160
+ def initialize(data)
161
+ @id = data[:id]
162
+ @size = data[:size]
163
+ end
164
+
165
+ def current_size
166
+ @size[0]
167
+ end
168
+
169
+ def max_size
170
+ @size[1]
171
+ end
172
+ end
173
+
174
+ #
175
+ # Represents the assets of an activity.
176
+ #
177
+ class Asset < DiscordModel
178
+ # @return [String] The large image ID of the asset.
179
+ attr_reader :large_image
180
+ alias large_id large_image
181
+ # @return [String] The large text of the activity.
182
+ attr_reader :large_text
183
+ # @return [String] The small image ID of the activity.
184
+ attr_reader :small_image
185
+ alias small_id small_image
186
+ # @return [String] The small text of the activity.
187
+ attr_reader :small_text
188
+
189
+ def initialize(data)
190
+ @large_image = data[:large_image]
191
+ @large_text = data[:large_text]
192
+ @small_image = data[:small_image]
193
+ @small_text = data[:small_text]
194
+ end
195
+ end
196
+
197
+ #
198
+ # Represents the flags of an activity.
199
+ # ## Flag fields
200
+ # |`1 << 0`|`:instance`|
201
+ # |`1 << 1`|`:join`|
202
+ # |`1 << 2`|`:spectate`|
203
+ # |`1 << 3`|`:join_request`|
204
+ # |`1 << 4`|`:sync`|
205
+ # |`1 << 5`|`:play`|
206
+ #
207
+ class Flag < Discorb::Flag
208
+ @bits = {
209
+ instance: 0,
210
+ join: 1,
211
+ spectate: 2,
212
+ join_request: 3,
213
+ sync: 4,
214
+ play: 5,
215
+ }
216
+ end
217
+
218
+ #
219
+ # Represents a secrets of an activity.
220
+ #
221
+ class Secrets < DiscordModel
222
+ # @return [String] The join secret of the activity.
223
+ attr_reader :join
224
+ # @return [String] The spectate secret of the activity.
225
+ attr_reader :spectate
226
+ # @return [String] The match secret of the activity.
227
+ attr_reader :match
228
+
229
+ # @!visibility private
230
+ def initialize(data)
231
+ @join = data[:join]
232
+ @spectate = data[:spectate]
233
+ @match = data[:match]
234
+ end
235
+ end
236
+
237
+ #
238
+ # Represents a button of an activity.
239
+ #
240
+ class Button < DiscordModel
241
+ # @return [String] The text of the button.
242
+ attr_reader :label
243
+ # @return [String] The URL of the button.
244
+ attr_reader :url
245
+ alias text label
246
+
247
+ # @!visibility private
248
+ def initialize(data)
249
+ @label = data[0]
250
+ @url = data[1]
251
+ end
252
+ end
253
+
254
+ class << self
255
+ # @!visibility private
256
+ attr_reader :activity_types
257
+ end
258
+ end
259
+
260
+ #
261
+ # Represents a user's client status.
262
+ #
263
+ class ClientStatus < DiscordModel
264
+ # @return [Symbol] The desktop status of the user.
265
+ attr_reader :desktop
266
+ # @return [Symbol] The mobile status of the user.
267
+ attr_reader :mobile
268
+ # @return [Symbol] The web status of the user.
269
+ attr_reader :web
270
+
271
+ # @!attribute [r] desktop?
272
+ # @return [Boolean] Whether the user is not offline on desktop.
273
+ # @!attribute [r] mobile?
274
+ # @return [Boolean] Whether the user is not offline on mobile.
275
+ # @!attribute [r] web?
276
+ # @return [Boolean] Whether the user is not offline on web.
277
+
278
+ # @!visibility private
279
+ def initialize(data)
280
+ @desktop = data[:desktop]&.to_sym || :offline
281
+ @mobile = data[:mobile]&.to_sym || :offline
282
+ @web = data[:web]&.to_sym || :offline
283
+ end
284
+
285
+ def desktop?
286
+ @desktop != :offline
287
+ end
288
+
289
+ def mobile?
290
+ @mobile != :offline
291
+ end
292
+
293
+ def web?
294
+ @web != :offline
295
+ end
296
+ end
297
+
298
+ private
299
+
300
+ def _set_data(data)
301
+ @user_id = data[:user][:id]
302
+ @guild_id = data[:guild_id]
303
+ @status = data[:status].to_sym
304
+ @activities = data[:activities].map { |a| Activity.new(a) }
305
+ @client_status = ClientStatus.new(data[:client_status])
306
+ end
307
+ end
308
+ end