Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/discordrb/api/channel.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ def message(token, channel_id, message_id)
# https://discord.com/developers/docs/resources/channel#create-message
# @param attachments [Array<File>, nil] Attachments to use with `attachment://` in embeds. See
# https://discord.com/developers/docs/resources/channel#create-message-using-attachments-within-embeds
def create_message(token, channel_id, message, tts = false, embeds = nil, nonce = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, flags = nil, enforce_nonce = false, poll = nil)
body = { content: message, tts: tts, embeds: embeds, nonce: nonce, allowed_mentions: allowed_mentions, message_reference: message_reference, components: components&.to_a, flags: flags, enforce_nonce: enforce_nonce, poll: poll }
def create_message(token, channel_id, message, tts = false, embeds = nil, nonce = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, flags = nil, enforce_nonce = false, poll = nil, shared_client_theme = nil)
body = { content: message, tts: tts, embeds: embeds, nonce: nonce, allowed_mentions: allowed_mentions, message_reference: message_reference, components: components&.to_a, flags: flags, enforce_nonce: enforce_nonce, poll: poll, shared_client_theme: shared_client_theme }
body = if attachments
files = [*0...attachments.size].zip(attachments).to_h
{ **files, payload_json: body.to_json }
Expand Down
11 changes: 7 additions & 4 deletions lib/discordrb/bot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -422,15 +422,16 @@ def delete_invite(code)
# @param nonce [String, nil] A optional nonce in order to verify that a message was sent. Maximum of twenty-five characters.
# @param enforce_nonce [true, false] Whether the nonce should be enforced and used for message de-duplication.
# @param poll [Hash, Poll::Builder, Poll, nil] The poll that should be attached to this message.
# @param shared_theme [hash, SharedTheme::Builder, SharedTheme, nil] The client-side theme to share via this message.
# @return [Message] The message that was sent.
def send_message(channel, content, tts = false, embeds = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, flags = 0, nonce = nil, enforce_nonce = false, poll = nil)
def send_message(channel, content, tts = false, embeds = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, flags = 0, nonce = nil, enforce_nonce = false, poll = nil, shared_theme = nil)
channel = channel.resolve_id
debug("Sending message to #{channel} with content '#{content}'")
allowed_mentions = { parse: [] } if allowed_mentions == false
message_reference = { message_id: message_reference.resolve_id } if message_reference.respond_to?(:resolve_id)
embeds = (embeds.instance_of?(Array) ? embeds.map(&:to_hash) : [embeds&.to_hash]).compact

response = API::Channel.create_message(token, channel, content, tts, embeds, nonce, attachments, allowed_mentions&.to_hash, message_reference, components, flags, enforce_nonce, poll&.to_h)
response = API::Channel.create_message(token, channel, content, tts, embeds, nonce, attachments, allowed_mentions&.to_hash, message_reference, components, flags, enforce_nonce, poll&.to_h, shared_theme&.to_h)
Message.new(JSON.parse(response), self)
end

