rename: cloud sync -> instance sync; cloud -> Timemachine Network; drop Tk
Product / UI / CLI / docs rebrand. Internal package, repo, and on-disk dir names stay 'cloud_sync' / 'cloud-sync' / '.cloud-sync/' to avoid breaking existing installs; a future commit can do the file-system rename when the cost is worth paying. User-facing changes: CLI prog name: cloud-sync -> instance-sync CLI description: cloud-svc URL -> Timemachine Network endpoint Dialog title: CLOUD SYNC -> INSTANCE SYNC Dialog title: CLOUD CONFLICT -> INSTANCE CONFLICT Dialog title: CONNECT CLOUD SAVE -> CONNECT TO THE NETWORK Card label: Cloud Save -> Remote Save Skip button: Skip cloud sync -> Skip instance sync Body copy: 'the cloud' -> 'the Timemachine Network' Window titles: Cloud sync — ... -> Instance sync — ... Log prefix: cloud-sync: -> instance-sync: Error prose: 'cloud-sync token' -> 'instance-sync token' Backend changes: restic --host tag: cloud-sync -> instance-sync State.host_tag dflt: cloud-sync -> instance-sync (Existing snapshots with the old tag still pull fine; we use 'latest'.) Drop tkinter fallback: ui.py now offers Qt OR Headless. tkinter is unnecessary given we already maintain Qt + headless; one less code path to keep styled, smaller pyz. make_progress() picks Qt first, falls through to HeadlessProgress on ImportError with a stderr hint to 'pip install PySide6'. README: rebrand title + prose; note repo/dir rename deferred; call out the PySide6 install step. Conflict/login dialogs are now Qt-only; without Qt, conflict aborts (defensive) and login tells the user to paste the token manually. 52 tests green; no test-file label changes needed since they only exercise internal APIs.
This commit is contained in:
+19
-18
@@ -1,4 +1,4 @@
|
||||
"""Qt progress UI for cloud-sync.
|
||||
"""Qt UI for instance-sync.
|
||||
|
||||
Supports both PySide6 (preferred — LGPL, official Qt binding) and PyQt6
|
||||
(fallback — GPL/commercial). Same code runs on both because their
|
||||
@@ -6,7 +6,7 @@ QtWidgets / QtCore APIs are interchangeable for our subset.
|
||||
|
||||
This module never imports Qt at top level. ``import_qt()`` raises
|
||||
ImportError if neither binding is available; the factory in ``ui.py``
|
||||
catches that and falls back to the tkinter window.
|
||||
catches that and falls back to :class:`HeadlessProgress`.
|
||||
|
||||
Threading model: ``QApplication`` runs on the main thread (started by
|
||||
``run_with`` via ``QDialog.exec``); the restic worker runs on a daemon
|
||||
@@ -35,7 +35,7 @@ def import_qt() -> tuple[Any, Any, Any]:
|
||||
except ImportError as e:
|
||||
raise ImportError(
|
||||
"neither PySide6 nor PyQt6 is installed; "
|
||||
"pip install 'cloud-sync[qt]' or pip install PySide6"
|
||||
"pip install PySide6 (or pip install 'cloud-sync[qt]')"
|
||||
) from e
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ class QtProgressWindow:
|
||||
_apply_prism_dark(self._app)
|
||||
|
||||
self._dialog = QtWidgets.QDialog()
|
||||
self._dialog.setWindowTitle("Cloud sync")
|
||||
self._dialog.setWindowTitle("Instance sync")
|
||||
self._dialog.setFixedSize(520, 240)
|
||||
self._dialog.setStyleSheet(_PROGRESS_QSS)
|
||||
self._dialog.setWindowFlag(
|
||||
@@ -161,7 +161,7 @@ class QtProgressWindow:
|
||||
badge.setPixmap(icons.svg_pixmap(icons.SYNC_BADGE_SVG, 32))
|
||||
badge.setFixedSize(32, 32)
|
||||
header.addWidget(badge)
|
||||
self._title_label = QtWidgets.QLabel("CLOUD SYNC")
|
||||
self._title_label = QtWidgets.QLabel("INSTANCE SYNC")
|
||||
self._title_label.setObjectName("title")
|
||||
header.addWidget(self._title_label)
|
||||
header.addStretch(1)
|
||||
@@ -326,7 +326,7 @@ def prompt_login_qt() -> str | None:
|
||||
_apply_prism_dark(app)
|
||||
|
||||
dialog = QtWidgets.QDialog()
|
||||
dialog.setWindowTitle("Cloud sync — connect account")
|
||||
dialog.setWindowTitle("Instance sync — connect account")
|
||||
dialog.setFixedSize(560, 360)
|
||||
dialog.setStyleSheet(_LOGIN_QSS)
|
||||
|
||||
@@ -340,16 +340,16 @@ def prompt_login_qt() -> str | None:
|
||||
badge.setPixmap(icons.svg_pixmap(icons.PLUS_BADGE_SVG, 32))
|
||||
badge.setFixedSize(32, 32)
|
||||
header.addWidget(badge)
|
||||
title = QtWidgets.QLabel("CONNECT CLOUD SAVE")
|
||||
title = QtWidgets.QLabel("CONNECT TO THE NETWORK")
|
||||
title.setObjectName("title")
|
||||
header.addWidget(title)
|
||||
header.addStretch(1)
|
||||
outer.addLayout(header)
|
||||
|
||||
body = QtWidgets.QLabel(
|
||||
"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."
|
||||
"To sync this instance across machines, register on the Timemachine "
|
||||
"Network. Message the Discord bot — it will DM you a one-line token. "
|
||||
"Paste it below."
|
||||
)
|
||||
body.setObjectName("body")
|
||||
body.setWordWrap(True)
|
||||
@@ -380,7 +380,7 @@ def prompt_login_qt() -> str | None:
|
||||
outer.addStretch(1)
|
||||
|
||||
foot = QtWidgets.QHBoxLayout()
|
||||
skip = QtWidgets.QPushButton("Skip cloud sync")
|
||||
skip = QtWidgets.QPushButton("Skip instance sync")
|
||||
skip.setObjectName("secondary")
|
||||
foot.addWidget(skip)
|
||||
foot.addStretch(1)
|
||||
@@ -479,7 +479,7 @@ def prompt_conflict_qt(
|
||||
|
||||
Args:
|
||||
local_modified: human-readable "Saturday, February 12 at 12:28 AM"
|
||||
remote_modified: same, but for the cloud snapshot
|
||||
remote_modified: same, but for the Timemachine Network snapshot
|
||||
save_label: noun phrase for body copy (e.g. "Minecraft save").
|
||||
|
||||
Returns one of: ``"keep_local"``, ``"use_remote"``, ``"cancel"``.
|
||||
@@ -527,7 +527,7 @@ def prompt_conflict_qt(
|
||||
self.clicked.emit()
|
||||
|
||||
dialog = QtWidgets.QDialog()
|
||||
dialog.setWindowTitle("Cloud sync — conflict")
|
||||
dialog.setWindowTitle("Instance sync — conflict")
|
||||
dialog.setFixedSize(640, 460)
|
||||
dialog.setStyleSheet(_CONFLICT_QSS)
|
||||
|
||||
@@ -541,16 +541,17 @@ def prompt_conflict_qt(
|
||||
warning.setPixmap(icons.svg_pixmap(icons.WARNING_BADGE_SVG, 32))
|
||||
warning.setFixedSize(32, 32)
|
||||
header.addWidget(warning)
|
||||
title = QtWidgets.QLabel("CLOUD CONFLICT")
|
||||
title = QtWidgets.QLabel("INSTANCE CONFLICT")
|
||||
title.setObjectName("title")
|
||||
header.addWidget(title)
|
||||
header.addStretch(1)
|
||||
outer.addLayout(header)
|
||||
|
||||
body = QtWidgets.QLabel(
|
||||
f"Your local {save_label} conflicts with what is stored in the cloud. "
|
||||
f"Whichever save data you choose to keep will be synced to this device "
|
||||
f"and the cloud. The option you choose not to keep will be overwritten."
|
||||
f"Your local {save_label} conflicts with what is stored on the "
|
||||
f"Timemachine Network. Whichever save data you choose to keep will "
|
||||
f"be synced to this device and the network. The option you choose "
|
||||
f"not to keep will be overwritten."
|
||||
)
|
||||
body.setObjectName("body")
|
||||
body.setWordWrap(True)
|
||||
@@ -560,7 +561,7 @@ def prompt_conflict_qt(
|
||||
|
||||
cloud_card = _Card(
|
||||
icons.svg_pixmap(icons.CLOUD_SVG, 32),
|
||||
"Cloud Save",
|
||||
"Remote Save",
|
||||
f"Modified {remote_modified}",
|
||||
)
|
||||
local_card = _Card(
|
||||
|
||||
Reference in New Issue
Block a user