Source code for spacr.qt.install_consent

"""Apply privacy and account choices collected by desktop installation."""
from __future__ import annotations

from typing import Any, Mapping, Optional

from PySide6.QtCore import QSettings
from PySide6.QtWidgets import (
    QDialog,
    QDialogButtonBox,
    QLabel,
    QSizePolicy,
    QVBoxLayout,
)

from ..install_profile import read_profile
from .i18n import tr
from .widgets.toggle import Toggle
from .prefs import _store_args


_ORG = "spacr"
_APP = "qt"
_KEY_APPLIED = "installer/consent_applied"


def _settings() -> QSettings:
    """Open spaCR's ``QSettings``.

    :returns: the settings store.
    """
    return QSettings(*_store_args(_ORG, _APP))


def _as_bool(value: Any) -> bool:
    """Read a stored value as a boolean.

    ``QSettings`` returns strings on some platforms and real booleans on
    others, so both are accepted -- anything unrecognised is ``False``,
    which is the safe answer for a consent flag.

    :param value: the stored value.
    :returns: whether it means yes.
    """
    if isinstance(value, bool):
        return value
    return str(value).strip().lower() in {"1", "true", "yes", "on"}


[docs] class InstallerConsentDialog(QDialog): """One first-launch page whose three optional choices start off. :param parent: parent widget. """ def __init__(self, parent=None): """Build the privacy and optional-account dialog. Sized in scaled pixels rather than raw ones: a size set from Python does not grow with the stylesheet's font size, and at the 200% scale the prose inside wrapped to more height than the window had. :param parent: parent widget, or ``None``. """ super().__init__(parent) self.setWindowTitle(tr("spaCR privacy and optional account setup")) from .preferences import scaled_px self.setMinimumWidth(scaled_px(640)) layout = QVBoxLayout(self) explanation = QLabel(tr( "Crash reports go to the PUBLIC spaCR GitHub repository. They " "are world-readable, indexed, and cannot be reliably unpublished. " "A report is redacted, shown in an editable preview, and sent " "only when you press Send for that specific report. Account setup " "uses the official GitHub, Claude, Codex (GPT), and Gemini CLIs; " "spaCR does not store their passwords or tokens. All choices are " "optional and revocable in Preferences." )) explanation.setWordWrap(True) explanation.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum) layout.addWidget(explanation) self.share_diagnostics = Toggle(tr( "Include redacted diagnostic logs in report previews" )) self.report_issues = Toggle(tr( "Enable the public GitHub issue-report action" )) self.sign_in_now = Toggle(tr( "Set up GitHub, Claude, GPT/Codex, and Gemini now" )) for choice in ( self.share_diagnostics, self.report_issues, self.sign_in_now ): choice.setChecked(False) layout.addWidget(choice) buttons = QDialogButtonBox() save = buttons.addButton( tr("Save choices"), QDialogButtonBox.AcceptRole ) skip = buttons.addButton( tr("Skip — keep all off"), QDialogButtonBox.RejectRole ) save.clicked.connect(self.accept) skip.clicked.connect(self.reject) layout.addWidget(buttons)
[docs] def choices(self) -> dict[str, bool]: """Return the three explicit checkbox states.""" return { "share_diagnostics": self.share_diagnostics.isChecked(), "report_issues": self.report_issues.isChecked(), "sign_in_now": self.sign_in_now.isChecked(), }
[docs] def apply_choices(choices: Mapping[str, Any]) -> bool: """Persist choices and return whether account setup was requested. :param choices: the consent answers, read by the keys ``share_diagnostics``, ``report_issues`` and ``sign_in_now``; a missing or unrecognised value counts as no. """ from . import preferences from .ai import settings as ai_settings share = _as_bool(choices.get("share_diagnostics", False)) reports = _as_bool(choices.get("report_issues", False)) sign_in = _as_bool(choices.get("sign_in_now", False)) preferences.set_share_diagnostic_logs(share) ai_settings.set_auto_file_issues(reports) preferences.set_issue_prompt_mode( preferences.ISSUE_PROMPT_ASK if reports else preferences.ISSUE_PROMPT_NEVER ) return sign_in
def _open_account_setup(parent) -> None: """Open the AI providers dialog, for the optional account step. :param parent: the dialog to parent it to. """ from .widgets.ai_chat_panel import _ProvidersDialog _ProvidersDialog(parent).exec()