diff --git a/shop/shop.py b/shop/shop.py index 4917706..7d3aa40 100644 --- a/shop/shop.py +++ b/shop/shop.py @@ -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() diff --git a/shop/ui.py b/shop/ui.py index 399fb85..dc83842 100644 --- a/shop/ui.py +++ b/shop/ui.py @@ -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() \ No newline at end of file + 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) \ No newline at end of file