An Declarative UI Kit for discord.py
Project description
このパッケージはdiscord.uiの拡張です。
なぜdiscord-ext-uiを使うのか?
discord-ext-uiは、SwiftUIに似た宣言的Viewシステム・Combineシステムを搭載しています。
これにより、MVVMなどのアーキテクチャを実装したり、送信した後のボタンの編集が容易になります。
MVVMアーキテクチャを採用する利点
まずMVVMとは、各クラスが公開インスタンス変数を管理することによって、画面状態の管理を安全に行うことのできるModel View ViewModelと呼ばれるアーキテクチャの略称です。
MVVMにおいてコンポーネントの設計はView、ViewModel、Modelにわけられ、それぞれ別の役割を担います。
https://qiita.com/yuutetu/items/ea175b73e1dbbfd355db
詳しくはこちらなどの記事を参考にしてください。
MVVMにより、ロジック部分と画面への描画部分、およびDiscordへの通信部分が分けられるため、ロジックに対するテストが書きやすく、結果として品質の高いコードを維持することができます。
discord-ext-uiを採用する利点
メッセージの更新を明示的に行う必要がなくなる
例として、ボタンを使ってカウントを増やしたり減らしたりできるような機能を実装するとしましょう。
MVVMを用いらずに実装する場合、ボタンの押下時に内部状態が変更された際にその状態を反映してメッセージの更新を行う処理を明示的に記述する必要があります。
対して、discord-ext-uiでは、 state や published といった変数のラッパーを提供します。このラッパーを使用することで、メンバ変数の変更に応じてメッセージの更新を明示的に書く必要がなくなります。
また、ボタンが押されたときに実行される関数を宣言的に設定できるので、forループ等の複雑な処理を行うことも可能です。
ボタンを使った時の処理が書きやすい
discord.py 2.0からボタンの対応が始まりましたが、discord.py標準のボタン対応の仕組みでは、途中でボタンの変更などがし辛いなどの問題があります。
discord-ext-uiを使えば、自動で更新する際にボタンの変更も可能なので、インスタンス変数の値に応じた無効化・有効化や、ペジネーション等の内部状態に応じたボタンの変更処理も簡単に実装することができます。
View
Viewは body という名前のメソッドを実装しなければなりません。 body メソッドはdiscord-ext-uiの Message を返却する必要があります。 ライブラリは body メソッドをメッセージを作成/更新する際に毎回呼び出し、その結果を用いてDiscord APIを呼び出します。 View クラスは start メソッドを持っていて、これにチャンネルを渡すことでメッセージの作成が行われます。
State
stateはViewのプロパティとして振る舞います。 Viewのクラス変数として定義したあと、値を代入してください。
View上のstateを更新するとメッセージの更新が行われます。つまり、ライブラリによって、 body メソッドが呼び出され、その結果を用いてDiscord上のメッセージが更新されます。
ObservedObjectとPublished
これはMVVMに関連した概念です。MVVMを用いないのであればこの節は読まなくても良いかもしれません。 ObservableObject を継承したViewModelをViewのインスタンス変数とすると、 ObservableObjectのpublished propertyにした値が変更されたとき、Viewに変更を通知して、Viewが自動で更新されます。
Example
from discord.ext.ui import Component, Button, View, ObservableObject, published, Message
from discord.ext import commands
import discord
import os
client = discord.Client()
class SampleViewModel(ObservableObject):
num = published('num')
def __init__(self, bot):
super().__init__(bot)
self.num = 0
def countup(self):
self.num += 1
def countdown(self):
self.num -= 1
class SampleView(View):
def __init__(self, bot):
super().__init__(bot)
self.view_model = SampleViewModel(bot)
async def add_reaction(self):
await self.get_message().add_reaction("\U0001f44d")
async def body(self):
return Message(
content=f"test! {self.view_model.num}",
component=Component(items=[
[
Button("+1")
.on_click(lambda x: self.view_model.countup())
.style(discord.ButtonStyle.blurple),
Button("-1")
.on_click(lambda x: self.view_model.countdown())
.style(discord.ButtonStyle.blurple)
]
])
)
@client.event
async def on_message(message):
if message.content != "!test":
return
await SampleView(client).start(message.channel)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Hashes for discord_ext_ui-2.1.1-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 915e210a20a39323bcd1909cef37c214df3d3fe953d141d25804b20ed99d963c |
|
MD5 | 24c496f479bacab540824071f24a7b88 |
|
BLAKE2b-256 | 52193605da29447551b5c4e6718ed26871edbc68d9838dc6e1c3b6a77e30b0aa |