Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ButtonStyle.premium #9845

Merged
merged 9 commits into from
Jun 1, 2024
13 changes: 13 additions & 0 deletions discord/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ class Button(Component):
The label of the button, if any.
emoji: Optional[:class:`PartialEmoji`]
The emoji of the button, if available.
sku_id: Optional[:class:`int`]
The SKU ID this button sends you to, if available.

.. versionadded:: 2.4
"""

__slots__: Tuple[str, ...] = (
Expand All @@ -179,6 +183,7 @@ class Button(Component):
'disabled',
'label',
'emoji',
'sku_id',
DA-344 marked this conversation as resolved.
Show resolved Hide resolved
)

__repr_info__: ClassVar[Tuple[str, ...]] = __slots__
Expand All @@ -195,6 +200,11 @@ def __init__(self, data: ButtonComponentPayload, /) -> None:
except KeyError:
self.emoji = None

try:
self.sku_id: Optional[int] = int(data['sku_id'])
except KeyError:
self.sku_id = None

@property
def type(self) -> Literal[ComponentType.button]:
""":class:`ComponentType`: The type of component."""
Expand All @@ -207,6 +217,9 @@ def to_dict(self) -> ButtonComponentPayload:
'disabled': self.disabled,
}

if self.sku_id:
payload['sku_id'] = str(self.sku_id)

if self.label:
payload['label'] = self.label

Expand Down
3 changes: 2 additions & 1 deletion discord/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ class InteractionResponseType(Enum):
message_update = 7 # for components
autocomplete_result = 8
modal = 9 # for modals
premium_required = 10
# premium_required = 10 (deprecated)


class VideoQualityMode(Enum):
Expand Down Expand Up @@ -635,6 +635,7 @@ class ButtonStyle(Enum):
success = 3
danger = 4
link = 5
premium = 6

# Aliases
blurple = 1
Expand Down
32 changes: 0 additions & 32 deletions discord/interactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -1050,38 +1050,6 @@ async def send_modal(self, modal: Modal, /) -> None:
self._parent._state.store_view(modal)
self._response_type = InteractionResponseType.modal

async def require_premium(self) -> None:
"""|coro|

Sends a message to the user prompting them that a premium purchase is required for this interaction.

This type of response is only available for applications that have a premium SKU set up.

Raises
-------
HTTPException
Sending the response failed.
InteractionResponded
This interaction has already been responded to before.
"""
if self._response_type:
raise InteractionResponded(self._parent)

parent = self._parent
adapter = async_context.get()
http = parent._state.http

params = interaction_response_params(InteractionResponseType.premium_required.value)
await adapter.create_interaction_response(
parent.id,
parent.token,
session=parent._session,
proxy=http.proxy,
proxy_auth=http.proxy_auth,
params=params,
)
self._response_type = InteractionResponseType.premium_required

async def autocomplete(self, choices: Sequence[Choice[ChoiceT]]) -> None:
"""|coro|

Expand Down
3 changes: 2 additions & 1 deletion discord/types/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from .channel import ChannelType

ComponentType = Literal[1, 2, 3, 4]
ButtonStyle = Literal[1, 2, 3, 4, 5]
ButtonStyle = Literal[1, 2, 3, 4, 5, 6]
TextStyle = Literal[1, 2]
DefaultValueType = Literal['user', 'role', 'channel']

Expand All @@ -49,6 +49,7 @@ class ButtonComponent(TypedDict):
disabled: NotRequired[bool]
emoji: NotRequired[PartialEmoji]
label: NotRequired[str]
sku_id: NotRequired[str]


class SelectOption(TypedDict):
Expand Down
30 changes: 30 additions & 0 deletions discord/ui/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ class Button(Item[V]):
like to control the relative positioning of the row then passing an index is advised.
For example, row=1 will show up before row=2. Defaults to ``None``, which is automatic
ordering. The row number must be between 0 and 4 (i.e. zero indexed).
sku_id: Optional[:class:`int`]
The SKU ID this button sends you to. Can't be combined with ``url``.
DA-344 marked this conversation as resolved.
Show resolved Hide resolved

.. versionadded:: 2.4
"""

__item_repr_attributes__: Tuple[str, ...] = (
Expand All @@ -86,6 +90,7 @@ class Button(Item[V]):
'label',
'emoji',
'row',
'sku_id',
)

def __init__(
Expand All @@ -98,6 +103,7 @@ def __init__(
url: Optional[str] = None,
emoji: Optional[Union[str, Emoji, PartialEmoji]] = None,
row: Optional[int] = None,
sku_id: Optional[int] = None,
):
super().__init__()
if custom_id is not None and url is not None:
Expand All @@ -113,6 +119,9 @@ def __init__(
if url is not None:
style = ButtonStyle.link

if sku_id is not None:
style = ButtonStyle.premium

if emoji is not None:
if isinstance(emoji, str):
emoji = PartialEmoji.from_str(emoji)
Expand All @@ -128,6 +137,7 @@ def __init__(
label=label,
style=style,
emoji=emoji,
sku_id=sku_id,
)
self.row = row

Expand Down Expand Up @@ -202,6 +212,19 @@ def emoji(self, value: Optional[Union[str, Emoji, PartialEmoji]]) -> None:
else:
self._underlying.emoji = None

@property
def sku_id(self) -> Optional[int]:
"""Optional[:class:`int`]: The SKU ID this button sends you to.

.. versionadded:: 2.4
"""
return self._underlying.sku_id

@sku_id.setter
def sku_id(self, value: Optional[int]) -> None:
self.style = ButtonStyle.premium
self._underlying.sku_id = value

@classmethod
def from_component(cls, button: ButtonComponent) -> Self:
return cls(
Expand All @@ -212,6 +235,7 @@ def from_component(cls, button: ButtonComponent) -> Self:
url=button.url,
emoji=button.emoji,
row=None,
sku_id=button.sku_id,
)

@property
Expand Down Expand Up @@ -241,6 +265,7 @@ def button(
style: ButtonStyle = ButtonStyle.secondary,
emoji: Optional[Union[str, Emoji, PartialEmoji]] = None,
row: Optional[int] = None,
sku_id: Optional[int] = None,
) -> Callable[[ItemCallbackType[V, Button[V]]], Button[V]]:
"""A decorator that attaches a button to a component.

Expand Down Expand Up @@ -278,6 +303,10 @@ def button(
like to control the relative positioning of the row then passing an index is advised.
For example, row=1 will show up before row=2. Defaults to ``None``, which is automatic
ordering. The row number must be between 0 and 4 (i.e. zero indexed).
sku_id: Optional[:class:`int`]
The SKU ID this button sends you to. Can't be combined with ``url``.

.. versionadded:: 2.4
"""

def decorator(func: ItemCallbackType[V, Button[V]]) -> ItemCallbackType[V, Button[V]]:
Expand All @@ -293,6 +322,7 @@ def decorator(func: ItemCallbackType[V, Button[V]]) -> ItemCallbackType[V, Butto
'label': label,
'emoji': emoji,
'row': row,
'sku_id': sku_id,
}
return func

Expand Down
5 changes: 5 additions & 0 deletions docs/interactions/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,12 @@ Enumerations
.. attribute:: link

Represents a link button.
.. attribute:: premium

Represents a gradient button denoting that buying a SKU is
required to perform this action.
DA-344 marked this conversation as resolved.
Show resolved Hide resolved

.. versionadded:: 2.4
.. attribute:: blurple

An alias for :attr:`primary`.
Expand Down
Loading