PycordViews 1.2.4__tar.gz → 1.2.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pycordviews-1.2.4 → pycordviews-1.2.6}/PKG-INFO +1 -1
- {pycordviews-1.2.4 → pycordviews-1.2.6}/PycordViews.egg-info/PKG-INFO +1 -1
- {pycordviews-1.2.4 → pycordviews-1.2.6}/PycordViews.egg-info/SOURCES.txt +8 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/PycordViews.egg-info/top_level.txt +1 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/pycordViews/__init__.py +1 -0
- pycordviews-1.2.6/pycordViews/kit/__init__.py +2 -0
- pycordviews-1.2.6/pycordViews/kit/confirm.py +69 -0
- pycordviews-1.2.6/pycordViews/kit/poll.py +147 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/pycordViews/pagination/__init__.py +1 -0
- pycordviews-1.2.6/pycordViews/pagination/page.py +25 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/pycordViews/pagination/pagination_view.py +24 -16
- {pycordviews-1.2.4 → pycordviews-1.2.6}/pycordViews/views/easy_modified_view.py +62 -22
- pycordviews-1.2.6/pycordViews/views/errors.py +13 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/setup.py +2 -2
- pycordviews-1.2.4/pycordViews/views/errors.py +0 -9
- {pycordviews-1.2.4 → pycordviews-1.2.6}/LICENSE +0 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/PycordViews.egg-info/dependency_links.txt +0 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/PycordViews.egg-info/requires.txt +0 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/README.md +0 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/pycordViews/menu/__init__.py +0 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/pycordViews/menu/errors.py +0 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/pycordViews/menu/menu.py +0 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/pycordViews/menu/selectMenu.py +0 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/pycordViews/multibot/__init__.py +0 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/pycordViews/multibot/bot.py +0 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/pycordViews/multibot/errors.py +0 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/pycordViews/multibot/multibot.py +0 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/pycordViews/multibot/process.py +0 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/pycordViews/pagination/errors.py +0 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/pycordViews/views/__init__.py +0 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/pyproject.toml +0 -0
- {pycordviews-1.2.4 → pycordviews-1.2.6}/setup.cfg +0 -0
@@ -8,6 +8,9 @@ PycordViews.egg-info/dependency_links.txt
|
|
8
8
|
PycordViews.egg-info/requires.txt
|
9
9
|
PycordViews.egg-info/top_level.txt
|
10
10
|
pycordViews/__init__.py
|
11
|
+
pycordViews/kit/__init__.py
|
12
|
+
pycordViews/kit/confirm.py
|
13
|
+
pycordViews/kit/poll.py
|
11
14
|
pycordViews/menu/__init__.py
|
12
15
|
pycordViews/menu/errors.py
|
13
16
|
pycordViews/menu/menu.py
|
@@ -19,10 +22,14 @@ pycordViews/multibot/multibot.py
|
|
19
22
|
pycordViews/multibot/process.py
|
20
23
|
pycordViews/pagination/__init__.py
|
21
24
|
pycordViews/pagination/errors.py
|
25
|
+
pycordViews/pagination/page.py
|
22
26
|
pycordViews/pagination/pagination_view.py
|
23
27
|
pycordViews/views/__init__.py
|
24
28
|
pycordViews/views/easy_modified_view.py
|
25
29
|
pycordViews/views/errors.py
|
30
|
+
pycordViews/kit/__init__.py
|
31
|
+
pycordViews/kit/confirm.py
|
32
|
+
pycordViews/kit/poll.py
|
26
33
|
pycordViews/menu/__init__.py
|
27
34
|
pycordViews/menu/errors.py
|
28
35
|
pycordViews/menu/menu.py
|
@@ -34,6 +41,7 @@ pycordViews/multibot/multibot.py
|
|
34
41
|
pycordViews/multibot/process.py
|
35
42
|
pycordViews/pagination/__init__.py
|
36
43
|
pycordViews/pagination/errors.py
|
44
|
+
pycordViews/pagination/page.py
|
37
45
|
pycordViews/pagination/pagination_view.py
|
38
46
|
pycordViews/views/__init__.py
|
39
47
|
pycordViews/views/easy_modified_view.py
|
@@ -0,0 +1,69 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
from ..views.easy_modified_view import EasyModifiedViews
|
3
|
+
from discord import Interaction, ButtonStyle, Bot
|
4
|
+
from discord.ui import Button
|
5
|
+
from asyncio import wait_for, Future, get_event_loop, TimeoutError
|
6
|
+
|
7
|
+
|
8
|
+
class Confirm:
|
9
|
+
|
10
|
+
def __init__(self, timeout: Optional[float] = None, disable_on_click: bool = False):
|
11
|
+
"""
|
12
|
+
Init a Confirm class instance kit.
|
13
|
+
:param timeout: Time before end the view
|
14
|
+
"""
|
15
|
+
self.__timeout: float = timeout
|
16
|
+
self.__disable_on_click: bool = disable_on_click
|
17
|
+
self.__view: EasyModifiedViews = EasyModifiedViews(disabled_on_timeout=True, timeout=timeout, call_on_timeout=self._on_timeout)
|
18
|
+
self.__button_confirm: Button = Button(label='Confirm', emoji='✅', style=ButtonStyle.green, custom_id='Confirm_confirm')
|
19
|
+
self.__button_denied: Button = Button(label='Denied', emoji='❌', style=ButtonStyle.gray, custom_id='Confirm_denied')
|
20
|
+
self.__view.add_items(self.__button_confirm, self.__button_denied)
|
21
|
+
self.__view.set_callable(self.__button_confirm.custom_id, _callable=self._confirm)
|
22
|
+
self.__view.set_callable(self.__button_denied.custom_id, _callable=self._denied)
|
23
|
+
|
24
|
+
self.__future: Future = get_event_loop().create_future()
|
25
|
+
|
26
|
+
async def _confirm(self, button: Button, interaction: Interaction):
|
27
|
+
"""
|
28
|
+
Base asynchronous _confirm function called when button is pressed
|
29
|
+
"""
|
30
|
+
if not self.__future.done():
|
31
|
+
self.__future.set_result(True)
|
32
|
+
if self.__disable_on_click:
|
33
|
+
await self.__view.disable_items('Confirm_confirm', 'Confirm_denied')
|
34
|
+
await interaction.response.defer()
|
35
|
+
|
36
|
+
async def _denied(self, button: Button, interaction: Interaction):
|
37
|
+
"""
|
38
|
+
Base asynchronous _denied function called when button is pressed
|
39
|
+
"""
|
40
|
+
if not self.__future.done():
|
41
|
+
self.__future.set_result(False)
|
42
|
+
if self.__disable_on_click:
|
43
|
+
await self.__view.disable_items('Confirm_confirm', 'Confirm_denied')
|
44
|
+
await interaction.response.defer()
|
45
|
+
|
46
|
+
async def wait_for_response(self) -> Optional[bool]:
|
47
|
+
"""
|
48
|
+
Wait and return the result of current button pressed.
|
49
|
+
:return: True if it is confirmed, False else. If timeout is reached, return None
|
50
|
+
"""
|
51
|
+
try:
|
52
|
+
return await wait_for(self.__future, timeout=self.__timeout)
|
53
|
+
|
54
|
+
except TimeoutError:
|
55
|
+
return None
|
56
|
+
|
57
|
+
async def _on_timeout(self, ctx):
|
58
|
+
"""
|
59
|
+
Called when the timeout is reached to end the Future
|
60
|
+
"""
|
61
|
+
if not self.__future.done():
|
62
|
+
self.__future.set_result(None)
|
63
|
+
|
64
|
+
@property
|
65
|
+
def get_view(self) -> EasyModifiedViews:
|
66
|
+
"""
|
67
|
+
Get the current view
|
68
|
+
"""
|
69
|
+
return self.__view
|
@@ -0,0 +1,147 @@
|
|
1
|
+
from ..views.easy_modified_view import EasyModifiedViews
|
2
|
+
from ..views.errors import CoroutineError
|
3
|
+
from discord.ui.button import Button, ButtonStyle
|
4
|
+
from discord import Emoji, PartialEmoji, Embed, Color
|
5
|
+
from typing import Optional, Callable, Union
|
6
|
+
from asyncio import iscoroutinefunction
|
7
|
+
|
8
|
+
|
9
|
+
class Poll:
|
10
|
+
|
11
|
+
def __init__(self, timeout: Optional[float] = None, unique_vote: bool = True):
|
12
|
+
"""
|
13
|
+
Class instance to make poll with buttons
|
14
|
+
:param timeout: Time before end the view
|
15
|
+
:param unique_vote: Set True to make vote unchangeable
|
16
|
+
"""
|
17
|
+
self.yes_count: int = 0
|
18
|
+
self.no_count: int = 0
|
19
|
+
self.__unique_vote: bool = unique_vote
|
20
|
+
self.__view = EasyModifiedViews(disabled_on_timeout=True, timeout=timeout)
|
21
|
+
self.__button_yes = Button(label='Yes', emoji='✅', custom_id='Poll_yes', style=ButtonStyle.green)
|
22
|
+
self.__button_no = Button(label='No', emoji='❌', custom_id='Poll_no', style=ButtonStyle.gray)
|
23
|
+
self.__view.add_items(self.__button_yes, self.__button_no)
|
24
|
+
self.__view.set_callable('Poll_yes', _callable=self.yes)
|
25
|
+
self.__view.set_callable('Poll_no', _callable=self.no)
|
26
|
+
self.__view.call_on_timeout(self._result) # asynchrone fonction quand la view est arrivé à son timeout
|
27
|
+
self.__clicked_members: list[int] = []
|
28
|
+
|
29
|
+
def add_answer_button(self, label: str,
|
30
|
+
custom_id: str,
|
31
|
+
emoji: Optional[Union[str, Emoji, PartialEmoji]] = None,
|
32
|
+
style: ButtonStyle = ButtonStyle.secondary,
|
33
|
+
row: Optional[int] = None,
|
34
|
+
_callable: Optional[Callable] = None) -> Button:
|
35
|
+
"""
|
36
|
+
Create a new answer button and add it in the view.
|
37
|
+
:param label: Button label
|
38
|
+
:param custom_id: Button ID
|
39
|
+
:param emoji: Button emoji
|
40
|
+
:param style: Button style
|
41
|
+
:param row: Button row
|
42
|
+
:param _callable: Asynchronous function linked to the button interaction. It's called when the button is pressed
|
43
|
+
"""
|
44
|
+
|
45
|
+
if not iscoroutinefunction(_callable):
|
46
|
+
raise CoroutineError(_callable)
|
47
|
+
|
48
|
+
b = Button(label=label, emoji=emoji, style=style, row=row, custom_id=custom_id)
|
49
|
+
self.__view.add_items(b)
|
50
|
+
self.__view.set_callable(custom_id, _callable=_callable)
|
51
|
+
|
52
|
+
return b
|
53
|
+
|
54
|
+
|
55
|
+
def set_yes_button(self, label: Optional[str] = None,
|
56
|
+
emoji: Optional[Union[str, Emoji, PartialEmoji]] = None,
|
57
|
+
style: Optional[ButtonStyle] = None,
|
58
|
+
row: Optional[int] = None,
|
59
|
+
_callable: Optional[Callable] = None):
|
60
|
+
"""
|
61
|
+
Set yes button parameters (he didn't change dynamically if the view was sent before)
|
62
|
+
:param label: Button label
|
63
|
+
:param emoji: Button emoji
|
64
|
+
:param style: Button style
|
65
|
+
:param row: Button row
|
66
|
+
:param _callable: Asynchronous function linked to the button interaction. It's called when the button is pressed
|
67
|
+
"""
|
68
|
+
self.__button_yes.emoji = emoji if emoji is not None else self.__button_yes.emoji
|
69
|
+
self.__button_yes.style = style if style is not None else self.__button_yes.style
|
70
|
+
self.__button_yes.label = label if label is not None else self.__button_yes.label
|
71
|
+
self.__button_yes.row = row if row is not None else self.__button_yes.row
|
72
|
+
|
73
|
+
if not iscoroutinefunction(_callable):
|
74
|
+
raise CoroutineError(_callable)
|
75
|
+
|
76
|
+
if _callable is not None:
|
77
|
+
self.__view.set_callable(self.__button_yes.custom_id, _callable=_callable)
|
78
|
+
|
79
|
+
def set_no_button(self, label: Optional[str] = None,
|
80
|
+
emoji: Optional[Union[str, Emoji, PartialEmoji]] = None,
|
81
|
+
style: Optional[ButtonStyle] = None,
|
82
|
+
row: Optional[int] = None,
|
83
|
+
_callable: Optional[Callable] = None):
|
84
|
+
"""
|
85
|
+
Set no button parameters (he didn't change dynamically if the view was sent before)
|
86
|
+
:param label: Button label
|
87
|
+
:param emoji: Button emoji
|
88
|
+
:param row: Button row
|
89
|
+
:param style: Button style
|
90
|
+
:param callable: Asynchronous function linked to the button interaction. It's called when the button is pressed
|
91
|
+
"""
|
92
|
+
self.__button_no.emoji = emoji if emoji is not None else self.__button_no.emoji
|
93
|
+
self.__button_no.style = style if style is not None else self.__button_no.style
|
94
|
+
self.__button_no.label = label if label is not None else self.__button_no.label
|
95
|
+
self.__button_no.row = row if row is not None else self.__button_no.row
|
96
|
+
|
97
|
+
if not iscoroutinefunction(_callable):
|
98
|
+
raise CoroutineError(_callable)
|
99
|
+
|
100
|
+
if _callable is not None:
|
101
|
+
self.__view.set_callable(self.__button_no.custom_id, _callable=_callable)
|
102
|
+
|
103
|
+
async def yes(self, button, interaction):
|
104
|
+
"""
|
105
|
+
Base asynchronous function when "yes" button is pressed.
|
106
|
+
Increment “yes_count” attribute when pressed and respond with an ephemeral message.
|
107
|
+
This function can be changed.
|
108
|
+
"""
|
109
|
+
if self.__unique_vote and interaction.user.id in self.__clicked_members:
|
110
|
+
await interaction.response.send_message(f"You have already voted !", ephemeral=True)
|
111
|
+
return
|
112
|
+
self.yes_count += 1
|
113
|
+
self.__clicked_members.append(interaction.user.id)
|
114
|
+
await interaction.response.send_message(f"You have selected : {button.label}", ephemeral=True)
|
115
|
+
|
116
|
+
async def no(self, button, interaction):
|
117
|
+
"""
|
118
|
+
Base asynchronous function when "no" button is pressed.
|
119
|
+
Increment “yes_count” attribute when pressed and respond with an ephemeral message.
|
120
|
+
This function can be changed.
|
121
|
+
"""
|
122
|
+
if self.__unique_vote and interaction.user.id in self.__clicked_members:
|
123
|
+
await interaction.response.send_message(f"You have already voted !", ephemeral=True)
|
124
|
+
return
|
125
|
+
self.yes_count += 1
|
126
|
+
self.__clicked_members.append(interaction.user.id)
|
127
|
+
await interaction.response.send_message(f"You have selected : {button.label}", ephemeral=True)
|
128
|
+
|
129
|
+
async def _result(self, ctx):
|
130
|
+
"""
|
131
|
+
Asynchronous base function called when timeout is reached.
|
132
|
+
:param ctx: Actual command context
|
133
|
+
"""
|
134
|
+
embed = Embed(title="Poll ended !",
|
135
|
+
description=f"## Results :\n"
|
136
|
+
f" `-` {self.__button_yes.emoji.name} {self.__button_yes.label} -> `{self.yes_count}`\n"
|
137
|
+
f" `-` {self.__button_no.emoji.name} {self.__button_no.label} -> `{self.no_count}`",
|
138
|
+
color=Color.gold())
|
139
|
+
|
140
|
+
await self.__view.message.reply(embed=embed)
|
141
|
+
|
142
|
+
@property
|
143
|
+
def get_view(self) -> EasyModifiedViews:
|
144
|
+
"""
|
145
|
+
Get the current view
|
146
|
+
"""
|
147
|
+
return self.__view
|
@@ -0,0 +1,25 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
from typing import Optional, Callable
|
3
|
+
from discord import File, Embed
|
4
|
+
from immutableType import callable_, NoneType
|
5
|
+
from ..views import EasyModifiedViews
|
6
|
+
|
7
|
+
class Page:
|
8
|
+
|
9
|
+
@callable_(is_class=True, kwargs_types={'view': [NoneType, EasyModifiedViews], 'content': [NoneType, str], 'embed': [NoneType, Embed], 'embeds': [list], 'file': [NoneType, File], 'files': [list]})
|
10
|
+
def __init__(self, view: EasyModifiedViews, content: Optional[str] = None, embed: Optional[Embed] = None, embeds: list[Embed] = [], file: Optional[File] = None, files: Optional[list[File]] = []):
|
11
|
+
"""
|
12
|
+
Init Page instance from Pagination class
|
13
|
+
"""
|
14
|
+
self.__view: EasyModifiedViews = view if view is not None else EasyModifiedViews()
|
15
|
+
self.content: Optional[str] = content
|
16
|
+
self.embeds: list[Embed] = embeds if embed is None else embeds + [embed]
|
17
|
+
self.files: list[File] = files if file is None else files + [file]
|
18
|
+
|
19
|
+
@property
|
20
|
+
def get_page_view(self) -> EasyModifiedViews:
|
21
|
+
"""
|
22
|
+
Get the current page view
|
23
|
+
"""
|
24
|
+
return self.__view
|
25
|
+
|
@@ -1,9 +1,10 @@
|
|
1
1
|
from ..views.easy_modified_view import EasyModifiedViews
|
2
|
-
from discord import ButtonStyle, Interaction, TextChannel, Member, ApplicationContext
|
2
|
+
from discord import ButtonStyle, Interaction, TextChannel, Member, ApplicationContext, File, Embed
|
3
3
|
from discord.ui import Button
|
4
4
|
from .errors import PageNumberNotFound
|
5
|
+
from .page import Page
|
5
6
|
|
6
|
-
from typing import Union, Any
|
7
|
+
from typing import Union, Any, Optional
|
7
8
|
|
8
9
|
|
9
10
|
class Pagination:
|
@@ -28,17 +29,17 @@ class Pagination:
|
|
28
29
|
self.__view.add_items(Button(label='⏭', row=0, custom_id='forward+', style=ButtonStyle.blurple))
|
29
30
|
self.__view.set_callable('back+', 'back', 'forward', 'forward+', _callable=self.__turn_page)
|
30
31
|
|
31
|
-
self.__pages: list[
|
32
|
+
self.__pages: list[Page] = []
|
32
33
|
self.__current_page: int = 0
|
33
34
|
|
34
|
-
def add_page(self,
|
35
|
+
def add_page(self, content: Optional[str] = None, embed: Optional[Embed] = None, embeds: list[Embed] = [], file: Optional[File] = None, files: Optional[list[File]] = [], view: Optional[EasyModifiedViews] = None) -> "Pagination":
|
35
36
|
"""
|
36
37
|
Adds a page (in a list) as if this function directly sent the message
|
37
38
|
Pages are just modified and not reset ! Don't forget to disable embeds or content if the page don't need this.
|
38
39
|
|
39
40
|
add_page(content="my message", embeds=[embed1, embed2], ...)
|
40
41
|
"""
|
41
|
-
self.__pages.append((
|
42
|
+
self.__pages.append(Page(content=content, embed=embed, embeds=embeds, file=file, files=files, view=view))
|
42
43
|
self.__view.get_ui('counter').label = f"{self.__current_page+1}/{len(self.__pages)}"
|
43
44
|
return self
|
44
45
|
|
@@ -86,13 +87,15 @@ class Pagination:
|
|
86
87
|
|
87
88
|
self.__view.get_ui('counter').label = f"{self.__current_page + 1}/{len(self.__pages)}"
|
88
89
|
|
89
|
-
|
90
|
+
c = self.__pages[self.__current_page]
|
90
91
|
|
91
|
-
|
92
|
+
await interaction.message.edit(
|
92
93
|
|
93
|
-
|
94
|
+
content=c.content,
|
95
|
+
embeds=c.embeds,
|
96
|
+
files=c.files,
|
94
97
|
|
95
|
-
|
98
|
+
view=self.__view.copy() + self.__pages[self.__current_page].get_page_view,
|
96
99
|
|
97
100
|
)
|
98
101
|
|
@@ -104,23 +107,28 @@ class Pagination:
|
|
104
107
|
Send pagination without introduction message.
|
105
108
|
:param target: The member or channel to send the pagination
|
106
109
|
"""
|
107
|
-
|
110
|
+
first_page = self.__pages[0]
|
111
|
+
return await self.__view.send(target=target, content=first_page.content, embeds=first_page.embeds, files=first_page.files, view=self.__view.copy() + first_page.get_page_view)
|
108
112
|
|
109
113
|
async def respond(self, ctx: ApplicationContext) -> Any:
|
110
114
|
"""
|
111
115
|
Respond to the command call
|
116
|
+
:param ctx: ApplicationContext to respond
|
112
117
|
"""
|
113
|
-
|
118
|
+
first_page = self.__pages[0]
|
119
|
+
return await self.__view.respond(ctx=ctx, content=first_page.content, embeds=first_page.embeds, files=first_page.files, view=self.__view.copy() + first_page.get_page_view)
|
114
120
|
|
115
|
-
|
116
|
-
def get_view(self) -> EasyModifiedViews:
|
121
|
+
def get_page(self, page_number: int) -> Page:
|
117
122
|
"""
|
118
|
-
Get the
|
123
|
+
Get the page
|
119
124
|
"""
|
120
|
-
|
125
|
+
if 0 <= page_number <= len(self.__pages):
|
126
|
+
return self.__pages[page_number]
|
127
|
+
else:
|
128
|
+
raise PageNumberNotFound(page_number)
|
121
129
|
|
122
130
|
@property
|
123
|
-
def
|
131
|
+
def get_current_showed_page(self) -> int:
|
124
132
|
"""
|
125
133
|
Get the number of showed page
|
126
134
|
(start to 0)
|
@@ -1,13 +1,16 @@
|
|
1
1
|
from __future__ import annotations
|
2
|
-
from discord import Interaction, ApplicationContext, Message, Member
|
2
|
+
from discord import Interaction, ApplicationContext, Message, Member
|
3
|
+
from discord.abc import GuildChannel
|
3
4
|
from discord.ui import View, Item
|
4
|
-
from typing import Union, Callable, TYPE_CHECKING
|
5
|
+
from typing import Union, Callable, TYPE_CHECKING, Optional
|
6
|
+
from asyncio import iscoroutinefunction, create_task
|
5
7
|
|
6
|
-
from .errors import CustomIDNotFound
|
8
|
+
from .errors import CustomIDNotFound, CoroutineError
|
7
9
|
|
8
10
|
if TYPE_CHECKING:
|
9
11
|
from ..menu.selectMenu import SelectMenu
|
10
12
|
from ..pagination.pagination_view import Pagination
|
13
|
+
from ..kit import Poll, Confirm
|
11
14
|
|
12
15
|
|
13
16
|
class EasyModifiedViews(View):
|
@@ -17,16 +20,19 @@ class EasyModifiedViews(View):
|
|
17
20
|
Allows you to easily modify and replace an ui.
|
18
21
|
"""
|
19
22
|
|
20
|
-
def __init__(self, timeout:
|
23
|
+
def __init__(self, timeout: Optional[float] = None, disabled_on_timeout: bool = False, call_on_timeout: Optional[Callable] = None, *items: Item):
|
21
24
|
"""
|
22
25
|
Init a Class view for Discord UI
|
23
26
|
:param timeout: The time before ui disable
|
27
|
+
:param disabled_on_timeout: disable view if timeout is reached
|
28
|
+
:param call_on_timeout: asynchronous function to call after view timed-out
|
24
29
|
"""
|
25
30
|
super().__init__(*items, timeout=timeout)
|
26
|
-
self.__timeout:
|
31
|
+
self.__timeout: Optional[float] = timeout
|
27
32
|
self.__disabled_on_timeout: bool = disabled_on_timeout
|
28
33
|
self.__callback: dict[str, dict[str, Union[Callable[[Interaction], None], Item]]] = {}
|
29
34
|
self.__ctx: Union[Message, Interaction] = None
|
35
|
+
self.__call_on_timeout: Callable = call_on_timeout
|
30
36
|
|
31
37
|
def __check_custom_id(self, custom_id: str) -> None:
|
32
38
|
"""
|
@@ -43,21 +49,24 @@ class EasyModifiedViews(View):
|
|
43
49
|
"""
|
44
50
|
self.__ctx = await ctx.respond(*args, **kwargs)
|
45
51
|
|
46
|
-
async def send(self, target: Union[Member,
|
52
|
+
async def send(self, target: Union[Member, GuildChannel], *args, **kwargs) -> None:
|
47
53
|
"""
|
48
54
|
Send at the target
|
49
55
|
"""
|
50
56
|
self.__ctx = await target.send(*args, **kwargs)
|
51
57
|
|
52
58
|
def add_items(self,
|
53
|
-
*items: Union[
|
59
|
+
*items: Union[EasyModifiedViews, Confirm, Pagination, Poll, SelectMenu, Item]) -> EasyModifiedViews:
|
54
60
|
"""
|
55
61
|
Add all items in the View.
|
56
62
|
"""
|
57
63
|
|
58
64
|
for ui in items:
|
59
65
|
|
60
|
-
if
|
66
|
+
if ui is None: # si l'ui n'est pas setup
|
67
|
+
continue
|
68
|
+
|
69
|
+
if type(ui).__name__ in ('SelectMenu', 'Pagination', 'Confirm', 'Poll', 'EasyModifiedViews'):
|
61
70
|
for item in ui.get_view.items:
|
62
71
|
self.add_items(item)
|
63
72
|
self.set_callable(item.custom_id, _callable=ui.get_callable(item.custom_id))
|
@@ -118,7 +127,7 @@ class EasyModifiedViews(View):
|
|
118
127
|
"""
|
119
128
|
set up a callable for items
|
120
129
|
:param custom_ids: items IDs of the view
|
121
|
-
:param _callable: The callable linked
|
130
|
+
:param _callable: The asynchronous callable linked. Take UI (Button, Select...) and Interaction parameters.
|
122
131
|
|
123
132
|
**UI and Interaction parameter is required in callable function !**
|
124
133
|
|
@@ -230,7 +239,6 @@ class EasyModifiedViews(View):
|
|
230
239
|
|
231
240
|
return True
|
232
241
|
|
233
|
-
|
234
242
|
async def delete_items(self, clear_all: bool = False, *custom_ids: str) -> None:
|
235
243
|
"""
|
236
244
|
Delete an item on the view
|
@@ -254,13 +262,25 @@ class EasyModifiedViews(View):
|
|
254
262
|
Called if timeout view is finished
|
255
263
|
"""
|
256
264
|
if self.__disabled_on_timeout:
|
257
|
-
self.shutdown()
|
265
|
+
create_task(self.shutdown())
|
266
|
+
if self.__call_on_timeout is not None:
|
267
|
+
create_task(self.__call_on_timeout(self.__ctx))
|
268
|
+
|
269
|
+
def call_on_timeout(self, _callable: Callable) -> None:
|
270
|
+
"""
|
271
|
+
Call asynchronous function passed when the timeout is reached.
|
272
|
+
:param _callable: asynchronous function to call. It takes one argument : ctx
|
273
|
+
"""
|
274
|
+
if iscoroutinefunction(_callable):
|
275
|
+
self.__call_on_timeout = _callable
|
276
|
+
else:
|
277
|
+
raise CoroutineError(_callable)
|
258
278
|
|
259
279
|
async def _update(self) -> None:
|
260
280
|
"""
|
261
281
|
Update the View on the attached message.
|
262
282
|
"""
|
263
|
-
if self.is_finished():
|
283
|
+
if self.is_finished() and not self.__disabled_on_timeout:
|
264
284
|
return
|
265
285
|
|
266
286
|
if self.message:
|
@@ -269,16 +289,6 @@ class EasyModifiedViews(View):
|
|
269
289
|
elif self.__ctx:
|
270
290
|
await self.__ctx.edit(view=self)
|
271
291
|
|
272
|
-
else:
|
273
|
-
return
|
274
|
-
|
275
|
-
@property
|
276
|
-
def get_uis(self) -> list[Item]:
|
277
|
-
"""
|
278
|
-
Get all uis in the view
|
279
|
-
"""
|
280
|
-
return [i['ui'] for i in self.__callback.values()]
|
281
|
-
|
282
292
|
def get_ui(self, custom_id: str) -> Item:
|
283
293
|
"""
|
284
294
|
Get an ui in the view
|
@@ -287,9 +297,39 @@ class EasyModifiedViews(View):
|
|
287
297
|
self.__check_custom_id(custom_id)
|
288
298
|
return self.__callback[custom_id]['ui']
|
289
299
|
|
300
|
+
def copy(self) -> EasyModifiedViews:
|
301
|
+
"""
|
302
|
+
Return an exact copy of the view. All mutable object in the view is a new object
|
303
|
+
"""
|
304
|
+
e = EasyModifiedViews(timeout=self.__timeout, disabled_on_timeout=self.__disabled_on_timeout).add_items(*self.items)
|
305
|
+
for i in self.items:
|
306
|
+
e.set_callable(i.custom_id, _callable=self.get_callable(i.custom_id))
|
307
|
+
|
308
|
+
return e
|
309
|
+
|
290
310
|
def __str__(self):
|
291
311
|
return str(self.__callback)
|
292
312
|
|
293
313
|
@property
|
294
314
|
def items(self) -> tuple[Item]:
|
295
315
|
return tuple([i['ui'] for i in self.__callback.values()])
|
316
|
+
|
317
|
+
@property
|
318
|
+
def get_view(self) -> EasyModifiedViews:
|
319
|
+
"""
|
320
|
+
Get The current view. Don't use in your code
|
321
|
+
"""
|
322
|
+
return self
|
323
|
+
|
324
|
+
def __add__(self, _view: Union[EasyModifiedViews, Confirm, Pagination, Poll, SelectMenu, Item]) -> EasyModifiedViews:
|
325
|
+
"""
|
326
|
+
Add all items to _view from the current EasyModifiedViews instance
|
327
|
+
"""
|
328
|
+
self.add_items(_view)
|
329
|
+
return self
|
330
|
+
|
331
|
+
def __iadd__(self, _view) -> EasyModifiedViews:
|
332
|
+
"""
|
333
|
+
Add all items to _view from the current EasyModifiedViews instance
|
334
|
+
"""
|
335
|
+
return self.__add__(_view)
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Py_cordEasyModifiedViews(Exception):
|
2
|
+
"""
|
3
|
+
Main class exception
|
4
|
+
"""
|
5
|
+
|
6
|
+
|
7
|
+
class CustomIDNotFound(Py_cordEasyModifiedViews):
|
8
|
+
def __init__(self):
|
9
|
+
super().__init__(f"custom_id not found !")
|
10
|
+
|
11
|
+
class CoroutineError(Py_cordEasyModifiedViews):
|
12
|
+
def __init__(self, coro):
|
13
|
+
super().__init__(f"{coro} is not a coroutine !")
|
@@ -5,7 +5,7 @@ with open("README.md", encoding='utf-8') as file:
|
|
5
5
|
|
6
6
|
setup(
|
7
7
|
name="PycordViews",
|
8
|
-
version="1.2.
|
8
|
+
version="1.2.6",
|
9
9
|
url="https://github.com/BOXERRMD/Py-cord_Views",
|
10
10
|
author="Chronos (alias BOXERRMD)",
|
11
11
|
author_email="vagabonwalybi@gmail.com",
|
@@ -27,6 +27,6 @@ setup(
|
|
27
27
|
install_requires=[
|
28
28
|
"immutable-Python-type"
|
29
29
|
],
|
30
|
-
packages=['pycordViews', 'pycordViews/pagination', 'pycordViews/views', 'pycordViews/menu', 'pycordViews/multibot'],
|
30
|
+
packages=['pycordViews', 'pycordViews/pagination', 'pycordViews/views', 'pycordViews/menu', 'pycordViews/multibot', 'pycordViews/kit'],
|
31
31
|
python_requires='>=3.9'
|
32
32
|
)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|