Refactor Shop and UI components to improve timeout handling for interactive views. Update timeout duration to 3 minutes and implement message replies for user feedback upon timeout in ShopView, PurchaseView, and InventoryView.
Some checks are pending
Run pre-commit / Run pre-commit (push) Waiting to run

This commit is contained in:
Valerie 2025-05-25 23:58:22 -04:00
parent 3ee6707cc5
commit 85de2c70c1
2 changed files with 38 additions and 16 deletions

View file

@ -129,14 +129,14 @@ class Shop(commands.Cog):
color=discord.Color.blue()
)
view = InventoryView(ctx, inventory)
await ctx.send(embed=embed, view=view)
view.message = await ctx.send(embed=embed, view=view)
try:
await view.wait()
if view.selected_item: # An item was selected to use
await self.pending_prompt(ctx, instance, inventory, view.selected_item)
except asyncio.TimeoutError:
await ctx.send("Inventory view timed out.", ephemeral=True)
pass # Handled by view's on_timeout
async def inv_hook(self, user):
"""Inventory Hook for outside cogs
@ -244,7 +244,7 @@ class Shop(commands.Cog):
view = PurchaseView(ctx, shop, item, item_data)
embed = view.build_embed()
await ctx.send(embed=embed, view=view)
view.message = await ctx.send(embed=embed, view=view)
try:
await view.wait()
@ -253,7 +253,7 @@ class Shop(commands.Cog):
sm = ShopManager(ctx, instance, user_data)
await sm.order(shop, item, view.quantity)
except asyncio.TimeoutError:
await ctx.send("Purchase menu timed out.", ephemeral=True)
pass # Handled by view's on_timeout
else:
# Open interactive shop menu
@ -263,7 +263,7 @@ class Shop(commands.Cog):
color=discord.Color.blue()
)
view = ShopView(ctx, shops)
await ctx.send(embed=embed, view=view)
view.message = await ctx.send(embed=embed, view=view)
try:
await view.wait()
@ -272,7 +272,7 @@ class Shop(commands.Cog):
sm = ShopManager(ctx, instance, user_data)
await sm.order(view.current_shop, view.current_item, view.quantity)
except asyncio.TimeoutError:
await ctx.send("Shop menu timed out.", ephemeral=True)
pass # Handled by view's on_timeout
@commands.max_concurrency(1, commands.BucketType.user)
@shop.command()

View file

@ -4,15 +4,15 @@ from typing import Optional, List, Dict, Any
from redbot.core.utils.chat_formatting import box, humanize_list
class ShopView(View):
def __init__(self, ctx, shops: Dict[str, Any], timeout: int = 60):
def __init__(self, ctx, shops: Dict[str, Any], timeout: int = 180): # 3 minutes timeout
super().__init__(timeout=timeout)
self.ctx = ctx
self.shops = shops
self.current_shop = None
self.current_item = None
self.quantity = None
self.message = None # Store message for timeout handling
self.setup_shop_select()
# Add cancel button to a different row
cancel_button = Button(label="Cancel", style=discord.ButtonStyle.red, custom_id="cancel", row=4)
cancel_button.callback = self.cancel
self.add_item(cancel_button)
@ -104,14 +104,20 @@ class ShopView(View):
self.quantity = purchase_view.quantity # Store the quantity from purchase view
self.stop() # Stop the shop view since we're done
async def on_timeout(self) -> None:
if self.message:
await self.message.reply("Shop menu timed out after 3 minutes of inactivity.", mention_author=True)
await self.message.edit(view=None)
class PurchaseView(View):
def __init__(self, ctx, shop: str, item: str, item_data: Dict[str, Any], timeout: int = 60):
def __init__(self, ctx, shop: str, item: str, item_data: Dict[str, Any], timeout: int = 180): # 3 minutes timeout
super().__init__(timeout=timeout)
self.ctx = ctx
self.shop = shop
self.item = item
self.item_data = item_data
self.quantity = None
self.message = None # Store message for timeout handling
# Add buttons with explicit row assignments
buy_one = Button(label="Buy 1", style=discord.ButtonStyle.green, row=1)
@ -162,7 +168,7 @@ class PurchaseView(View):
await self.handle_purchase(interaction)
@button(label="Custom Amount", style=discord.ButtonStyle.blurple, row=1)
async def custom_amount(self, interaction: discord.Interaction, button: Button):
async def custom_amount(self, interaction: discord.Interaction):
embed = discord.Embed(
title="Custom Purchase Amount",
description="How many would you like to buy? Type a number in chat.",
@ -178,11 +184,11 @@ class PurchaseView(View):
)
try:
msg = await self.ctx.bot.wait_for("message", timeout=30.0, check=check)
msg = await self.ctx.bot.wait_for("message", timeout=60.0, check=check) # 1 minute to type amount
self.quantity = int(msg.content)
await self.handle_purchase(interaction)
except asyncio.TimeoutError:
await interaction.followup.send("Purchase cancelled - took too long to respond.", ephemeral=True)
await interaction.message.reply("Custom amount entry timed out after 1 minute.", mention_author=True)
self.stop()
@button(label="Cancel", style=discord.ButtonStyle.red, row=1)
@ -227,14 +233,19 @@ class PurchaseView(View):
self.stop()
await interaction.response.edit_message(embed=embed, view=None)
async def on_timeout(self) -> None:
if self.message:
await self.message.reply("Purchase menu timed out after 3 minutes of inactivity.", mention_author=True)
await self.message.edit(view=None)
class InventoryView(View):
def __init__(self, ctx, inventory: Dict[str, Any], timeout: int = 60):
def __init__(self, ctx, inventory: Dict[str, Any], timeout: int = 180): # 3 minutes timeout
super().__init__(timeout=timeout)
self.ctx = ctx
self.inventory = inventory
self.selected_item = None
self.message = None # Store message for timeout handling
self.setup_inventory_select()
# Add close button to a different row
close_button = Button(label="Close", style=discord.ButtonStyle.red, custom_id="close", row=4)
close_button.callback = self.close
self.add_item(close_button)
@ -293,13 +304,19 @@ class InventoryView(View):
else:
await interaction.response.edit_message(embed=embed)
async def on_timeout(self) -> None:
if self.message:
await self.message.reply("Inventory menu timed out after 3 minutes of inactivity.", mention_author=True)
await self.message.edit(view=None)
class UseItemView(View):
def __init__(self, ctx, item: str, item_data: Dict[str, Any], timeout: int = 60):
def __init__(self, ctx, item: str, item_data: Dict[str, Any], timeout: int = 180): # 3 minutes timeout
super().__init__(timeout=timeout)
self.ctx = ctx
self.item = item
self.item_data = item_data
self.value = False
self.message = None # Store message for timeout handling
async def interaction_check(self, interaction: discord.Interaction) -> bool:
if interaction.user != self.ctx.author:
@ -322,4 +339,9 @@ class UseItemView(View):
async def cancel(self, interaction: discord.Interaction, button: Button):
self.value = False
await interaction.response.edit_message(content="Cancelled.", embed=None, view=None)
self.stop()
self.stop()
async def on_timeout(self) -> None:
if self.message:
await self.message.reply("Item use menu timed out after 3 minutes of inactivity.", mention_author=True)
await self.message.edit(view=None)