Skip to content

Commit

Permalink
feat: add view object comparison to prevent unnecessary re-renders
Browse files Browse the repository at this point in the history
  • Loading branch information
sushichan044 committed Nov 10, 2024
1 parent 78e6c83 commit 82dc99d
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 2 deletions.
16 changes: 14 additions & 2 deletions src/ductile/controller/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@
debounce,
wait_tasks_by_name,
)
from ..view import ( # noqa: TID252
ViewObject,
)

if TYPE_CHECKING:
from collections.abc import Awaitable, Callable, Generator

from discord import Message

from ..view import View, ViewObject # noqa: TID252
from ..view import View # noqa: TID252
from .type import ViewObjectDictWithAttachment, ViewObjectDictWithFiles


Expand Down Expand Up @@ -44,6 +47,9 @@ def __init__(self, view: "View", *, timeout: float | None = 180, sync_interval:
self.__sync_fn = self.__create_sync_function(sync_interval=sync_interval)
self.__loop = asyncio.get_event_loop()

# store latest view object to compare with upcoming view object
self.__view_object = ViewObject()

@property
def message(self) -> "Message | None":
"""
Expand Down Expand Up @@ -105,6 +111,12 @@ async def __sync_immediately(self) -> None:
if self.message is None:
return

# Do not re-render if the view is not changed
if self.__view_object.equals(upcoming := self.__view.render()):
return

self.__view_object = upcoming

# maybe validation for self.__view is needed
d = self._process_view_for_discord("attachment")
await self.message.edit(**d)
Expand Down Expand Up @@ -173,7 +185,7 @@ def _process_view_for_discord(
This can be passed to `discord.abc.Messageable.send` or `discord.abc.Messageable.edit` and etc
as unpacked keyword arguments.
"""
view_object: ViewObject = self.__view.render()
view_object = self.__view_object

# implicitly clear view every time see:#54
v = self.__raw_view
Expand Down
41 changes: 41 additions & 0 deletions src/ductile/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,47 @@ class ViewObject(BaseModel):

model_config = {"arbitrary_types_allowed": True}

def equals(self, other: "ViewObject") -> bool:
if self.content != other.content:
return False

if self._equals_embeds(other.embeds) is False:
return False

if self._equals_components(other.components) is False:
return False

# Comparing content of File is not easy, so just compare Nullity
return self.files is None and other.files is None

def _equals_embeds(self, other: "list[Embed] | None") -> bool:
if self.embeds is None and other is None:
return True

# One of them is None, so they are not equal
if self.embeds is None or other is None:
return False

if len(self.embeds) != len(other):
return False

return all(self.embeds[i] == other[i] for i in range(len(self.embeds)))

def _equals_components(self, other: "list[ui.Item] | None") -> bool:
if self.components is None and other is None:
return True

# One of them is None, so they are not equal
if self.components is None or other is None:
return False

if len(self.components) != len(other):
return False

return all(
self.components[i].to_component_dict() == other[i].to_component_dict() for i in range(len(self.components))
)


class View:
"""
Expand Down

0 comments on commit 82dc99d

Please sign in to comment.