#!/usr/bin/env python # # A library that provides a Python interface to the Telegram Bot API # Copyright (C) 2015-2024 # Leandro Toledo de Souza # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser Public License for more details. # # You should have received a copy of the GNU Lesser Public License # along with this program. If not, see [http://www.gnu.org/licenses/]. """This module contains objects related to chat backgrounds.""" from collections.abc import Sequence from typing import TYPE_CHECKING, Final, Optional from telegram import constants from telegram._files.document import Document from telegram._telegramobject import TelegramObject from telegram._utils import enum from telegram._utils.argumentparsing import parse_sequence_arg from telegram._utils.types import JSONDict if TYPE_CHECKING: from telegram import Bot class BackgroundFill(TelegramObject): """Base class for Telegram BackgroundFill Objects. It can be one of: * :class:`telegram.BackgroundFillSolid` * :class:`telegram.BackgroundFillGradient` * :class:`telegram.BackgroundFillFreeformGradient` Objects of this class are comparable in terms of equality. Two objects of this class are considered equal, if their :attr:`type` is equal. .. versionadded:: 21.2 Args: type (:obj:`str`): Type of the background fill. Can be one of: :attr:`~telegram.BackgroundFill.SOLID`, :attr:`~telegram.BackgroundFill.GRADIENT` or :attr:`~telegram.BackgroundFill.FREEFORM_GRADIENT`. Attributes: type (:obj:`str`): Type of the background fill. Can be one of: :attr:`~telegram.BackgroundFill.SOLID`, :attr:`~telegram.BackgroundFill.GRADIENT` or :attr:`~telegram.BackgroundFill.FREEFORM_GRADIENT`. """ __slots__ = ("type",) SOLID: Final[constants.BackgroundFillType] = constants.BackgroundFillType.SOLID """:const:`telegram.constants.BackgroundFillType.SOLID`""" GRADIENT: Final[constants.BackgroundFillType] = constants.BackgroundFillType.GRADIENT """:const:`telegram.constants.BackgroundFillType.GRADIENT`""" FREEFORM_GRADIENT: Final[constants.BackgroundFillType] = ( constants.BackgroundFillType.FREEFORM_GRADIENT ) """:const:`telegram.constants.BackgroundFillType.FREEFORM_GRADIENT`""" def __init__( self, type: str, # pylint: disable=redefined-builtin *, api_kwargs: Optional[JSONDict] = None, ): super().__init__(api_kwargs=api_kwargs) # Required by all subclasses self.type: str = enum.get_member(constants.BackgroundFillType, type, type) self._id_attrs = (self.type,) self._freeze() @classmethod def de_json( cls, data: Optional[JSONDict], bot: Optional["Bot"] = None ) -> Optional["BackgroundFill"]: """See :meth:`telegram.TelegramObject.de_json`.""" data = cls._parse_data(data) if not data: return None _class_mapping: dict[str, type[BackgroundFill]] = { cls.SOLID: BackgroundFillSolid, cls.GRADIENT: BackgroundFillGradient, cls.FREEFORM_GRADIENT: BackgroundFillFreeformGradient, } if cls is BackgroundFill and data.get("type") in _class_mapping: return _class_mapping[data.pop("type")].de_json(data=data, bot=bot) return super().de_json(data=data, bot=bot) class BackgroundFillSolid(BackgroundFill): """ The background is filled using the selected color. Objects of this class are comparable in terms of equality. Two objects of this class are considered equal, if their :attr:`color` is equal. .. versionadded:: 21.2 Args: color (:obj:`int`): The color of the background fill in the `RGB24` format. Attributes: type (:obj:`str`): Type of the background fill. Always :attr:`~telegram.BackgroundFill.SOLID`. color (:obj:`int`): The color of the background fill in the `RGB24` format. """ __slots__ = ("color",) def __init__( self, color: int, *, api_kwargs: Optional[JSONDict] = None, ): super().__init__(type=self.SOLID, api_kwargs=api_kwargs) with self._unfrozen(): self.color: int = color self._id_attrs = (self.color,) class BackgroundFillGradient(BackgroundFill): """ The background is a gradient fill. Objects of this class are comparable in terms of equality. Two objects of this class are considered equal, if their :attr:`top_color`, :attr:`bottom_color` and :attr:`rotation_angle` are equal. .. versionadded:: 21.2 Args: top_color (:obj:`int`): Top color of the gradient in the `RGB24` format. bottom_color (:obj:`int`): Bottom color of the gradient in the `RGB24` format. rotation_angle (:obj:`int`): Clockwise rotation angle of the background fill in degrees; 0-:tg-const:`telegram.constants.BackgroundFillLimit.MAX_ROTATION_ANGLE`. Attributes: type (:obj:`str`): Type of the background fill. Always :attr:`~telegram.BackgroundFill.GRADIENT`. top_color (:obj:`int`): Top color of the gradient in the `RGB24` format. bottom_color (:obj:`int`): Bottom color of the gradient in the `RGB24` format. rotation_angle (:obj:`int`): Clockwise rotation angle of the background fill in degrees; 0-:tg-const:`telegram.constants.BackgroundFillLimit.MAX_ROTATION_ANGLE`. """ __slots__ = ("bottom_color", "rotation_angle", "top_color") def __init__( self, top_color: int, bottom_color: int, rotation_angle: int, *, api_kwargs: Optional[JSONDict] = None, ): super().__init__(type=self.GRADIENT, api_kwargs=api_kwargs) with self._unfrozen(): self.top_color: int = top_color self.bottom_color: int = bottom_color self.rotation_angle: int = rotation_angle self._id_attrs = (self.top_color, self.bottom_color, self.rotation_angle) class BackgroundFillFreeformGradient(BackgroundFill): """ The background is a freeform gradient that rotates after every message in the chat. Objects of this class are comparable in terms of equality. Two objects of this class are considered equal, if their :attr:`colors` is equal. .. versionadded:: 21.2 Args: colors (Sequence[:obj:`int`]): A list of the 3 or 4 base colors that are used to generate the freeform gradient in the `RGB24` format Attributes: type (:obj:`str`): Type of the background fill. Always :attr:`~telegram.BackgroundFill.FREEFORM_GRADIENT`. colors (Sequence[:obj:`int`]): A list of the 3 or 4 base colors that are used to generate the freeform gradient in the `RGB24` format """ __slots__ = ("colors",) def __init__( self, colors: Sequence[int], *, api_kwargs: Optional[JSONDict] = None, ): super().__init__(type=self.FREEFORM_GRADIENT, api_kwargs=api_kwargs) with self._unfrozen(): self.colors: tuple[int, ...] = parse_sequence_arg(colors) self._id_attrs = (self.colors,) class BackgroundType(TelegramObject): """Base class for Telegram BackgroundType Objects. It can be one of: * :class:`telegram.BackgroundTypeFill` * :class:`telegram.BackgroundTypeWallpaper` * :class:`telegram.BackgroundTypePattern` * :class:`telegram.BackgroundTypeChatTheme`. Objects of this class are comparable in terms of equality. Two objects of this class are considered equal, if their :attr:`type` is equal. .. versionadded:: 21.2 Args: type (:obj:`str`): Type of the background. Can be one of: :attr:`~telegram.BackgroundType.FILL`, :attr:`~telegram.BackgroundType.WALLPAPER` :attr:`~telegram.BackgroundType.PATTERN` or :attr:`~telegram.BackgroundType.CHAT_THEME`. Attributes: type (:obj:`str`): Type of the background. Can be one of: :attr:`~telegram.BackgroundType.FILL`, :attr:`~telegram.BackgroundType.WALLPAPER` :attr:`~telegram.BackgroundType.PATTERN` or :attr:`~telegram.BackgroundType.CHAT_THEME`. """ __slots__ = ("type",) FILL: Final[constants.BackgroundTypeType] = constants.BackgroundTypeType.FILL """:const:`telegram.constants.BackgroundTypeType.FILL`""" WALLPAPER: Final[constants.BackgroundTypeType] = constants.BackgroundTypeType.WALLPAPER """:const:`telegram.constants.BackgroundTypeType.WALLPAPER`""" PATTERN: Final[constants.BackgroundTypeType] = constants.BackgroundTypeType.PATTERN """:const:`telegram.constants.BackgroundTypeType.PATTERN`""" CHAT_THEME: Final[constants.BackgroundTypeType] = constants.BackgroundTypeType.CHAT_THEME """:const:`telegram.constants.BackgroundTypeType.CHAT_THEME`""" def __init__( self, type: str, # pylint: disable=redefined-builtin *, api_kwargs: Optional[JSONDict] = None, ): super().__init__(api_kwargs=api_kwargs) # Required by all subclasses self.type: str = enum.get_member(constants.BackgroundTypeType, type, type) self._id_attrs = (self.type,) self._freeze() @classmethod def de_json( cls, data: Optional[JSONDict], bot: Optional["Bot"] = None ) -> Optional["BackgroundType"]: """See :meth:`telegram.TelegramObject.de_json`.""" data = cls._parse_data(data) if not data: return None _class_mapping: dict[str, type[BackgroundType]] = { cls.FILL: BackgroundTypeFill, cls.WALLPAPER: BackgroundTypeWallpaper, cls.PATTERN: BackgroundTypePattern, cls.CHAT_THEME: BackgroundTypeChatTheme, } if cls is BackgroundType and data.get("type") in _class_mapping: return _class_mapping[data.pop("type")].de_json(data=data, bot=bot) if "fill" in data: data["fill"] = BackgroundFill.de_json(data.get("fill"), bot) if "document" in data: data["document"] = Document.de_json(data.get("document"), bot) return super().de_json(data=data, bot=bot) class BackgroundTypeFill(BackgroundType): """ The background is automatically filled based on the selected colors. Objects of this class are comparable in terms of equality. Two objects of this class are considered equal, if their :attr:`fill` and :attr:`dark_theme_dimming` are equal. .. versionadded:: 21.2 Args: fill (:class:`telegram.BackgroundFill`): The background fill. dark_theme_dimming (:obj:`int`): Dimming of the background in dark themes, as a percentage; 0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_DIMMING`. Attributes: type (:obj:`str`): Type of the background. Always :attr:`~telegram.BackgroundType.FILL`. fill (:class:`telegram.BackgroundFill`): The background fill. dark_theme_dimming (:obj:`int`): Dimming of the background in dark themes, as a percentage; 0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_DIMMING`. """ __slots__ = ("dark_theme_dimming", "fill") def __init__( self, fill: BackgroundFill, dark_theme_dimming: int, *, api_kwargs: Optional[JSONDict] = None, ): super().__init__(type=self.FILL, api_kwargs=api_kwargs) with self._unfrozen(): self.fill: BackgroundFill = fill self.dark_theme_dimming: int = dark_theme_dimming self._id_attrs = (self.fill, self.dark_theme_dimming) class BackgroundTypeWallpaper(BackgroundType): """ The background is a wallpaper in the `JPEG` format. Objects of this class are comparable in terms of equality. Two objects of this class are considered equal, if their :attr:`document` and :attr:`dark_theme_dimming` are equal. .. versionadded:: 21.2 Args: document (:class:`telegram.Document`): Document with the wallpaper dark_theme_dimming (:obj:`int`): Dimming of the background in dark themes, as a percentage; 0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_DIMMING`. is_blurred (:obj:`bool`, optional): :obj:`True`, if the wallpaper is downscaled to fit in a 450x450 square and then box-blurred with radius 12 is_moving (:obj:`bool`, optional): :obj:`True`, if the background moves slightly when the device is tilted Attributes: type (:obj:`str`): Type of the background. Always :attr:`~telegram.BackgroundType.WALLPAPER`. document (:class:`telegram.Document`): Document with the wallpaper dark_theme_dimming (:obj:`int`): Dimming of the background in dark themes, as a percentage; 0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_DIMMING`. is_blurred (:obj:`bool`): Optional. :obj:`True`, if the wallpaper is downscaled to fit in a 450x450 square and then box-blurred with radius 12 is_moving (:obj:`bool`): Optional. :obj:`True`, if the background moves slightly when the device is tilted """ __slots__ = ("dark_theme_dimming", "document", "is_blurred", "is_moving") def __init__( self, document: Document, dark_theme_dimming: int, is_blurred: Optional[bool] = None, is_moving: Optional[bool] = None, *, api_kwargs: Optional[JSONDict] = None, ): super().__init__(type=self.WALLPAPER, api_kwargs=api_kwargs) with self._unfrozen(): # Required self.document: Document = document self.dark_theme_dimming: int = dark_theme_dimming # Optionals self.is_blurred: Optional[bool] = is_blurred self.is_moving: Optional[bool] = is_moving self._id_attrs = (self.document, self.dark_theme_dimming) class BackgroundTypePattern(BackgroundType): """ The background is a `PNG` or `TGV` (gzipped subset of `SVG` with `MIME` type `"application/x-tgwallpattern"`) pattern to be combined with the background fill chosen by the user. Objects of this class are comparable in terms of equality. Two objects of this class are considered equal, if their :attr:`document` and :attr:`fill` and :attr:`intensity` are equal. .. versionadded:: 21.2 Args: document (:class:`telegram.Document`): Document with the pattern. fill (:class:`telegram.BackgroundFill`): The background fill that is combined with the pattern. intensity (:obj:`int`): Intensity of the pattern when it is shown above the filled background; 0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_INTENSITY`. is_inverted (:obj:`int`, optional): :obj:`True`, if the background fill must be applied only to the pattern itself. All other pixels are black in this case. For dark themes only. is_moving (:obj:`bool`, optional): :obj:`True`, if the background moves slightly when the device is tilted. Attributes: type (:obj:`str`): Type of the background. Always :attr:`~telegram.BackgroundType.PATTERN`. document (:class:`telegram.Document`): Document with the pattern. fill (:class:`telegram.BackgroundFill`): The background fill that is combined with the pattern. intensity (:obj:`int`): Intensity of the pattern when it is shown above the filled background; 0-:tg-const:`telegram.constants.BackgroundTypeLimit.MAX_INTENSITY`. is_inverted (:obj:`int`): Optional. :obj:`True`, if the background fill must be applied only to the pattern itself. All other pixels are black in this case. For dark themes only. is_moving (:obj:`bool`): Optional. :obj:`True`, if the background moves slightly when the device is tilted. """ __slots__ = ( "document", "fill", "intensity", "is_inverted", "is_moving", ) def __init__( self, document: Document, fill: BackgroundFill, intensity: int, is_inverted: Optional[bool] = None, is_moving: Optional[bool] = None, *, api_kwargs: Optional[JSONDict] = None, ): super().__init__(type=self.PATTERN, api_kwargs=api_kwargs) with self._unfrozen(): # Required self.document: Document = document self.fill: BackgroundFill = fill self.intensity: int = intensity # Optionals self.is_inverted: Optional[bool] = is_inverted self.is_moving: Optional[bool] = is_moving self._id_attrs = (self.document, self.fill, self.intensity) class BackgroundTypeChatTheme(BackgroundType): """ The background is taken directly from a built-in chat theme. Objects of this class are comparable in terms of equality. Two objects of this class are considered equal, if their :attr:`theme_name` is equal. .. versionadded:: 21.2 Args: theme_name (:obj:`str`): Name of the chat theme, which is usually an emoji. Attributes: type (:obj:`str`): Type of the background. Always :attr:`~telegram.BackgroundType.CHAT_THEME`. theme_name (:obj:`str`): Name of the chat theme, which is usually an emoji. """ __slots__ = ("theme_name",) def __init__( self, theme_name: str, *, api_kwargs: Optional[JSONDict] = None, ): super().__init__(type=self.CHAT_THEME, api_kwargs=api_kwargs) with self._unfrozen(): self.theme_name: str = theme_name self._id_attrs = (self.theme_name,) class ChatBackground(TelegramObject): """ This object represents a chat background. Objects of this class are comparable in terms of equality. Two objects of this class are considered equal, if their :attr:`type` is equal. .. versionadded:: 21.2 Args: type (:class:`telegram.BackgroundType`): Type of the background. Attributes: type (:class:`telegram.BackgroundType`): Type of the background. """ __slots__ = ("type",) def __init__( self, type: BackgroundType, # pylint: disable=redefined-builtin *, api_kwargs: Optional[JSONDict] = None, ): super().__init__(api_kwargs=api_kwargs) self.type: BackgroundType = type self._id_attrs = (self.type,) self._freeze() @classmethod def de_json( cls, data: Optional[JSONDict], bot: Optional["Bot"] = None ) -> Optional["ChatBackground"]: """See :meth:`telegram.TelegramObject.de_json`.""" data = cls._parse_data(data) if not data: return None data["type"] = BackgroundType.de_json(data.get("type"), bot) return super().de_json(data=data, bot=bot)