Skip to content

Commit

Permalink
Unify clients
Browse files Browse the repository at this point in the history
  • Loading branch information
hypergonial committed Jan 14, 2024
1 parent 66b9471 commit 1f5daf8
Show file tree
Hide file tree
Showing 44 changed files with 1,191 additions and 1,565 deletions.
44 changes: 22 additions & 22 deletions docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ This is what a basic component menu looks like with miru:
import miru

# Define a new custom View that contains 3 items
class BasicView(miru.View[miru.GW]):
class BasicView(miru.View):

# Define a new TextSelect menu with two options
@miru.text_select(
Expand All @@ -55,26 +55,26 @@ This is what a basic component menu looks like with miru:
miru.SelectOption(label="Option 2"),
],
)
async def basic_select(self, select: miru.TextSelect[miru.GW], ctx: miru.ViewContext[miru.GW]) -> None:
async def basic_select(self, select: miru.TextSelect, ctx: miru.ViewContext) -> None:
await ctx.respond(f"You've chosen {select.values[0]}!")

# Define a new Button with the Style of success (Green)
@miru.button(label="Click me!", style=hikari.ButtonStyle.SUCCESS)
async def basic_button(self, button: miru.Button[miru.GW], ctx: miru.ViewContext[miru.GW]) -> None:
async def basic_button(self, button: miru.Button, ctx: miru.ViewContext) -> None:
await ctx.respond("You clicked me!")

# Define a new Button that when pressed will stop the view
# & invalidate all the buttons in this view
@miru.button(label="Stop me!", style=hikari.ButtonStyle.DANGER)
async def stop_button(self, button: miru.Button[miru.GW], ctx: miru.ViewContext[miru.GW]) -> None:
async def stop_button(self, button: miru.Button, ctx: miru.ViewContext) -> None:
self.stop() # Called to stop the view


# Create an instance of our bot. miru supports
# both 'hikari.GatewayBot' and 'hikari.RESTBot'.
# You can swap at the top to see an example with RESTBot instead.
bot = hikari.GatewayBot("YOUR_TOKEN_HERE")
client = miru.GatewayClient(bot)
client = miru.Client(bot)
```

=== "REST"
Expand All @@ -84,7 +84,7 @@ This is what a basic component menu looks like with miru:
import miru

# Define a new custom View that contains 3 items
class BasicView(miru.View[miru.REST]):
class BasicView(miru.View):

# Define a new TextSelect menu with two options
@miru.text_select(
Expand All @@ -94,26 +94,26 @@ This is what a basic component menu looks like with miru:
miru.SelectOption(label="Option 2"),
],
)
async def basic_select(self, select: miru.TextSelect[miru.REST], ctx: miru.ViewContext[miru.REST]) -> None:
async def basic_select(self, select: miru.TextSelect, ctx: miru.ViewContext) -> None:
await ctx.respond(f"You've chosen {select.values[0]}!")

# Define a new Button with the Style of success (Green)
@miru.button(label="Click me!", style=hikari.ButtonStyle.SUCCESS)
async def basic_button(self, button: miru.Button[miru.REST], ctx: miru.ViewContext[miru.REST]) -> None:
async def basic_button(self, button: miru.Button, ctx: miru.ViewContext) -> None:
await ctx.respond("You clicked me!")

# Define a new Button that when pressed will stop the view
# & invalidate all the buttons in this view
@miru.button(label="Stop me!", style=hikari.ButtonStyle.DANGER)
async def stop_button(self, button: miru.Button[miru.REST], ctx: miru.ViewContext[miru.REST]) -> None:
async def stop_button(self, button: miru.Button, ctx: miru.ViewContext) -> None:
self.stop() # Called to stop the view


# Create an instance of our bot. miru supports
# both 'hikari.GatewayBot' and 'hikari.RESTBot'.
# You can swap at the top to see an example with RESTBot instead.
bot = hikari.RESTBot("YOUR_TOKEN_HERE")
client = miru.RESTClient(bot)
client = miru.Client(bot)
```

Next up, we need to send our view. `miru` has support for all popular command handlers, and naturally can be used with only hikari as well.
Expand Down Expand Up @@ -226,14 +226,14 @@ Below you can see such an example:
import hikari
import miru

class YesButton(miru.Button[miru.GW]):
class YesButton(miru.Button):
def __init__(self) -> None:
# Initialize our button with some pre-defined properties
super().__init__(style=hikari.ButtonStyle.SUCCESS, label="Yes")

