Skip to content

paginator

Provides a basic Paginator to provide a clean interface for users to navigator your multiple embeds.

Note

This can be used for pretty much any list of disnake.Embed

Paginator

Bases: View

Provides a basic paginator View that allows users to navigate over multiple embeds.

Inspired by the paginator.py example provided by disnake

Attributes:

  • message (InteractionMessage) –

    The interaction message associated with this Paginator. Only useful if a timeout has been provided and the original response will need to be edited.

Parameters:

  • embeds (List[Embed]) –

    List of embeds that will be cycled through

  • user (Optional[Member], default: None ) –

    Include a user to prevent others from using buttons.

  • timeout (float, default: 180.0 ) –

    Set the timeout in seconds.

Source code in src\helply\utils\paginator.py
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
class Paginator(disnake.ui.View):
    """Provides a basic paginator View that allows users to navigate over multiple embeds.

    Inspired by the paginator.py example provided by
    [disnake](https://github.com/DisnakeDev/disnake/blob/stable/examples/views/button/paginator.py)

    Attributes
    ----------
    message: disnake.InteractionMessage
        The interaction message associated with this Paginator.
        Only useful if a timeout has been provided and the original response will need to be
        edited.

    Parameters
    ----------
    embeds: List[disnake.Embed]
        List of embeds that will be cycled through
    user: disnake.User, optional
        Include a user to prevent others from using buttons.
    timeout: float
        Set the timeout in seconds.
    """

    message: disnake.InteractionMessage

    def __init__(
        self,
        *,
        embeds: List[disnake.Embed],
        user: Optional[disnake.Member] = None,
        timeout: float = 180.0,
    ) -> None:
        super().__init__(timeout=timeout)
        self.user: Optional[disnake.Member] = user
        self.embeds: List[disnake.Embed] = embeds
        self.index: int = 0

        self._update_state()

    async def on_timeout(self) -> None:
        """Call when Paginator has timed out.

        Requires a Paginator.message to be set and timeout to not be `None`

        Example
        --------
        ```py
        view = utils.Paginator(embeds=embeds, timeout=300)
        await inter.response.send_message(view=view)
        view.message = await inter.original_response()
        ```
        """
        if message := getattr(self, "message", None):
            try:
                await message.edit(view=None)
            except disnake.NotFound:
                # message may have already been deleted
                pass

    async def interaction_check(self, interaction: disnake.MessageInteraction) -> bool:
        """Check if interaction.author is allowed to interact.

        If no member is provided to Paginator, this check always returns True

        Parameters
        ----------
        interaction: disnake.MessageInteraction
            The interaction invoked by a button

        Returns
        -------
        bool
            True if the interaction check passes and the button callback should be invoked,
            else False and the callback will not be invoked.
        """
        if self.user and self.user.id != interaction.author.id:
            await interaction.response.send_message(
                "You do not have permission to interact with this button.", ephemeral=True
            )
            return False

        return True

    def _update_state(self) -> None:
        """
        Update the "state" of the view.

        Enable/disable navigation buttons and update the disable counter component
        """
        self._page_counter.label = f"{self.index + 1} / {len(self.embeds)}"
        self._first_page.disabled = self._prev_page.disabled = self.index == 0
        self._last_page.disabled = self._next_page.disabled = self.index == len(self.embeds) - 1

    @disnake.ui.button(label="First Page", style=disnake.ButtonStyle.primary)
    async def _first_page(
        self, _: disnake.ui.Button[Paginator], inter: disnake.MessageInteraction
    ) -> None:
        """Jump to the first embed."""
        self.index = 0
        self._update_state()

        await inter.response.edit_message(embed=self.embeds[self.index], view=self)

    @disnake.ui.button(label="Prev Page", style=disnake.ButtonStyle.primary)
    async def _prev_page(
        self, _: disnake.ui.Button[Paginator], inter: disnake.MessageInteraction
    ) -> None:
        """Go back one page."""
        self.index -= 1
        self._update_state()

        await inter.response.edit_message(embed=self.embeds[self.index], view=self)

    @disnake.ui.button(label="", style=disnake.ButtonStyle.primary, disabled=True)
    async def _page_counter(
        self, _: disnake.ui.Button[Paginator], __: disnake.MessageInteraction
    ) -> None:
        """Just a page counter and cannot be interacted with."""

    @disnake.ui.button(label="Next Page", style=disnake.ButtonStyle.primary)
    async def _next_page(
        self, _: disnake.ui.Button[Paginator], inter: disnake.MessageInteraction
    ) -> None:
        """Go to next page."""
        self.index += 1
        self._update_state()

        await inter.response.edit_message(embed=self.embeds[self.index], view=self)

    @disnake.ui.button(label="Last Page", style=disnake.ButtonStyle.primary)
    async def _last_page(
        self, _: disnake.ui.Button[Paginator], inter: disnake.MessageInteraction
    ) -> None:
        """Go to last page."""
        self.index = len(self.embeds) - 1
        self._update_state()

        await inter.response.edit_message(embed=self.embeds[self.index], view=self)

interaction_check(interaction) async

Check if interaction.author is allowed to interact.

If no member is provided to Paginator, this check always returns True

Parameters:

  • interaction (MessageInteraction) –

    The interaction invoked by a button

Returns:

  • bool

    True if the interaction check passes and the button callback should be invoked, else False and the callback will not be invoked.

Source code in src\helply\utils\paginator.py
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
async def interaction_check(self, interaction: disnake.MessageInteraction) -> bool:
    """Check if interaction.author is allowed to interact.

    If no member is provided to Paginator, this check always returns True

    Parameters
    ----------
    interaction: disnake.MessageInteraction
        The interaction invoked by a button

    Returns
    -------
    bool
        True if the interaction check passes and the button callback should be invoked,
        else False and the callback will not be invoked.
    """
    if self.user and self.user.id != interaction.author.id:
        await interaction.response.send_message(
            "You do not have permission to interact with this button.", ephemeral=True
        )
        return False

    return True

on_timeout() async

Call when Paginator has timed out.

Requires a Paginator.message to be set and timeout to not be None

Example
view = utils.Paginator(embeds=embeds, timeout=300)
await inter.response.send_message(view=view)
view.message = await inter.original_response()
Source code in src\helply\utils\paginator.py
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
async def on_timeout(self) -> None:
    """Call when Paginator has timed out.

    Requires a Paginator.message to be set and timeout to not be `None`

    Example
    --------
    ```py
    view = utils.Paginator(embeds=embeds, timeout=300)
    await inter.response.send_message(view=view)
    view.message = await inter.original_response()
    ```
    """
    if message := getattr(self, "message", None):
        try:
            await message.edit(view=None)
        except disnake.NotFound:
            # message may have already been deleted
            pass