from __future__ import annotations from pathlib import Path from PySide6.QtWidgets import ( QDialog, QDialogButtonBox, QFileDialog, QHBoxLayout, QLabel, QLineEdit, QPushButton, QVBoxLayout, ) from . import strings class KeyPrompt(QDialog): def __init__( self, parent=None, title: str = strings._("key_prompt_enter_key"), message: str = strings._("key_prompt_enter_key"), initial_db_path: str | Path | None = None, show_db_change: bool = False, ): """ Prompt the user for the key required to decrypt the database. Used when opening the app, unlocking the idle locked screen, or when rekeying. If show_db_change is true, also show a QFileDialog allowing to select a database file, else the default from settings is used. """ super().__init__(parent) self.setWindowTitle(title) self._db_path: Path | None = Path(initial_db_path) if initial_db_path else None v = QVBoxLayout(self) v.addWidget(QLabel(message)) # DB chooser self.path_edit: QLineEdit | None = None if show_db_change: path_row = QHBoxLayout() self.path_edit = QLineEdit() if self._db_path is not None: self.path_edit.setText(str(self._db_path)) browse_btn = QPushButton(strings._("select_notebook")) def _browse(): start_dir = str(self._db_path or "") fname, _ = QFileDialog.getOpenFileName( self, strings._("select_notebook"), start_dir, "SQLCipher DB (*.db);;All files (*)", ) if fname: self._db_path = Path(fname) if self.path_edit is not None: self.path_edit.setText(fname) browse_btn.clicked.connect(_browse) path_row.addWidget(self.path_edit, 1) path_row.addWidget(browse_btn) v.addLayout(path_row) # Key entry self.key_entry = QLineEdit() self.key_entry.setEchoMode(QLineEdit.Password) v.addWidget(self.key_entry) toggle = QPushButton(strings._("show")) toggle.setCheckable(True) toggle.toggled.connect( lambda c: self.key_entry.setEchoMode( QLineEdit.Normal if c else QLineEdit.Password ) ) v.addWidget(toggle) bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) bb.accepted.connect(self.accept) bb.rejected.connect(self.reject) v.addWidget(bb) self.key_entry.setFocus() self.resize(500, self.sizeHint().height()) def key(self) -> str: return self.key_entry.text() def db_path(self) -> Path | None: """Return the chosen DB path (or None if unchanged/not shown).""" p = self._db_path if self.path_edit is not None: text = self.path_edit.text().strip() if text: p = Path(text) return p