""" settings_dialog.py — Indstillinger for LineDance Player. Gemmes via QSettings og læses ved opstart. """ from PyQt6.QtWidgets import ( QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QComboBox, QSpinBox, QCheckBox, QFrame, QTabWidget, QWidget, QFileDialog, QGroupBox, QFormLayout, ) from PyQt6.QtCore import Qt, QSettings SETTINGS_KEY_THEME = "appearance/dark_theme" SETTINGS_KEY_DEMO_SEC = "playback/demo_seconds" SETTINGS_KEY_MAIL_CLIENT = "mail/client" # "auto"|"thunderbird"|"outlook"|"mailto" SETTINGS_KEY_MAIL_PATH = "mail/custom_path" SETTINGS_KEY_AUTO_LOGIN = "online/auto_login" SETTINGS_KEY_USERNAME = "online/username" SETTINGS_KEY_PASSWORD = "online/password" # gemt i klartekst — ikke ideelt, men funktionelt def load_settings() -> dict: """Indlæs alle indstillinger med fornuftige standardværdier.""" s = QSettings("LineDance", "Player") return { "dark_theme": s.value(SETTINGS_KEY_THEME, True, type=bool), "demo_seconds": s.value(SETTINGS_KEY_DEMO_SEC, 10, type=int), "mail_client": s.value(SETTINGS_KEY_MAIL_CLIENT, "auto"), "mail_path": s.value(SETTINGS_KEY_MAIL_PATH, ""), "auto_login": s.value(SETTINGS_KEY_AUTO_LOGIN, False, type=bool), "username": s.value(SETTINGS_KEY_USERNAME, ""), "password": s.value(SETTINGS_KEY_PASSWORD, ""), } def save_settings(values: dict): s = QSettings("LineDance", "Player") s.setValue(SETTINGS_KEY_THEME, values.get("dark_theme", True)) s.setValue(SETTINGS_KEY_DEMO_SEC, values.get("demo_seconds", 10)) s.setValue(SETTINGS_KEY_MAIL_CLIENT, values.get("mail_client", "auto")) s.setValue(SETTINGS_KEY_MAIL_PATH, values.get("mail_path", "")) s.setValue(SETTINGS_KEY_AUTO_LOGIN, values.get("auto_login", False)) s.setValue(SETTINGS_KEY_USERNAME, values.get("username", "")) s.setValue(SETTINGS_KEY_PASSWORD, values.get("password", "")) class SettingsDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("Indstillinger") self.setMinimumWidth(480) self.setModal(True) self._values = load_settings() self._build_ui() self._populate() def _build_ui(self): layout = QVBoxLayout(self) layout.setContentsMargins(16, 16, 16, 16) layout.setSpacing(12) tabs = QTabWidget() tabs.addTab(self._build_appearance_tab(), "🎨 Udseende") tabs.addTab(self._build_playback_tab(), "▶ Afspilning") tabs.addTab(self._build_mail_tab(), "✉ Mail") tabs.addTab(self._build_online_tab(), "🌐 Online") layout.addWidget(tabs) # Knapper btn_row = QHBoxLayout() btn_row.addStretch() btn_cancel = QPushButton("Annuller") btn_cancel.clicked.connect(self.reject) btn_row.addWidget(btn_cancel) btn_save = QPushButton("💾 Gem indstillinger") btn_save.setObjectName("btn_play") btn_save.setDefault(True) btn_save.clicked.connect(self._save_and_close) btn_row.addWidget(btn_save) layout.addLayout(btn_row) # ── Fane: Udseende ──────────────────────────────────────────────────────── def _build_appearance_tab(self) -> QWidget: tab = QWidget() layout = QVBoxLayout(tab) layout.setSpacing(12) grp = QGroupBox("Standard tema") grp_layout = QVBoxLayout(grp) self._chk_dark = QCheckBox("Start med mørkt tema") grp_layout.addWidget(self._chk_dark) note = QLabel("Du kan altid skifte tema mens programmet kører via topbar-knappen.") note.setObjectName("result_count") note.setWordWrap(True) grp_layout.addWidget(note) layout.addWidget(grp) layout.addStretch() return tab # ── Fane: Afspilning ────────────────────────────────────────────────────── def _build_playback_tab(self) -> QWidget: tab = QWidget() layout = QVBoxLayout(tab) layout.setSpacing(12) grp = QGroupBox("Forspil (▶ N SEK knappen)") grp_layout = QFormLayout(grp) self._spin_demo = QSpinBox() self._spin_demo.setRange(3, 60) self._spin_demo.setSuffix(" sekunder") self._spin_demo.setFixedWidth(140) grp_layout.addRow("Forspil-længde:", self._spin_demo) note = QLabel( "Forspillet afspiller begyndelsen af sangen så arrangøren kan bekræfte\n" "at det er den rigtige sang og dans inden eventet starter." ) note.setObjectName("result_count") note.setWordWrap(True) grp_layout.addRow(note) layout.addWidget(grp) layout.addStretch() return tab # ── Fane: Mail ──────────────────────────────────────────────────────────── def _build_mail_tab(self) -> QWidget: tab = QWidget() layout = QVBoxLayout(tab) layout.setSpacing(12) grp = QGroupBox("Mailklient") grp_layout = QFormLayout(grp) self._mail_combo = QComboBox() self._mail_combo.addItem("Auto-detekter (Thunderbird → Outlook → mailto:)", "auto") self._mail_combo.addItem("Thunderbird", "thunderbird") self._mail_combo.addItem("Outlook (Windows)", "outlook") self._mail_combo.addItem("Brugerdefineret sti", "custom") self._mail_combo.addItem("Kun mailto: (ingen vedhæftning)", "mailto") self._mail_combo.currentIndexChanged.connect(self._on_mail_combo_changed) grp_layout.addRow("Klient:", self._mail_combo) path_row = QHBoxLayout() self._mail_path = QLineEdit() self._mail_path.setPlaceholderText("/usr/bin/thunderbird eller C:\\...\\thunderbird.exe") path_row.addWidget(self._mail_path) btn_browse = QPushButton("...") btn_browse.setFixedWidth(32) btn_browse.clicked.connect(self._browse_mail_path) path_row.addWidget(btn_browse) self._mail_path_row_widget = QWidget() self._mail_path_row_widget.setLayout(path_row) grp_layout.addRow("Sti:", self._mail_path_row_widget) note = QLabel( "Med Thunderbird og Outlook åbnes et nyt compose-vindue med filen vedhæftet.\n" "mailto: åbner standard-mailprogrammet men uden automatisk vedhæftning." ) note.setObjectName("result_count") note.setWordWrap(True) grp_layout.addRow(note) layout.addWidget(grp) layout.addStretch() return tab def _on_mail_combo_changed(self, idx: int): is_custom = self._mail_combo.currentData() == "custom" self._mail_path_row_widget.setVisible(is_custom) def _browse_mail_path(self): path, _ = QFileDialog.getOpenFileName(self, "Vælg mailklient") if path: self._mail_path.setText(path) # ── Fane: Online ────────────────────────────────────────────────────────── def _build_online_tab(self) -> QWidget: tab = QWidget() layout = QVBoxLayout(tab) layout.setSpacing(12) grp = QGroupBox("Automatisk login ved opstart") grp_layout = QFormLayout(grp) self._chk_auto_login = QCheckBox("Log automatisk ind når programmet starter") self._chk_auto_login.stateChanged.connect(self._on_auto_login_changed) grp_layout.addRow(self._chk_auto_login) self._user_input = QLineEdit() self._user_input.setPlaceholderText("dit-brugernavn") grp_layout.addRow("Brugernavn:", self._user_input) self._pass_input = QLineEdit() self._pass_input.setEchoMode(QLineEdit.EchoMode.Password) self._pass_input.setPlaceholderText("••••••••") grp_layout.addRow("Kodeord:", self._pass_input) note = QLabel( "⚠ Kodeordet gemmes lokalt på denne computer.\n" "Brug kun dette på en personlig maskine." ) note.setObjectName("result_count") note.setWordWrap(True) grp_layout.addRow(note) layout.addWidget(grp) layout.addStretch() return tab def _on_auto_login_changed(self, state: int): enabled = state == Qt.CheckState.Checked.value self._user_input.setEnabled(enabled) self._pass_input.setEnabled(enabled) # ── Populer fra gemte værdier ───────────────────────────────────────────── def _populate(self): v = self._values self._chk_dark.setChecked(v.get("dark_theme", True)) self._spin_demo.setValue(v.get("demo_seconds", 10)) # Mail client = v.get("mail_client", "auto") for i in range(self._mail_combo.count()): if self._mail_combo.itemData(i) == client: self._mail_combo.setCurrentIndex(i) break self._mail_path.setText(v.get("mail_path", "")) self._on_mail_combo_changed(self._mail_combo.currentIndex()) # Online auto = v.get("auto_login", False) self._chk_auto_login.setChecked(auto) self._user_input.setText(v.get("username", "")) self._pass_input.setText(v.get("password", "")) self._user_input.setEnabled(auto) self._pass_input.setEnabled(auto) # ── Gem ─────────────────────────────────────────────────────────────────── def _save_and_close(self): values = { "dark_theme": self._chk_dark.isChecked(), "demo_seconds": self._spin_demo.value(), "mail_client": self._mail_combo.currentData(), "mail_path": self._mail_path.text().strip(), "auto_login": self._chk_auto_login.isChecked(), "username": self._user_input.text().strip(), "password": self._pass_input.text(), } save_settings(values) self._values = values self.accept() def get_values(self) -> dict: return self._values