diff --git a/cloud_sync/ui_qt.py b/cloud_sync/ui_qt.py index d4aea86..d12d5c8 100644 --- a/cloud_sync/ui_qt.py +++ b/cloud_sync/ui_qt.py @@ -85,8 +85,58 @@ def _apply_prism_dark(app: Any) -> None: app.setPalette(p) +_PROGRESS_QSS = """ +QDialog { background: #313131; } +QLabel#title { + color: white; + font-size: 18pt; + font-weight: bold; + letter-spacing: 2px; +} +QLabel#badge { + color: #313131; + background: #96db59; + border-radius: 16px; + font-size: 18pt; + font-weight: bold; + qproperty-alignment: AlignCenter; + min-width: 32px; + max-width: 32px; + min-height: 32px; + max-height: 32px; +} +QLabel#status { + color: #c8c8c8; + font-size: 10pt; +} +QProgressBar { + background: #222222; + border: 1px solid #3a3a3a; + border-radius: 3px; + height: 14px; +} +QProgressBar::chunk { + background: #96db59; + border-radius: 2px; +} +QPushButton#secondary { + background: #303030; + color: white; + border: 1px solid #4a4a4a; + border-radius: 2px; + padding: 8px 20px; + font-size: 10pt; +} +QPushButton#secondary:hover { background: #3a3a3a; border-color: #96db59; } +QPushButton#secondary:pressed { background: #222222; } +QPushButton#secondary:disabled { color: #777; border-color: #2a2a2a; } +""" + + class QtProgressWindow: - """Modal Qt dialog: title + status + indeterminate progress + Cancel.""" + """Modal Qt dialog: header badge + uppercase title + status + bar + Cancel. + + Matches the conflict + login dialog skeleton in Prism dark.""" def __init__(self) -> None: QtWidgets, QtCore, Signal = import_qt() @@ -106,35 +156,45 @@ class QtProgressWindow: self._dialog = QtWidgets.QDialog() self._dialog.setWindowTitle("Cloud sync") - self._dialog.setFixedSize(440, 160) - # Block ESC + window close X → mark cancelled, don't accept + self._dialog.setFixedSize(520, 240) + self._dialog.setStyleSheet(_PROGRESS_QSS) self._dialog.setWindowFlag( QtCore.Qt.WindowType.WindowContextHelpButtonHint, False ) - layout = QtWidgets.QVBoxLayout(self._dialog) - layout.setContentsMargins(20, 20, 20, 20) + outer = QtWidgets.QVBoxLayout(self._dialog) + outer.setContentsMargins(28, 24, 28, 20) + outer.setSpacing(14) - self._title_label = QtWidgets.QLabel("Working…") - font = self._title_label.font() - font.setBold(True) - font.setPointSize(font.pointSize() + 1) - self._title_label.setFont(font) - layout.addWidget(self._title_label) + header = QtWidgets.QHBoxLayout() + header.setSpacing(12) + badge = QtWidgets.QLabel("↻") + badge.setObjectName("badge") + header.addWidget(badge) + self._title_label = QtWidgets.QLabel("CLOUD SYNC") + self._title_label.setObjectName("title") + header.addWidget(self._title_label) + header.addStretch(1) + outer.addLayout(header) self._status_label = QtWidgets.QLabel("Starting…") - layout.addWidget(self._status_label) + self._status_label.setObjectName("status") + self._status_label.setWordWrap(True) + outer.addWidget(self._status_label) + + outer.addStretch(1) self._bar = QtWidgets.QProgressBar() self._bar.setRange(0, 0) # indeterminate self._bar.setTextVisible(False) - layout.addWidget(self._bar) + outer.addWidget(self._bar) - button_row = QtWidgets.QHBoxLayout() - button_row.addStretch(1) + foot = QtWidgets.QHBoxLayout() + foot.addStretch(1) self._cancel_btn = QtWidgets.QPushButton("Cancel") - button_row.addWidget(self._cancel_btn) - layout.addLayout(button_row) + self._cancel_btn.setObjectName("secondary") + foot.addWidget(self._cancel_btn) + outer.addLayout(foot) self._bridge = _Bridge() self._bridge.status_changed.connect(self._status_label.setText) @@ -155,7 +215,7 @@ class QtProgressWindow: return self._cancelled def run_with(self, worker: Callable[[], int], title: str) -> int: - self._title_label.setText(title) + self._title_label.setText(title.upper()) self._status_label.setText("Starting…") def thread_target() -> None: