""" Server connection dialog for adding/editing Navidrome servers """ from PySide6.QtWidgets import ( QDialog, QVBoxLayout, QHBoxLayout, QFormLayout, QLineEdit, QPushButton, QLabel, QMessageBox, QCheckBox ) from PySide6.QtCore import Qt from src.api.client import SubsonicClient, SubsonicError from src.config.settings import Settings class ServerDialog(QDialog): """Dialog for configuring a Navidrome server connection""" def __init__(self, settings: Settings, serverName: str = None, parent=None): """ Initialize the server dialog Args: settings: Application settings instance serverName: Name of existing server to edit (None for new server) parent: Parent widget """ super().__init__(parent) self.settings = settings self.editingServer = serverName self.isNew = serverName is None self.setWindowTitle("Add Server" if self.isNew else "Edit Server") self.setModal(True) self.setMinimumWidth(400) self.setupUi() self.loadExistingData() def setupUi(self): """Setup the dialog UI""" layout = QVBoxLayout(self) # Form layout for inputs formLayout = QFormLayout() # Server name self.nameEdit = QLineEdit() self.nameEdit.setAccessibleName("Server Name") self.nameEdit.setAccessibleDescription("A friendly name for this server") nameLabel = QLabel("&Name:") nameLabel.setBuddy(self.nameEdit) formLayout.addRow(nameLabel, self.nameEdit) # Server URL self.urlEdit = QLineEdit() self.urlEdit.setAccessibleName("Server URL") self.urlEdit.setAccessibleDescription("The full URL to your Navidrome server, for example https://music.example.com") self.urlEdit.setPlaceholderText("https://music.example.com") urlLabel = QLabel("&URL:") urlLabel.setBuddy(self.urlEdit) formLayout.addRow(urlLabel, self.urlEdit) # Username self.usernameEdit = QLineEdit() self.usernameEdit.setAccessibleName("Username") usernameLabel = QLabel("U&sername:") usernameLabel.setBuddy(self.usernameEdit) formLayout.addRow(usernameLabel, self.usernameEdit) # Password self.passwordEdit = QLineEdit() self.passwordEdit.setEchoMode(QLineEdit.Password) self.passwordEdit.setAccessibleName("Password") passwordLabel = QLabel("&Password:") passwordLabel.setBuddy(self.passwordEdit) formLayout.addRow(passwordLabel, self.passwordEdit) # Set as default checkbox self.defaultCheckbox = QCheckBox("Set as &default server") self.defaultCheckbox.setAccessibleName("Set as default server") formLayout.addRow("", self.defaultCheckbox) layout.addLayout(formLayout) # Status label for connection test self.statusLabel = QLabel("") self.statusLabel.setAccessibleName("Connection Status") self.statusLabel.setWordWrap(True) layout.addWidget(self.statusLabel) # Button layout buttonLayout = QHBoxLayout() self.testButton = QPushButton("&Test Connection") self.testButton.setAccessibleName("Test Connection") self.testButton.clicked.connect(self.testConnection) buttonLayout.addWidget(self.testButton) buttonLayout.addStretch() self.cancelButton = QPushButton("&Cancel") self.cancelButton.setAccessibleName("Cancel") self.cancelButton.clicked.connect(self.reject) buttonLayout.addWidget(self.cancelButton) self.saveButton = QPushButton("&Save") self.saveButton.setAccessibleName("Save") self.saveButton.setDefault(True) self.saveButton.clicked.connect(self.saveServer) buttonLayout.addWidget(self.saveButton) layout.addLayout(buttonLayout) # Set initial focus self.nameEdit.setFocus() def loadExistingData(self): """Load existing server data if editing""" if not self.isNew and self.editingServer: server = self.settings.getServer(self.editingServer) if server: self.nameEdit.setText(self.editingServer) self.nameEdit.setReadOnly(True) # Can't change name when editing self.urlEdit.setText(server.get('url', '')) self.usernameEdit.setText(server.get('username', '')) self.passwordEdit.setText(server.get('password', '')) # Check if this is the default server defaultServer = self.settings.getDefaultServer() self.defaultCheckbox.setChecked(defaultServer == self.editingServer) def testConnection(self): """Test connection to the server""" url = self.urlEdit.text().strip() username = self.usernameEdit.text().strip() password = self.passwordEdit.text() if not url or not username or not password: self.statusLabel.setText("Please fill in all fields") return self.statusLabel.setText("Testing connection...") self.testButton.setEnabled(False) try: client = SubsonicClient(url, username, password) if client.ping(): self.statusLabel.setText("Connection successful!") else: self.statusLabel.setText("Connection failed: Invalid response") except SubsonicError as e: self.statusLabel.setText(f"Connection failed: {e.message}") except Exception as e: self.statusLabel.setText(f"Connection failed: {str(e)}") finally: self.testButton.setEnabled(True) def saveServer(self): """Save the server configuration""" name = self.nameEdit.text().strip() url = self.urlEdit.text().strip() username = self.usernameEdit.text().strip() password = self.passwordEdit.text() # Validate inputs if not name: QMessageBox.warning(self, "Validation Error", "Please enter a server name") self.nameEdit.setFocus() return if not url: QMessageBox.warning(self, "Validation Error", "Please enter the server URL") self.urlEdit.setFocus() return if not username: QMessageBox.warning(self, "Validation Error", "Please enter a username") self.usernameEdit.setFocus() return if not password: QMessageBox.warning(self, "Validation Error", "Please enter a password") self.passwordEdit.setFocus() return # Check for duplicate name when adding new server if self.isNew and self.settings.getServer(name): QMessageBox.warning( self, "Validation Error", f"A server named '{name}' already exists. Please choose a different name." ) self.nameEdit.setFocus() return # Save the server self.settings.addServer(name, url, username, password) # Set as default if checked if self.defaultCheckbox.isChecked(): self.settings.setDefaultServer(name) self.accept() def getServerName(self) -> str: """Get the name of the saved server""" return self.nameEdit.text().strip()