Expand All @@ -449,11 +450,13 @@ def send_message(channel, content, tts = false, embeds = nil, attachments = nil,
# @param nonce [String, nil] A optional nonce in order to verify that a message was sent. Maximum of twenty-five characters.
# @param enforce_nonce [true, false] Whether the nonce should be enforced and used for message de-duplication.
# @param poll [Hash, Poll::Builder, Poll, nil] The poll that should be attached to this message.
def send_temporary_message(channel, content, timeout, tts = false, embeds = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, flags = 0, nonce = nil, enforce_nonce = false, poll = nil)
# @param shared_theme [hash, SharedTheme::Builder, SharedTheme, nil] The client-side theme to share via this message.
# @return [nil]
def send_temporary_message(channel, content, timeout, tts = false, embeds = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, flags = 0, nonce = nil, enforce_nonce = false, poll = nil, shared_theme = nil)
Thread.new do
Thread.current[:discordrb_name] = "#{@current_thread}-temp-msg"

message = send_message(channel, content, tts, embeds, attachments, allowed_mentions, message_reference, components, flags, nonce, enforce_nonce, poll)
message = send_message(channel, content, tts, embeds, attachments, allowed_mentions, message_reference, components, flags, nonce, enforce_nonce, poll, shared_theme)
sleep(timeout)
message.delete
end
Expand Down
13 changes: 12 additions & 1 deletion lib/discordrb/colour_rgb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class ColourRGB
# @example Initialize a with a hexadecimal string
# ColourRGB.new('7289da') #=> ColourRGB
def initialize(combined)
@combined = combined.is_a?(String) ? combined.to_i(16) : combined
@combined = combined.is_a?(String) ? combined.delete('#').to_i(16) : combined
@red = (@combined >> 16) & 0xFF
@green = (@combined >> 8) & 0xFF
@blue = @combined & 0xFF
Expand All @@ -35,7 +35,18 @@ def initialize(combined)
def hex
@combined.to_s(16)
end

alias_method :to_s, :hex
alias_method :hexadecimal, :hex

# Check if two colour RGB objects are equivalent.
# @param other [Object] The object to compare against for equality.
# @return [true, false] Whether or not the two objects are equivalent.
def ==(other)
other.is_a?(ColourRGB) ? @combined == other.combined : false
end

alias_method :eql?, :==
end

# Alias for the class {ColourRGB}
Expand Down
1 change: 1 addition & 0 deletions lib/discordrb/data.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,4 @@
require 'discordrb/data/timestamp'
require 'discordrb/data/scheduled_event'
require 'discordrb/data/poll'
require 'discordrb/data/shared_theme'
8 changes: 5 additions & 3 deletions lib/discordrb/data/channel.rb
Original file line number Diff line number Diff line change
Expand Up @@ -611,16 +611,18 @@ def send_embed(message = '', embed = nil, attachments = nil, tts = false, allowe
# @param nonce [nil, String, Integer, false] The 25 character nonce that should be used when sending this message.
# @param enforce_nonce [true, false] Whether the provided nonce should be enforced and used for message de-duplication.
# @param poll [Hash, Poll::Builder, Poll, nil] The poll that should be attached to the message.
# @param shared_theme [hash, SharedTheme::Builder, SharedTheme, nil] The client-side theme to share via the message.
# @yieldparam builder [Webhooks::Builder] An optional message builder. Arguments passed to the builder overwrite method data.
# @yieldparam view [Webhooks::View] An optional component builder. Arguments passed to the builder overwrite method data.
# @return [Message, nil] The resulting message that was created, or `nil` if the `timeout` parameter was set to a non `nil` value.
def send_message!(content: '', timeout: nil, tts: false, embeds: [], attachments: nil, allowed_mentions: nil, reference: nil, components: nil, flags: 0, has_components: false, nonce: nil, enforce_nonce: false, poll: nil)
def send_message!(content: '', timeout: nil, tts: false, embeds: [], attachments: nil, allowed_mentions: nil, reference: nil, components: nil, flags: 0, has_components: false, nonce: nil, enforce_nonce: false, poll: nil, shared_theme: nil)
builder = Discordrb::Webhooks::Builder.new
view = Discordrb::Webhooks::View.new

builder.tts = tts
builder.poll = poll
builder.content = content
builder.shared_theme = shared_theme
embeds&.each { |embed| builder << embed }
builder.allowed_mentions = allowed_mentions

Expand All @@ -631,9 +633,9 @@ def send_message!(content: '', timeout: nil, tts: false, embeds: [], attachments
builder = builder.to_json_hash

if timeout
@bot.send_temporary_message(@id, builder[:content], timeout, builder[:tts], builder[:embeds], attachments, builder[:allowed_mentions], reference, components&.to_a || view.to_a, flags, nonce, enforce_nonce, builder[:poll])
@bot.send_temporary_message(@id, builder[:content], timeout, builder[:tts], builder[:embeds], attachments, builder[:allowed_mentions], reference, components&.to_a || view.to_a, flags, nonce, enforce_nonce, builder[:poll], builder[:shared_client_theme])
else
@bot.send_message(@id, builder[:content], builder[:tts], builder[:embeds], attachments, builder[:allowed_mentions], reference, components&.to_a || view.to_a, flags, nonce, enforce_nonce, builder[:poll])
@bot.send_message(@id, builder[:content], builder[:tts], builder[:embeds], attachments, builder[:allowed_mentions], reference, components&.to_a || view.to_a, flags, nonce, enforce_nonce, builder[:poll], builder[:shared_client_theme])
end
end

Expand Down
6 changes: 5 additions & 1 deletion lib/discordrb/data/message.rb
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ class Message
# @return [Integer] a generally increasing integer that can be used to determine this message's position in a thread.
attr_reader :position

# @return [SharedTheme, nil] the client-side theme that was shared via this message, or `nil`.
attr_reader :shared_theme

# @return [Poll, nil] the poll that was sent with this message, or `nil`.
attr_reader :poll

Expand Down Expand Up @@ -215,6 +218,7 @@ def initialize(data, bot)
@pinned_at = Time.parse(data['pinned_at']) if data['pinned_at']
@call = Call.new(data['call'], @bot) if data['call']
@poll = Poll.new(data['poll'], self, @bot) if data['poll']
@shared_theme = SharedTheme.new(data['shared_client_theme'], @bot) if data['shared_client_theme']

@snapshots = data['message_snapshots']&.map { |snapshot| Snapshot.new(snapshot['message'], @bot) } || []
@role_subscription = RoleSubscriptionData.new(data['role_subscription_data'], self, @bot) if data['role_subscription_data']
Expand Down Expand Up @@ -375,7 +379,7 @@ def webhook?

# @return [Array<Emoji>] the emotes that were used/mentioned in this message.
def emoji
return [] if @content.empty? || @content.nil?
return [] if @content.nil? || @content.empty?

@emoji ||= @bot.parse_mentions(@content).select { |mention| mention.is_a?(Discordrb::Emoji) }
end
Expand Down
115 changes: 115 additions & 0 deletions lib/discordrb/data/shared_theme.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# frozen_string_literal: true

module Discordrb
# A theme for the official Discord client.
class SharedTheme
# Mapping of names to base theme values.
BASES = {
unset: 0,
dark: 1,
light: 2,
darker: 3,
midnight: 4
}.freeze

# @return [Integer] the background tone of the theme.
attr_reader :base

# @return [Integer] the angle of the theme's colours.
attr_reader :angle

# @return [Array<ColourRGB>] the colours of the theme.
attr_reader :colours
alias colors colours

# @return [Integer] the intensity of the theme's colours.
attr_reader :intensity

# @!visibility private
def initialize(data, bot)
@bot = bot
@base = data['base_theme']
@intensity = data['base_mix']
@angle = data['gradient_angle']
@colours = data['colors']&.map { |value| ColourRGB.new(value) }
end

# Check if two shared theme objects are equivalent.
# @param other [Object] The object to compare against for equality.
# @return [true, false] Whether or not the two objects are equivalent.
def ==(other)
return false unless other.is_a?(SharedTheme)

@angle == other.angle && @base == other.base &&
@intensity == other.intensity && @colours == other.colours
end

alias_method :eql?, :==

# @!method unset_base?
# @return [true, false] whether or not the background tone of the theme is not defined.
# @!method dark_base?
# @return [true, false] whether or not the background tone of the theme is a dark color.
# @!method light_base?
# @return [true, false] whether or not the background tone of the theme is a light color.
# @!method darker_base?
# @return [true, false] whether or not the background tone of the theme is a darker color.
# @!method midnight_base?
# @return [true, false] whether or not the background tone of the theme is a midnight color.
BASES.each do |name, value|
define_method("#{name}_base?") { @base == value }
end

# @!visibility private
def to_h
{
base_theme: @base,
base_mix: @intensity,
gradient_angle: @angle,
colors: @colours.map { |value| format('%06x', value.to_i) }
}
end

# @!visibility private
def inspect
"<SharedTheme base=#{@base} angle=#{@angle} intensity=#{@intensity}>"
end

# Builder for shared themes.
class Builder
# Create a shared theme object.
# @param angle [Integer] The angle of the theme's colours; between 0-360.
# @param intensity [Integer] The intensity of the theme's colours; between 0-100.
# @param base [Integer, Symbol, nil] The background tone of the theme; see {BASES}.
def initialize(angle:, intensity:, base: :unset)
@base = base
@colours = []
@angle = angle
@intensity = intensity
end

# Add a colour to the shared theme.
# @param value [Integer, String, ColourRGB] The colour to add to the theme's colours.
# @return [void]
def colour(value)
raise 'Maximum number of shared theme colours reached (5)' if @colours.length == 5

@colours << format('%06x', value.is_a?(String) ? value&.delete('#')&.to_i(16) : value&.to_i)
end

alias_method :color, :colour
alias_method :add_color, :colour
alias_method :add_colour, :colour

# @!visibility private
def to_h
{
colors: @colours,
base_mix: @intensity.to_i,
gradient_angle: @angle.to_i,
base_theme: BASES[@base] || @base
}
end
end
end
end
32 changes: 28 additions & 4 deletions lib/discordrb/webhooks/builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
module Discordrb::Webhooks
# A class that acts as a builder for a webhook message object.
class Builder
def initialize(content: '', username: nil, avatar_url: nil, tts: false, file: nil, embeds: [], allowed_mentions: nil, poll: nil)
def initialize(content: '', username: nil, avatar_url: nil, tts: false, file: nil, embeds: [], allowed_mentions: nil, poll: nil, shared_theme: nil)
@content = content
@username = username
@avatar_url = avatar_url
Expand All @@ -14,6 +14,7 @@ def initialize(content: '', username: nil, avatar_url: nil, tts: false, file: ni
@embeds = embeds
@allowed_mentions = allowed_mentions
@poll = poll
@shared_theme = shared_theme
end

# The content of the message. May be 2000 characters long at most.
Expand Down Expand Up @@ -75,15 +76,33 @@ def add_embed(embed = nil)
# end
# @param poll [Poll::Builder, Poll, Hash, nil] The poll to start the building process with, or nil if one should be created anew.
# @return [Poll::Builder, Poll] The created poll.
def add_poll(poll = nil, **kwargs)
poll ||= Discordrb::Poll::Builder.new(**kwargs)
def add_poll(poll = nil, ...)
poll ||= Discordrb::Poll::Builder.new(...)
yield(poll) if block_given?
@poll = poll
poll
end

alias_method :poll, :add_poll

# Convenience method to add a shared theme using a builder pattern
# @example Add a shared theme to a message
# builder.shared_theme(angle: 257, intensity: 20) do |theme|
# theme.colour('C27F74')
# theme.colour('0F0508')
# theme.colour('BF7E72')
# end
# @param theme [SharedTheme::Builder, SharedTheme, Hash, nil] The theme to start the building process with, or nil if one should be created anew.
# @return [SharedTheme::Builder, SharedTheme] The created theme.
def add_shared_theme(theme = nil, ...)
theme ||= Discordrb::SharedTheme::Builder.new(...)
yield(theme) if block_given?
@shared_theme = theme
theme
end

alias_method :shared_theme, :add_shared_theme

# @return [File, nil] the file attached to this message.
attr_reader :file

Expand All @@ -98,6 +117,10 @@ def add_poll(poll = nil, **kwargs)
# @see https://discord.com/developers/docs/resources/poll#poll-create-request-object
attr_writer :poll

# @return [hash, SharedTheme::Builder, SharedTheme, nil] The client-side theme to share via this message.
# @see https://docs.discord.com/developers/resources/message#shared-client-theme-object
attr_writer :shared_theme

# @return [Hash] a hash representation of the created message, for JSON format.
def to_json_hash
{
Expand All @@ -107,7 +130,8 @@ def to_json_hash
tts: @tts,
embeds: @embeds.map(&:to_hash),
allowed_mentions: @allowed_mentions&.to_hash,
poll: @poll&.to_h
poll: @poll&.to_h,
shared_client_theme: @shared_theme&.to_h
}
end

Expand Down
Loading