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 support for hang statuses #9914

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
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
110 changes: 108 additions & 2 deletions discord/activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from typing import Any, Dict, List, Optional, TYPE_CHECKING, Union, overload

from .asset import Asset
from .enums import ActivityType, try_enum
from .enums import ActivityType, try_enum, HangStatusType
from .colour import Colour
from .partial_emoji import PartialEmoji
from .utils import _get_as_snowflake
Expand All @@ -40,6 +40,7 @@
'Game',
'Spotify',
'CustomActivity',
'HangStatus',
)

"""If curious, this is the current schema for an activity.
Expand Down Expand Up @@ -109,6 +110,7 @@ class BaseActivity:
- :class:`Game`
- :class:`Streaming`
- :class:`CustomActivity`
- :class:`HangStatus`

Note that although these types are considered user-settable by the library,
Discord typically ignores certain combinations of activity depending on
Expand Down Expand Up @@ -147,6 +149,7 @@ class Activity(BaseActivity):

- :class:`Game`
- :class:`Streaming`
- :class:`HangStatus`

Attributes
------------
Expand Down Expand Up @@ -825,7 +828,107 @@ def __repr__(self) -> str:
return f'<CustomActivity name={self.name!r} emoji={self.emoji!r}>'


ActivityTypes = Union[Activity, Game, CustomActivity, Streaming, Spotify]
class HangStatus(BaseActivity):
"""A slimmed down version of :class:`Activity` that represents a Discord hang status.

This is typically displayed via **Right now, I'm -** on the official Discord client.

.. container:: operations

.. describe:: x == y

Checks if two hang statuses are equal.

.. describe:: x != y

Checks if two hang statuses are not equal.

.. describe:: hash(x)

Returns the hang status' hash.

.. describe:: str(x)

Returns the hang status' name.

.. versionadded: 2.5

Attributes
-----------
state: :class:`HangStatusType`
The state of hang status.
name: :class:`str`
The name of the hang status.
emoji: Optional[:class:`PartialEmoji`]
The emoji of the hang status if any.
"""

__slots__ = ('state', 'name', 'emoji')

def __init__(self, state: HangStatusType, **extra: Any) -> None:
super().__init__(**extra)
self.state: HangStatusType = state

self.name: str
if self.state == HangStatusType.custom:
details = extra.get('details')
if details is None:
raise ValueError('hang status state cannot be custom')
self.name = details
else:
self.name = self.state.value

self.emoji: Optional[PartialEmoji]
emoji = extra.get('emoji')
if emoji is None:
self.emoji = emoji
elif isinstance(emoji, dict):
self.emoji = PartialEmoji.from_dict(emoji)
elif isinstance(emoji, str):
self.emoji = PartialEmoji(name=emoji)
elif isinstance(emoji, PartialEmoji):
self.emoji = emoji
else:
raise TypeError(f'Expected str, PartialEmoji, or None, received {type(emoji)!r} instead.')

@property
def type(self) -> ActivityType:
""":class:`ActivityType`: Returns the activity's type. This is for compatibility with :class:`Activity`.

It always returns :attr:`ActivityType.hang`.
"""
return ActivityType.hang

def to_dict(self) -> Dict[str, Any]:
codeofandrin marked this conversation as resolved.
Show resolved Hide resolved
ret = {
'type': ActivityType.hang.value,
'name': 'Hang Status',
'state': self.state.value,
}
if self.state == HangStatusType.custom:
ret['details'] = self.name
if self.emoji:
ret['emoji'] = self.emoji.to_dict()

return ret

def __str__(self) -> str:
return str(self.name)

def __repr__(self) -> str:
return f'<HangStatus state={self.state!r} name={self.name!r}>'

def __eq__(self, other: object) -> bool:
return isinstance(other, HangStatus) and other.name == self.name and other.emoji == self.emoji

def __ne__(self, other: object) -> bool:
return not self.__eq__(other)

def __hash__(self) -> int:
return hash((self.name, str(self.emoji)))


ActivityTypes = Union[Activity, Game, CustomActivity, Streaming, Spotify, HangStatus]


@overload
Expand Down Expand Up @@ -862,6 +965,9 @@ def create_activity(data: Optional[ActivityPayload], state: ConnectionState) ->
return Activity(**data)
elif game_type is ActivityType.listening and 'sync_id' in data and 'session_id' in data:
return Spotify(**data)
elif game_type is ActivityType.hang:
hang_state = try_enum(HangStatusType, data.pop('state'))
return HangStatus(state=hang_state, **data) # type: ignore
else:
ret = Activity(**data)

Expand Down
13 changes: 13 additions & 0 deletions discord/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
'EntitlementType',
'EntitlementOwnerType',
'PollLayoutType',
'HangStatusType',
)


Expand Down Expand Up @@ -525,11 +526,23 @@ class ActivityType(Enum):
watching = 3
custom = 4
competing = 5
hang = 6

def __int__(self) -> int:
return self.value


class HangStatusType(Enum):
chilling = 'chilling'
gaming = 'gaming'
focusing = 'focusing'
brb = 'brb'
eating = 'eating'
in_transit = 'in-transit'
watching = 'watching'
custom = 'custom'


class TeamMembershipState(Enum):
invited = 1
accepted = 2
Expand Down
2 changes: 1 addition & 1 deletion discord/types/activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class ActivityEmoji(TypedDict):
animated: NotRequired[bool]


ActivityType = Literal[0, 1, 2, 4, 5]
ActivityType = Literal[0, 1, 2, 4, 5, 6]


class SendableActivity(TypedDict):
Expand Down
53 changes: 53 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1911,6 +1911,12 @@ of :class:`enum.Enum`.

.. versionadded:: 1.5

.. attribute:: hang

A hang status activity type.

.. versionadded:: 2.5

.. class:: VerificationLevel

Specifies a :class:`Guild`\'s verification level, which is the criteria in
Expand Down Expand Up @@ -3663,6 +3669,45 @@ of :class:`enum.Enum`.
A burst reaction, also known as a "super reaction".


.. class:: HangStatusType

Represents the type of an hang status.

.. versionadded:: 2.5

.. attribute:: chilling

The default hang status "Chilling".

.. attribute:: gaming

The default hang status "GAMING".

.. attribute:: focusing

The default hang status "In the zone".

.. attribute:: brb

The default hang status "Gonna BRB".

.. attribute:: eating

The default hang status "Grubbin".

.. attribute:: in_transit

The default hang status "Wandering IRL".

.. attribute:: watching

The default hang status "Watchin' stuff".

.. attribute:: custom

A custom hang status set by the user.


.. _discord-api-audit-logs:

Audit Log Data
Expand Down Expand Up @@ -5310,6 +5355,14 @@ CustomActivity
.. autoclass:: CustomActivity
:members:

HangStatus
~~~~~~~~~~~

.. attributetable:: HangStatus

.. autoclass:: HangStatus
:members:

Permissions
~~~~~~~~~~~~

Expand Down
Loading