Add comprehensive voice channel system for Discord gameplay with:
## New Features
- `/voice-channel public` - Create public voice channels with random codenames
- `/voice-channel private` - Create private team vs team channels with role permissions
- Automatic cleanup after configurable empty duration (default: 5 minutes)
- Restart-resilient JSON persistence for channel tracking
- Background monitoring service with graceful error handling
## Technical Implementation
- **Voice Commands Package** (`commands/voice/`)
- `channels.py` - Main slash command implementation with modern command groups
- `cleanup_service.py` - Background service for automatic channel deletion
- `tracker.py` - JSON-based persistent channel tracking
- `__init__.py` - Package setup with resilient loading
- **Bot Integration** - Voice cleanup service integrated into bot lifecycle
- **Service Dependencies** - Integration with team, league, and schedule services
- **Permission System** - Team-based Discord role permissions for private channels
## Key Features
- **Public Channels**: Random codenames, open speaking permissions
- **Private Channels**: "{Away} vs {Home}" naming, team role restrictions
- **Auto-cleanup**: Configurable intervals with empty duration thresholds
- **Restart Resilience**: JSON file persistence survives bot restarts
- **Error Handling**: Comprehensive validation and graceful degradation
- **Migration Support**: Deprecated old prefix commands with helpful messages
## Documentation & Testing
- Comprehensive README.md following project patterns
- Full test suite with 15+ test methods covering all scenarios
- Updated CLAUDE.md files with voice command documentation
- Clean IDE diagnostics with proper type safety
## Integration Points
- Team service for user validation and role lookup
- League service for current season/week information
- Schedule service for opponent detection in private channels
- Background task management in bot startup/shutdown
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
|
||
|---|---|---|
| .. | ||
| __init__.py | ||
| base.py | ||
| common.py | ||
| custom_commands.py | ||
| embeds.py | ||
| modals.py | ||
| README.md | ||
| transaction_embed.py | ||
Views Directory
The views directory contains Discord UI components for Discord Bot v2.0, providing consistent visual interfaces and interactive elements. This includes embeds, modals, buttons, select menus, and other Discord UI components.
Architecture
Component-Based UI Design
Views in Discord Bot v2.0 follow these principles:
- Consistent styling via centralized templates
- Reusable components for common UI patterns
- Error handling with graceful degradation
- User interaction tracking and validation
- Accessibility with proper labeling and feedback
Base Components
All view components inherit from Discord.py base classes with enhanced functionality:
- BaseView - Enhanced discord.ui.View with logging and user validation
- BaseModal - Enhanced discord.ui.Modal with error handling
- EmbedTemplate - Centralized embed creation with consistent styling
View Components
Base View System (base.py)
BaseView Class
Foundation for all interactive views:
class BaseView(discord.ui.View):
def __init__(self, timeout=180.0, user_id=None):
super().__init__(timeout=timeout)
self.user_id = user_id
self.logger = get_contextual_logger(f'{__name__}.BaseView')
async def interaction_check(self, interaction) -> bool:
"""Validate user permissions for interaction."""
async def on_timeout(self) -> None:
"""Handle view timeout gracefully."""
async def on_error(self, interaction, error, item) -> None:
"""Handle view errors with user feedback."""
ConfirmationView Class
Standard Yes/No confirmation dialogs:
confirmation = ConfirmationView(
user_id=interaction.user.id,
confirm_callback=handle_confirm,
cancel_callback=handle_cancel
)
await interaction.followup.send("Confirm action?", view=confirmation)
PaginationView Class
Multi-page navigation for large datasets:
pages = [embed1, embed2, embed3]
pagination = PaginationView(
pages=pages,
user_id=interaction.user.id,
show_page_numbers=True
)
await interaction.followup.send(embed=pagination.get_current_embed(), view=pagination)
Embed Templates (embeds.py)
EmbedTemplate Class
Centralized embed creation with consistent styling:
# Success embed
embed = EmbedTemplate.success(
title="Operation Completed",
description="Your request was processed successfully."
)
# Error embed
embed = EmbedTemplate.error(
title="Operation Failed",
description="Please check your input and try again."
)
# Warning embed
embed = EmbedTemplate.warning(
title="Careful!",
description="This action cannot be undone."
)
# Info embed
embed = EmbedTemplate.info(
title="Information",
description="Here's what you need to know."
)
EmbedColors Dataclass
Consistent color scheme across all embeds:
@dataclass(frozen=True)
class EmbedColors:
PRIMARY: int = 0xa6ce39 # SBA green
SUCCESS: int = 0x28a745 # Green
WARNING: int = 0xffc107 # Yellow
ERROR: int = 0xdc3545 # Red
INFO: int = 0x17a2b8 # Blue
SECONDARY: int = 0x6c757d # Gray
Modal Forms (modals.py)
BaseModal Class
Foundation for interactive forms:
class BaseModal(discord.ui.Modal):
def __init__(self, title: str, timeout=300.0):
super().__init__(title=title, timeout=timeout)
self.logger = get_contextual_logger(f'{__name__}.BaseModal')
self.result = None
async def on_submit(self, interaction):
"""Handle form submission."""
async def on_error(self, interaction, error):
"""Handle form errors."""
Usage Pattern
class CustomCommandModal(BaseModal):
def __init__(self):
super().__init__(title="Create Custom Command")
name = discord.ui.TextInput(
label="Command Name",
placeholder="Enter command name...",
required=True,
max_length=50
)
response = discord.ui.TextInput(
label="Response",
placeholder="Enter command response...",
style=discord.TextStyle.paragraph,
required=True,
max_length=2000
)
async def on_submit(self, interaction):
# Process form data
command_data = {
"name": self.name.value,
"response": self.response.value
}
# Handle creation logic
Common UI Elements (common.py)
Shared Components
- Loading indicators for async operations
- Status messages for operation feedback
- Navigation elements for multi-step processes
- Validation displays for form errors
Specialized Views
Custom Commands (custom_commands.py)
Views specific to custom command management:
- Command creation forms
- Command listing with actions
- Bulk management interfaces
Transaction Management (transaction_embed.py)
Views for player transaction interfaces:
- Transaction proposal forms
- Approval/rejection workflows
- Transaction history displays
Styling Guidelines
Embed Consistency
All embeds should use EmbedTemplate methods:
# ✅ Consistent styling
embed = EmbedTemplate.success("Player Added", "Player successfully added to roster")
# ❌ Inconsistent styling
embed = discord.Embed(title="Player Added", color=0x00ff00)
Color Usage
Use the standard color palette:
- PRIMARY (SBA Green) - Default for neutral information
- SUCCESS (Green) - Successful operations
- ERROR (Red) - Errors and failures
- WARNING (Yellow) - Warnings and cautions
- INFO (Blue) - General information
- SECONDARY (Gray) - Less important information
User Feedback
Provide clear feedback for all user interactions:
# Loading state
embed = EmbedTemplate.info("Processing", "Please wait while we process your request...")
# Success state
embed = EmbedTemplate.success("Complete", "Your request has been processed successfully.")
# Error state with helpful information
embed = EmbedTemplate.error(
"Request Failed",
"The player name was not found. Please check your spelling and try again."
)
Interactive Components
Button Patterns
Action Buttons
@discord.ui.button(label="Confirm", style=discord.ButtonStyle.success, emoji="✅")
async def confirm_button(self, interaction, button):
self.increment_interaction_count()
# Handle confirmation
await interaction.response.edit_message(content="Confirmed!", view=None)
Navigation Buttons
@discord.ui.button(emoji="◀️", style=discord.ButtonStyle.primary)
async def previous_page(self, interaction, button):
self.current_page = max(0, self.current_page - 1)
await interaction.response.edit_message(embed=self.get_current_embed(), view=self)
Select Menu Patterns
Option Selection
@discord.ui.select(placeholder="Choose an option...")
async def select_option(self, interaction, select):
selected_value = select.values[0]
# Handle selection
await interaction.response.send_message(f"You selected: {selected_value}")
Dynamic Options
class PlayerSelectMenu(discord.ui.Select):
def __init__(self, players: List[Player]):
options = [
discord.SelectOption(
label=player.name,
value=str(player.id),
description=f"{player.position} - {player.team.abbrev}"
)
for player in players[:25] # Discord limit
]
super().__init__(placeholder="Select a player...", options=options)
Error Handling
View Error Handling
All views implement comprehensive error handling:
async def on_error(self, interaction, error, item):
"""Handle view errors gracefully."""
self.logger.error("View error", error=error, item_type=type(item).__name__)
try:
embed = EmbedTemplate.error(
"Interaction Error",
"Something went wrong. Please try again."
)
if not interaction.response.is_done():
await interaction.response.send_message(embed=embed, ephemeral=True)
else:
await interaction.followup.send(embed=embed, ephemeral=True)
except Exception as e:
self.logger.error("Failed to send error message", error=e)
User Input Validation
Forms validate user input before processing:
async def on_submit(self, interaction):
# Validate input
if len(self.name.value) < 2:
embed = EmbedTemplate.error(
"Invalid Input",
"Command name must be at least 2 characters long."
)
await interaction.response.send_message(embed=embed, ephemeral=True)
return
# Process valid input
await self.create_command(interaction)
Accessibility Features
User-Friendly Labels
- Clear button labels with descriptive text
- Helpful placeholders in form fields
- Descriptive error messages with actionable guidance
- Consistent emoji usage for visual recognition
Permission Validation
Views respect user permissions and provide appropriate feedback:
async def interaction_check(self, interaction) -> bool:
"""Check if user can interact with this view."""
if self.user_id and interaction.user.id != self.user_id:
await interaction.response.send_message(
"❌ You cannot interact with this menu.",
ephemeral=True
)
return False
return True
Performance Considerations
View Lifecycle Management
- Timeout handling prevents orphaned views
- Resource cleanup in view destructors
- Interaction tracking for usage analytics
- Memory management for large datasets
Efficient Updates
# ✅ Efficient - Only update what changed
await interaction.response.edit_message(embed=new_embed, view=self)
# ❌ Inefficient - Sends new message
await interaction.response.send_message(embed=new_embed, view=new_view)
Testing Strategies
View Testing
@pytest.mark.asyncio
async def test_confirmation_view():
view = ConfirmationView(user_id=123)
# Mock interaction
interaction = Mock()
interaction.user.id = 123
# Test button click
await view.confirm_button.callback(interaction)
assert view.result is True
Modal Testing
@pytest.mark.asyncio
async def test_custom_command_modal():
modal = CustomCommandModal()
# Set form values
modal.name.value = "test"
modal.response.value = "Test response"
# Mock interaction
interaction = Mock()
# Test form submission
await modal.on_submit(interaction)
# Verify processing
assert modal.result is not None
Development Guidelines
Creating New Views
- Inherit from base classes for consistency
- Use EmbedTemplate for all embed creation
- Implement proper error handling in all interactions
- Add user permission checks where appropriate
- Include comprehensive logging with context
- Follow timeout patterns to prevent resource leaks
View Composition
- Keep views focused on single responsibilities
- Use composition over complex inheritance
- Separate business logic from UI logic
- Make views testable with dependency injection
UI Guidelines
- Follow Discord design patterns for familiarity
- Use consistent colors from EmbedColors
- Provide clear user feedback for all actions
- Handle edge cases gracefully
- Consider mobile users in layout design
Next Steps for AI Agents:
- Review existing view implementations for patterns
- Understand the Discord UI component system
- Follow the EmbedTemplate system for consistent styling
- Implement proper error handling and user validation
- Test interactive components thoroughly
- Consider accessibility and user experience in design