style(ui): login dialog matches Steam-layout in Prism dark
Same skeleton as the conflict dialog: header (Prism-green badge +
uppercase title), body copy, content, foot row.
Specifics:
- badge: '+' on Prism-green circle (vs the conflict's '!' on
light gray) — green reads as 'setup / new', not warning
- command callout: monospace, green text, dark inset card
- token input: monospace, dark inset, green focus border, green
selection highlight
- 'Skip cloud sync' = secondary (dark surface, green hover border)
- 'Save and continue' = primary (Prism-green fill, black text)
Same Enter-to-submit + format validation behavior as before;
on-screen error reuses Prism's BrightText red.
This commit is contained in:
+131
-28
@@ -191,12 +191,94 @@ class QtProgressWindow:
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
_LOGIN_QSS = """
|
||||
QDialog { background: #313131; }
|
||||
QLabel#title {
|
||||
color: white;
|
||||
font-size: 20pt;
|
||||
font-weight: bold;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
QLabel#badge {
|
||||
color: #313131;
|
||||
background: #96db59;
|
||||
border-radius: 16px;
|
||||
font-size: 20pt;
|
||||
font-weight: bold;
|
||||
qproperty-alignment: AlignCenter;
|
||||
min-width: 32px;
|
||||
max-width: 32px;
|
||||
min-height: 32px;
|
||||
max-height: 32px;
|
||||
}
|
||||
QLabel#body {
|
||||
color: #c8c8c8;
|
||||
font-size: 10pt;
|
||||
}
|
||||
QLabel#hint {
|
||||
color: #8a8a8a;
|
||||
font-size: 9pt;
|
||||
}
|
||||
QLabel#error {
|
||||
color: #ff7373;
|
||||
font-size: 9pt;
|
||||
}
|
||||
QLabel#cmd {
|
||||
color: #96db59;
|
||||
background: #222222;
|
||||
border: 1px solid #3a3a3a;
|
||||
border-radius: 3px;
|
||||
padding: 6px 10px;
|
||||
font-family: "JetBrains Mono", "Source Code Pro", Menlo, Consolas, monospace;
|
||||
font-size: 10pt;
|
||||
}
|
||||
QLineEdit#token {
|
||||
background: #222222;
|
||||
border: 1px solid #3a3a3a;
|
||||
border-radius: 3px;
|
||||
padding: 8px 10px;
|
||||
color: white;
|
||||
font-family: "JetBrains Mono", "Source Code Pro", Menlo, Consolas, monospace;
|
||||
font-size: 10pt;
|
||||
selection-background-color: #96db59;
|
||||
selection-color: black;
|
||||
}
|
||||
QLineEdit#token:focus { border: 1px solid #96db59; }
|
||||
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#primary {
|
||||
background: #96db59;
|
||||
color: #1a1a1a;
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
padding: 8px 24px;
|
||||
font-size: 10pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
QPushButton#primary:hover { background: #a8e670; }
|
||||
QPushButton#primary:pressed { background: #7fbf48; }
|
||||
QPushButton#primary:disabled { background: #4a5a3a; color: #888888; }
|
||||
"""
|
||||
|
||||
|
||||
def prompt_login_qt() -> str | None:
|
||||
"""Modal dialog to collect a fresh ``discord_id:password`` token.
|
||||
|
||||
Returned string is the validated raw token (caller writes to disk).
|
||||
Returns ``None`` if the user picked "Skip cloud sync" or closed the
|
||||
dialog — caller should treat that as "don't sync, don't block launch."
|
||||
|
||||
Visually matches the conflict dialog: Prism dark surface, circled
|
||||
badge + uppercase title, monospace input field with Prism-green
|
||||
focus accent, primary "Save and continue" button in Prism green.
|
||||
"""
|
||||
QtWidgets, QtCore, _ = import_qt()
|
||||
app_existed = QtWidgets.QApplication.instance() is not None
|
||||
@@ -205,58 +287,79 @@ def prompt_login_qt() -> str | None:
|
||||
_apply_prism_dark(app)
|
||||
|
||||
dialog = QtWidgets.QDialog()
|
||||
dialog.setWindowTitle("Cloud sync — first time setup")
|
||||
dialog.setFixedSize(480, 260)
|
||||
dialog.setWindowTitle("Cloud sync — connect account")
|
||||
dialog.setFixedSize(560, 360)
|
||||
dialog.setStyleSheet(_LOGIN_QSS)
|
||||
|
||||
layout = QtWidgets.QVBoxLayout(dialog)
|
||||
layout.setContentsMargins(20, 20, 20, 20)
|
||||
layout.setSpacing(10)
|
||||
outer = QtWidgets.QVBoxLayout(dialog)
|
||||
outer.setContentsMargins(28, 24, 28, 20)
|
||||
outer.setSpacing(14)
|
||||
|
||||
title = QtWidgets.QLabel("Connect to cloud save")
|
||||
font = title.font()
|
||||
font.setBold(True)
|
||||
font.setPointSize(font.pointSize() + 2)
|
||||
title.setFont(font)
|
||||
layout.addWidget(title)
|
||||
header = QtWidgets.QHBoxLayout()
|
||||
header.setSpacing(12)
|
||||
badge = QtWidgets.QLabel("+")
|
||||
badge.setObjectName("badge")
|
||||
header.addWidget(badge)
|
||||
title = QtWidgets.QLabel("CONNECT CLOUD SAVE")
|
||||
title.setObjectName("title")
|
||||
header.addWidget(title)
|
||||
header.addStretch(1)
|
||||
outer.addLayout(header)
|
||||
|
||||
body = QtWidgets.QLabel(
|
||||
"In Discord, message the bot:\n"
|
||||
" /cloud register\n\n"
|
||||
"It will DM you a one-line token. Paste it below:"
|
||||
"To enable cross-machine save sync, message the Discord bot to "
|
||||
"register this account. The bot will DM you a one-line token — "
|
||||
"paste it below."
|
||||
)
|
||||
body.setObjectName("body")
|
||||
body.setWordWrap(True)
|
||||
layout.addWidget(body)
|
||||
outer.addWidget(body)
|
||||
|
||||
cmd = QtWidgets.QLabel("/cloud register")
|
||||
cmd.setObjectName("cmd")
|
||||
cmd.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.TextSelectableByMouse)
|
||||
cmd.setFixedWidth(180)
|
||||
outer.addWidget(cmd)
|
||||
|
||||
outer.addSpacing(4)
|
||||
|
||||
field_label = QtWidgets.QLabel("Token")
|
||||
field_label.setObjectName("hint")
|
||||
outer.addWidget(field_label)
|
||||
|
||||
field = QtWidgets.QLineEdit()
|
||||
field.setPlaceholderText("123456789012345678:a1b2c3d4…")
|
||||
field.setObjectName("token")
|
||||
field.setPlaceholderText("123456789012345678:a1b2c3d4e5f6…")
|
||||
field.setEchoMode(QtWidgets.QLineEdit.EchoMode.Password)
|
||||
layout.addWidget(field)
|
||||
outer.addWidget(field)
|
||||
|
||||
error = QtWidgets.QLabel("")
|
||||
error.setStyleSheet("color: #ff6b6b;")
|
||||
layout.addWidget(error)
|
||||
error.setObjectName("error")
|
||||
outer.addWidget(error)
|
||||
|
||||
layout.addStretch(1)
|
||||
outer.addStretch(1)
|
||||
|
||||
button_row = QtWidgets.QHBoxLayout()
|
||||
foot = QtWidgets.QHBoxLayout()
|
||||
skip = QtWidgets.QPushButton("Skip cloud sync")
|
||||
button_row.addWidget(skip)
|
||||
button_row.addStretch(1)
|
||||
skip.setObjectName("secondary")
|
||||
foot.addWidget(skip)
|
||||
foot.addStretch(1)
|
||||
save = QtWidgets.QPushButton("Save and continue")
|
||||
save.setObjectName("primary")
|
||||
save.setDefault(True)
|
||||
button_row.addWidget(save)
|
||||
layout.addLayout(button_row)
|
||||
foot.addWidget(save)
|
||||
outer.addLayout(foot)
|
||||
|
||||
chosen: dict[str, str | None] = {"value": None}
|
||||
|
||||
def on_save() -> None:
|
||||
token = field.text().strip()
|
||||
if ":" not in token:
|
||||
error.setText("Token must be discord_id:password")
|
||||
error.setText("Token must look like discord_id:password.")
|
||||
return
|
||||
head, sep, tail = token.partition(":")
|
||||
head, _sep, tail = token.partition(":")
|
||||
if not head.isdigit() or not tail:
|
||||
error.setText("discord_id must be numeric; password must be non-empty")
|
||||
error.setText("discord_id must be numeric and password non-empty.")
|
||||
return
|
||||
chosen["value"] = token
|
||||
dialog.accept()
|
||||
|
||||
Reference in New Issue
Block a user