discordpaginator 1.0.2
A library to create a discord.py embed paginator session. If discord.py version is 1.5.0+, intents are required
License: MIT
Keywords: discord,discord.py,discord paginator,discord reaction menu,discord embed,reaction menu,paginator,embed menu,embed reaction menu,embed paginator

## Demonstration
![demo](https://cdn.discordapp.com/attachments/655186216060321816/785152590852653066/demo.gif)

---
## How to import
```py
from discordpaginator import Paginator, ButtonType, CustomButton
```
This library comes with serveral methods and options in order to make an embed pagination session more simple. Once you have imported the paginator, you will have to initialize the constructor like so:
```py
pagination = Paginator(ctx, next_button='\U000027a1', back_button='\U00002b05', dynamic=True) 
```
---
## Parameters of the constructor
* `ctx` The `discord.ext.commands.Context` object
* `next_button` Button used to go the next page. 
* `back_button` Button used to go to the previous page. 
* `dynamic` The dynamic of the paginator, needs to be `True` or `False`. Having the dynamic set to `True` is meant for manually adding pages to the embed when a fixed amount of pages will be added. On the other hand, `False` is used for when an unknown amount of data can/will be applied to the paginator, i.e, getting information from a database. More on this below.
---
## Options of the constructor [kwargs]
* `clear_reactions_after` | `bool` Once the paginator session is finished (timed out), clear the reactions
* `timeout` | `Union[float, None]` The amount of seconds to wait before the session times out. Can be `None` for no timeout
* `show_page_director` | `bool` To show or not show the current page at the bottom of each embed pagination session. i.e, "Page 1/23"
* `rows_per_page` | `int` In a **dynamic** session, specify the amount of rows that will contain data
* `custom_embed_for_row_pages` | `discord.Embed` A custom embed to use when the paginator session is **dynamic**
* `name` | `str` Name of the pagination session
* `style` | `str` A custom page director style you can select. "$" represents the current page, "&" represents the total amount of pages. Example: `style="On $ out of &"`
* `all_can_react` | `bool` Sets if everyone is allowed to control when pages are "turned" when buttons are pressed
---
## Attributes
| Name                  | Return type                   | Settable | Details
|-----------------------|-------------------------------|----------|--------
| `all_can_react`       | `bool`                        | Yes      | See above
| `is_running`          | `bool`                        | No       | If the pagination session is active
| `name`                | `str`                         | Yes      | See above
| `custom_buttons`      | `List[CustomButton]`       | No       | See *Buttons*
| `back_button`         | `str`                         | No       | See above 
| `next_button`         | `str`                         | No       | See above
| `end_session_button`         | `str`       | No       | See *Buttons*
| `first_page_button`     | `str`       | No       | See *Buttons*
| `last_page_button`    | `str`     | No       | See *Buttons*
| `all_buttons`         | `List[str]`                   | No       | The emojis you have added for use
| `custom_embed_for_row_pages` | `discord.Embed` | Yes | The embed you set for row pages
---
## Buttons
There are 3 types of buttons you can add if you see fit
> **End session button:** The button that deletes the pagination message.
```py
pagination.add_button('\U000023ea', ButtonType.END_SESSION)
```

> **First to last page buttons:** The buttons used to go to the first or last page.
```py
pagination.add_button('\U000023ea', ButtonType.GO_TO_FIRST_PAGE)

pagination.add_button('\U000023ea', ButtonType.GO_TO_LAST_PAGE)
```

> **Custom Buttons:** The one used to go to the embed you assign
```py
my_button = CustomButton(emoji='\U0000274c', points_to=embed, name='optional name')
pagination.add_custom_button(my_button)
```
> **NOTE:** Once you've added all the buttons, you can change the order they appear in on the message
```py
pagination.change_button_order(['\U000023ea', '\U00002b05', '\U0000274c', '\U000027a1', '\U000023e9', '\U0001f60e'])

# tip: when you assign a button, you can access it using its property for easy assignment

pagination.change_button_order([pagination.next_button, pagination.end_session_button]) # etc. 
```
> **NOTE:** All buttons support emojis, unicode, and guild emojis. They are no different from a reaction
---
## Adding/Removing/Clearing Pages
You can add pages using the `.add_page` method
> **NOTE:** Adding pages only applies to **non**-dynamic pagination sessions (`dynamic=False`)
```py
pagination.add_page(embed)
```
To delete all pages, use the `.clear_all_pages` method
> **NOTE:** You can only clear all pages on **non**-dynamic pagination sessions (`dynamic=False`)
```py
pagination.clear_all_pages()
```
You can remove a certain page using the `.remove_page` method
```py
pagination.remove_page(3)
``` 
---
## Non-dynamic paginator
In this section, I will refer to non dynamic paginators as "static". A static paginator is when you have the `dynamic` parameter set to `False`. You usually want to make the paginator static when you have a fixed amount of embeds you'd like to use. Example:
```py
pagination = Paginator(ctx, next_button='\U000027a1', back_button='\U00002b05', dynamic=False)

will_smith = discord.Embed(title='Will Smith', description='https://www.instagram.com/willsmith/', color=discord.Color.blue())
chris_hems = discord.Embed(title='Chris Hemsworth', description='https://www.instagram.com/chrishemsworth/', color=discord.Color.dark_red())

pagination.add_page(will_smith)
pagination.add_page(chris_hems)
```
Although static pagination sessions are meant for the manual adding of pages, you can still use it somewhat dynamically (such as loops)
```py
member_details = [] # contains embed objects
pagination = Paginator(ctx, next_button='\U000027a1', back_button='\U00002b05', dynamic=False)

for member_embed in member_details:
    pagination.add_page(member_embed)
```
---
## Dynamic paginator
As stated above, a dynamic pagination session is used when there is an unknown amount of data that will be recieved, such as querying things from a database, or maybe a web request of some sort. When using a dynamic session, the dynamic must be set to `True`, and the constructor must inlcude the kwarg `rows_per_page`. See "Options" above for details on `rows_per_page`. Example:
> **NOTE:** When applying data, ensure there isn't an excess amount of new lines (`\n`), because that will throw off "rows_per_page". All information should still be applied, but the format might look a little weird. Also, if a custom embed is used, all description information will be overriden and replaced with the data that is applied to the row
```py
my_data = example.fetch_information() # returns an Iterable with x amount of information
pagination = Paginator(ctx, next_button='\U000027a1', back_button='\U00002b05', dynamic=True, rows_per_page=5)

for data in my_data:
    pagination.add_row(data)
```
Although dynamic pagination sessions are meant for an x amount of data/pages to use, you can still use it somewhat statically
```py
pagination = Paginator(ctx, next_button='\U000027a1', back_button='\U00002b05', dynamic=True, rows_per_page=2)
pagination.add_row('Made')
pagination.add_row('by')
pagination.add_row('Defxult#8269')
pagination.add_row('=)')
```
If you have a dynamic session, you might want to show a first or last page. Maybe the first page being a welcome page, or the last page being some informative info. You can do so with `.insert_main_page` and `.insert_last_page`. Example:
> **NOTE:** Those methods can only be called in a dynamic session
```py
for data in example.fetch_information():
    pagination.add_row(data)

pagination.insert_main_page(welcome_embed)
pagination.insert_last_page(details_embed)
```
---
## Starting the paginator
You can start the pagination session by using the `.start` method
```py
await pagination.start()
```
## Stopping the paginator
You can stop the pagination session by using the `.cancel` method. Upon cancelling the session, you can either delete the pagination message or clear all reactions
```py
await pagination.cancel(delete_paginator_message=True)
# or
await pagination.cancel(clear_reactions=True)
```
## All methods
```python
Paginator.clear_all_pages()
Paginator.add_page(embed: Embed)
Paginator.remove_page(page_number: int)
Paginator.add_row(data: str)
Paginator.insert_main_page(embed: Embed)
Paginator.insert_last_page(embed: Embed)

Paginator.add_button(emoji: str, type_: ButtonType)
Paginator.add_custom_button(custom: CustomButton)
Paginator.get_custom_button_by_name(name: str)
Paginator.change_button_order(emojis: List[str])
Paginator.cancel(*, delete_paginator_message=False, clear_reaction=False)
Paginator.start()
```
---
## Bug Reports / Suggestions
If you find any bugs or have any suggestions, please submit them on [Github](https://github.com/Defxult/discordpaginator/issues)