Basically this is just a commit to save progress in case I need to reset to this point. Things are mostly working, but I found a serious UX problem that requires a lot of changes to the infrastructure.

This commit is contained in:
Storm Dragon
2025-11-11 12:38:46 -05:00
parent 87ac31fafe
commit 3434342f22

216
src/ui/channel_manager.py Normal file
View File

@@ -0,0 +1,216 @@
"""
Channel management dialog - manage autojoin channels for a server
"""
import logging
from PySide6.QtWidgets import (
QDialog, QVBoxLayout, QHBoxLayout, QTableWidget, QTableWidgetItem,
QPushButton, QLabel, QHeaderView, QMessageBox
)
from PySide6.QtCore import Qt
from PySide6.QtGui import QKeyEvent
logger = logging.getLogger(__name__)
class ChannelManagerDialog(QDialog):
"""Dialog to manage channels for a server."""
def __init__(self, parent, config_manager, server_config, irc_client=None):
"""
Initialize channel manager dialog.
Args:
parent: Parent window
config_manager: ConfigManager instance
server_config: ServerConfig for the server
irc_client: Optional IRCClient instance for joining channels
"""
super().__init__(parent)
self.config_manager = config_manager
self.server_config = server_config
self.irc_client = irc_client
self.setWindowTitle(f"Manage Channels - {server_config.name}")
self.resize(600, 400)
self.setup_ui()
self.load_channels()
def setup_ui(self):
"""Set up the user interface."""
layout = QVBoxLayout()
self.setLayout(layout)
# Info label
info_label = QLabel(f"Channels for {self.server_config.name}")
info_label.setAccessibleName(f"Channels for {self.server_config.name}")
layout.addWidget(info_label)
# Table widget
self.table = QTableWidget()
self.table.setAccessibleName("Channel list table")
self.table.setColumnCount(2)
self.table.setHorizontalHeaderLabels(["Autojoin", "Channel"])
# Make first column narrow for checkbox
header = self.table.horizontalHeader()
header.setSectionResizeMode(0, QHeaderView.ResizeToContents)
header.setSectionResizeMode(1, QHeaderView.Stretch)
# Enable keyboard navigation
self.table.setFocusPolicy(Qt.StrongFocus)
self.table.setSelectionBehavior(QTableWidget.SelectRows)
self.table.setSelectionMode(QTableWidget.SingleSelection)
# Connect signals
self.table.itemActivated.connect(self.on_item_activated)
self.table.itemChanged.connect(self.on_item_changed)
layout.addWidget(self.table)
# Buttons
button_layout = QHBoxLayout()
join_button = QPushButton("Join Channel")
join_button.setAccessibleName("Join selected channel")
join_button.clicked.connect(self.on_join_clicked)
button_layout.addWidget(join_button)
remove_button = QPushButton("Remove Channel")
remove_button.setAccessibleName("Remove selected channel from list")
remove_button.clicked.connect(self.on_remove_clicked)
button_layout.addWidget(remove_button)
button_layout.addStretch()
close_button = QPushButton("Close")
close_button.setAccessibleName("Close dialog")
close_button.clicked.connect(self.accept)
button_layout.addWidget(close_button)
layout.addLayout(button_layout)
def load_channels(self):
"""Load channels from config into table."""
self.table.setRowCount(0)
self.table.blockSignals(True) # Prevent itemChanged from firing during load
for channel_data in self.server_config.known_channels:
channel_name = channel_data.get('name', '')
autojoin = channel_data.get('autojoin', False)
if channel_name:
self.add_channel_row(channel_name, autojoin)
self.table.blockSignals(False)
logger.info(f"Loaded {self.table.rowCount()} channels")
def add_channel_row(self, channel_name, autojoin):
"""Add a channel row to the table."""
row = self.table.rowCount()
self.table.insertRow(row)
# Autojoin checkbox
checkbox_item = QTableWidgetItem()
checkbox_item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsSelectable)
checkbox_item.setCheckState(Qt.Checked if autojoin else Qt.Unchecked)
checkbox_item.setData(Qt.UserRole, channel_name) # Store channel name
# Add accessible text for screen readers
checkbox_item.setText("Checked" if autojoin else "Unchecked")
self.table.setItem(row, 0, checkbox_item)
# Channel name
name_item = QTableWidgetItem(channel_name)
name_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
name_item.setData(Qt.UserRole, channel_name)
self.table.setItem(row, 1, name_item)
def on_item_changed(self, item):
"""Handle checkbox state change."""
if item.column() != 0: # Only handle autojoin column
return
channel_name = item.data(Qt.UserRole)
new_state = item.checkState() == Qt.Checked
logger.info(f"Autojoin changed for {channel_name}: {new_state}")
# Update config
self.config_manager.set_channel_autojoin(
self.server_config.name,
channel_name,
new_state
)
# Update text for screen readers
item.setText("Checked" if new_state else "Unchecked")
def on_item_activated(self, item):
"""Handle Enter key or double-click on item."""
# Get channel name from the row
channel_name = self.table.item(item.row(), 1).data(Qt.UserRole)
logger.info(f"Item activated: {channel_name}")
# Join the channel if IRC client is available
if self.irc_client:
self.join_channel(channel_name)
def on_join_clicked(self):
"""Handle Join button click."""
current_row = self.table.currentRow()
if current_row < 0:
QMessageBox.warning(self, "No Selection", "Please select a channel to join.")
return
channel_name = self.table.item(current_row, 1).data(Qt.UserRole)
self.join_channel(channel_name)
def join_channel(self, channel_name):
"""Join a channel."""
if not self.irc_client:
QMessageBox.warning(
self,
"Not Connected",
"Cannot join channel - not connected to server."
)
return
logger.info(f"Joining channel: {channel_name}")
self.irc_client.send_raw(f"JOIN {channel_name}")
# Close dialog after joining
self.accept()
def on_remove_clicked(self):
"""Handle Remove button click."""
current_row = self.table.currentRow()
if current_row < 0:
QMessageBox.warning(self, "No Selection", "Please select a channel to remove.")
return
channel_name = self.table.item(current_row, 1).data(Qt.UserRole)
reply = QMessageBox.question(
self,
"Remove Channel",
f"Remove {channel_name} from the channel list?",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No
)
if reply == QMessageBox.Yes:
self.config_manager.remove_channel_from_server(
self.server_config.name,
channel_name
)
self.table.removeRow(current_row)
logger.info(f"Removed channel: {channel_name}")
def keyPressEvent(self, event: QKeyEvent):
"""Handle key press events."""
if event.key() == Qt.Key_Escape:
logger.info("Escape pressed, closing dialog")
self.accept()
else:
super().keyPressEvent(event)