# The callback is the function that gets called when the button is pressed
# If you are subclassing, you must use the name "callback" when defining it.
async def callback(self, ctx: miru.ViewContext[miru.GW]) -> None:
async def callback(self, ctx: miru.ViewContext) -> None:
# You can specify the ephemeral message flag
# to make your response ephemeral
await ctx.respond(
Expand All @@ -246,12 +246,12 @@ Below you can see such an example:
self.view.stop()


class NoButton(miru.Button[miru.GW]):
class NoButton(miru.Button):
# Let's leave our arguments dynamic this time, instead of hard-coding them
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)

async def callback(self, ctx: miru.ViewContext[miru.GW]) -> None:
async def callback(self, ctx: miru.ViewContext) -> None:
await ctx.respond(
"This is the only correct answer.",
flags=hikari.MessageFlag.EPHEMERAL
Expand All @@ -260,13 +260,13 @@ Below you can see such an example:
self.view.stop()


class PineappleView(miru.View[miru.GW]):
class PineappleView(miru.View):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.answer = None

bot = hikari.GatewayBot("YOUR_TOKEN_HERE")
client = miru.GatewayClient(bot)
client = miru.Client(bot)
```

=== "REST"
Expand All @@ -275,14 +275,14 @@ Below you can see such an example:
import hikari
import miru

class YesButton(miru.Button[miru.REST]):
class YesButton(miru.Button):
def __init__(self) -> None:
# Initialize our button with some pre-defined properties
super().__init__(style=hikari.ButtonStyle.SUCCESS, label="Yes")

# The callback is the function that gets called when the button is pressed
# If you are subclassing, you must use the name "callback" when defining it.
async def callback(self, ctx: miru.ViewContext[miru.REST]) -> None:
async def callback(self, ctx: miru.ViewContext) -> None:
# You can specify the ephemeral message flag
# to make your response ephemeral
await ctx.respond(
Expand All @@ -295,12 +295,12 @@ Below you can see such an example:
self.view.stop()


class NoButton(miru.Button[miru.REST]):
class NoButton(miru.Button):
# Let's leave our arguments dynamic this time, instead of hard-coding them
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)

async def callback(self, ctx: miru.ViewContext[miru.REST]) -> None:
async def callback(self, ctx: miru.ViewContext) -> None:
await ctx.respond(
"This is the only correct answer.",
flags=hikari.MessageFlag.EPHEMERAL
Expand All @@ -309,13 +309,13 @@ Below you can see such an example:
self.view.stop()


class PineappleView(miru.View[miru.REST]):
class PineappleView(miru.View):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.answer = None

bot = hikari.RESTBot("YOUR_TOKEN_HERE")
client = miru.RESTClient(bot)
client = miru.Client(bot)
```

Then we can adjust our sending logic from the previous example like so:
Expand Down
93 changes: 25 additions & 68 deletions docs/guides/checks_timeout.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,89 +18,46 @@ Views provide a way to implement this via the [`View.view_check()`][miru.view.Vi
This object receives [`ViewContext`][miru.context.view.ViewContext] as it's only argument, and if it
does not evaluate to a truthy value, the interaction will be ignored.

=== "Gateway"
```py
class ChecksView(miru.View):

```py
class ChecksView(miru.View[miru.GW]):
@miru.button(label="Click me!", style=hikari.ButtonStyle.SUCCESS)
async def basic_button(self, button: miru.Button, ctx: miru.ViewContext) -> None:
await ctx.respond("You clicked me!")

@miru.button(label="Click me!", style=hikari.ButtonStyle.SUCCESS)
async def basic_button(self, button: miru.Button[miru.GW], ctx: miru.ViewContext[miru.GW]) -> None:
await ctx.respond("You clicked me!")
# Define a custom view check
async def view_check(self, ctx: miru.ViewContext) -> bool:
# This view will only handle interactions that belong to this user
# For every other user, we show them an error
if ctx.user.id != 123456789:
await ctx.respond("You cannot press this!")
return False

# Define a custom view check
async def view_check(self, ctx: miru.ViewContext[miru.GW]) -> bool:
# This view will only handle interactions that belong to this user
# For every other user, we show them an error
if ctx.user.id != 123456789:
await ctx.respond("You cannot press this!")
return False

return True
```

=== "REST"

```py
class ChecksView(miru.View[miru.REST]):

@miru.button(label="Click me!", style=hikari.ButtonStyle.SUCCESS)
async def basic_button(self, button: miru.Button[miru.REST], ctx: miru.ViewContext[miru.REST]) -> None:
await ctx.respond("You clicked me!")

# Define a custom view check
async def view_check(self, ctx: miru.ViewContext[miru.REST]) -> bool:
# This view will only handle interactions that belong to this user
# For every other user, we show them an error
if ctx.user.id != 123456789:
await ctx.respond("You cannot press this!")
return False

return True
```
return True
```

## Timeout

By default, views time out after 120 seconds of inactivity. This can be controlled via the `timeout=`
keyword argument passed to views. To execute code when the view times out, you can override the
[`View.on_timeout()`][miru.abc.item_handler.ItemHandler.on_timeout] method. This function receives no arguments.

=== "Gateway"

```py
class TimeoutView(miru.View[miru.GW]):

@miru.button(label="Click me!", style=hikari.ButtonStyle.SUCCESS)
async def basic_button(self, button: miru.Button[miru.GW], ctx: miru.ViewContext[miru.GW]) -> None:
await ctx.respond("You clicked me!")

async def on_timeout(self) -> None:
print("This view timed out!")
# Run custom logic here


# Somewhere else in code:

view = TimeoutView(timeout=10.0)
```

=== "REST"

```py
class TimeoutView(miru.View[miru.REST]):
```py
class TimeoutView(miru.View):

@miru.button(label="Click me!", style=hikari.ButtonStyle.SUCCESS)
async def basic_button(self, button: miru.Button[miru.REST], ctx: miru.ViewContext[miru.REST]) -> None:
await ctx.respond("You clicked me!")
@miru.button(label="Click me!", style=hikari.ButtonStyle.SUCCESS)
async def basic_button(self, button: miru.Button, ctx: miru.ViewContext) -> None:
await ctx.respond("You clicked me!")

async def on_timeout(self) -> None:
print("This view timed out!")
# Run custom logic here
async def on_timeout(self) -> None:
print("This view timed out!")
# Run custom logic here


# Somewhere else in code:
# Somewhere else in code:

view = TimeoutView(timeout=10.0)
```
view = TimeoutView(timeout=10.0)
```

!!! note
Note that if you manually call [`View.stop()`][miru.abc.item_handler.ItemHandler.stop], [`View.on_timeout()`][miru.abc.item_handler.ItemHandler.on_timeout] will not be called.
85 changes: 27 additions & 58 deletions docs/guides/editing_items.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,64 +15,33 @@ Additionally, view items can be queried using [`View.get_item_by`][miru.abc.item
[`View.get_item_by_id`][miru.abc.item_handler.ItemHandler.get_item_by_id]. Editing a specific item is as simple as changing the desired properties,
then editing the message with the updated view.

Example:
--------

=== "Gateway"

```py
import hikari
import miru

class EditView(miru.View[miru.GW]):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.counter = 0

@miru.button(label="Counter: 0", style=hikari.ButtonStyle.PRIMARY)
async def counter_button(self, button: miru.Button[miru.GW], ctx: miru.ViewContext[miru.GW]) -> None:
self.counter += 1
# Change the property we want to edit
button.label = f"Counter: {self.counter}"
# Re-send the view components
await ctx.edit_response(components=self)

@miru.button(label="Disable Menu", style=hikari.ButtonStyle.DANGER)
async def disable_button(self, button: miru.Button[miru.GW], ctx: miru.ViewContext[miru.GW]) -> None:
# Disable all items attached to the view
for item in self.children:
item.disabled = True
await ctx.edit_response(components=self)
self.stop()
```

=== "REST"

```py
import hikari
import miru

class EditView(miru.View[miru.REST]):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.counter = 0

@miru.button(label="Counter: 0", style=hikari.ButtonStyle.PRIMARY)
async def counter_button(self, button: miru.Button[miru.REST], ctx: miru.ViewContext[miru.REST]) -> None:
self.counter += 1
# Change the property we want to edit
button.label = f"Counter: {self.counter}"
# Re-send the view components
await ctx.edit_response(components=self)

@miru.button(label="Disable Menu", style=hikari.ButtonStyle.DANGER)
async def disable_button(self, button: miru.Button[miru.REST], ctx: miru.ViewContext[miru.REST]) -> None:
# Disable all items attached to the view
for item in self.children:
item.disabled = True
await ctx.edit_response(components=self)
self.stop()
```
## Example

```py
import hikari
import miru

class EditView(miru.View):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.counter = 0

@miru.button(label="Counter: 0", style=hikari.ButtonStyle.PRIMARY)
async def counter_button(self, button: miru.Button, ctx: miru.ViewContext) -> None:
self.counter += 1
# Change the property we want to edit
button.label = f"Counter: {self.counter}"
# Re-send the view components
await ctx.edit_response(components=self)

@miru.button(label="Disable Menu", style=hikari.ButtonStyle.DANGER)
async def disable_button(self, button: miru.Button, ctx: miru.ViewContext) -> None:
# Disable all items attached to the view
for item in self.children:
item.disabled = True
await ctx.edit_response(components=self)
self.stop()
```

Using the above view code should generate a button, that when clicked, increments it's counter shown on the label.
The second button iterates through all items attached to the view and disables them, then stops the view.
Loading

0 comments on commit 1f5daf8

Please sign in to comment.