Config admin complète + IMAP polling
Config admin : - Serveur upload : IP d'écoute, port, URL publique (QR code) - Email IMAP : activer/désactiver, serveur, port, user, password, dossier, intervalle de polling - Checkbox pour activer IMAP Service IMAP : - Thread daemon, polling configurable (défaut 30s) - Connexion IMAP SSL, récupère mails UNSEEN - Extrait les PJ photos (jpg/png/etc.) - Sauvegarde dans data/photos/, notifie l'app via signal Qt - Bouton Email passe au vert + Continuer quand photos reçues main.py : - Lit la config pour IP/port du serveur upload - Démarre IMAP polling si activé dans la config Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,8 @@ import json
|
||||
import os
|
||||
from PyQt6.QtWidgets import (
|
||||
QDialog, QVBoxLayout, QHBoxLayout, QGridLayout,
|
||||
QLineEdit, QPushButton, QLabel, QComboBox, QScrollArea, QWidget
|
||||
QLineEdit, QPushButton, QLabel, QComboBox, QScrollArea, QWidget,
|
||||
QSpinBox, QCheckBox
|
||||
)
|
||||
from PyQt6.QtCore import Qt
|
||||
from PyQt6.QtGui import QFont
|
||||
@@ -14,13 +15,25 @@ CONFIG_PATH = os.path.join(
|
||||
)
|
||||
|
||||
DEFAULT_CONFIG = {
|
||||
# WiFi hotspot
|
||||
"wifi_ap_name": "Photostation",
|
||||
"wifi_ap_password": "photo1234",
|
||||
# Serveur upload
|
||||
"server_ip": "0.0.0.0",
|
||||
"server_port": 8080,
|
||||
"upload_url": "http://192.168.4.1:8080/upload",
|
||||
# Email IMAP
|
||||
"email_address": "photo@photostation.local",
|
||||
"upload_url": "http://192.168.4.1/upload",
|
||||
"imap_enabled": False,
|
||||
"imap_server": "",
|
||||
"imap_port": 993,
|
||||
"imap_user": "",
|
||||
"imap_password": "",
|
||||
"imap_folder": "INBOX",
|
||||
"imap_interval": 30,
|
||||
# Impression
|
||||
"printer_name": "",
|
||||
"print_format": "10x15 cm",
|
||||
"kiosk_mode": False,
|
||||
}
|
||||
|
||||
|
||||
@@ -52,27 +65,60 @@ class ConfigDialog(QDialog):
|
||||
|
||||
def showEvent(self, event):
|
||||
super().showEvent(event)
|
||||
# Plein écran pour masquer l'interface derrière
|
||||
if self.parent():
|
||||
self.setGeometry(self.parent().rect())
|
||||
self.setStyleSheet("ConfigDialog { background-color: #f0f0f0; }")
|
||||
|
||||
def _fs(self, pct):
|
||||
"""Font size en % de la hauteur du dialogue."""
|
||||
return max(8, int(self.height() * pct / 100)) if self.height() > 0 else 14
|
||||
def _section_title(self, text):
|
||||
lbl = QLabel(text)
|
||||
lbl.setFont(QFont("", 13, QFont.Weight.Bold))
|
||||
lbl.setStyleSheet("color: #2196F3; padding-top: 5px;")
|
||||
return lbl
|
||||
|
||||
def _label(self, text):
|
||||
lbl = QLabel(text)
|
||||
lbl.setFont(QFont("", 12))
|
||||
lbl.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
|
||||
return lbl
|
||||
|
||||
def _input(self, value, placeholder=""):
|
||||
inp = QLineEdit(str(value))
|
||||
inp.setFont(QFont("", 12))
|
||||
inp.setMinimumHeight(35)
|
||||
inp.setStyleSheet("""
|
||||
QLineEdit {
|
||||
border: 2px solid #ccc; border-radius: 6px;
|
||||
padding: 5px 10px; background: white;
|
||||
}
|
||||
QLineEdit:focus { border-color: #2196F3; }
|
||||
""")
|
||||
if placeholder:
|
||||
inp.setPlaceholderText(placeholder)
|
||||
return inp
|
||||
|
||||
def _password_input(self, value):
|
||||
inp = self._input(value)
|
||||
inp.setEchoMode(QLineEdit.EchoMode.Password)
|
||||
return inp
|
||||
|
||||
def _spinbox(self, value, min_val, max_val):
|
||||
sb = QSpinBox()
|
||||
sb.setFont(QFont("", 12))
|
||||
sb.setMinimumHeight(35)
|
||||
sb.setRange(min_val, max_val)
|
||||
sb.setValue(value)
|
||||
return sb
|
||||
|
||||
def _setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
layout.setContentsMargins(20, 10, 20, 10)
|
||||
layout.setSpacing(8)
|
||||
|
||||
# Titre
|
||||
title = QLabel("Configuration Photostation")
|
||||
title.setFont(QFont("", 18, QFont.Weight.Bold))
|
||||
title.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
layout.addWidget(title)
|
||||
|
||||
# Scroll area pour le contenu
|
||||
scroll = QScrollArea()
|
||||
scroll.setWidgetResizable(True)
|
||||
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
||||
@@ -87,10 +133,7 @@ class ConfigDialog(QDialog):
|
||||
row = 0
|
||||
|
||||
# ── WiFi ──
|
||||
wifi_title = QLabel("WiFi (Hotspot)")
|
||||
wifi_title.setFont(QFont("", 13, QFont.Weight.Bold))
|
||||
wifi_title.setStyleSheet("color: #2196F3; padding-top: 5px;")
|
||||
grid.addWidget(wifi_title, row, 0, 1, 2)
|
||||
grid.addWidget(self._section_title("WiFi (Hotspot)"), row, 0, 1, 2)
|
||||
row += 1
|
||||
|
||||
grid.addWidget(self._label("Nom du réseau :"), row, 0)
|
||||
@@ -103,35 +146,73 @@ class ConfigDialog(QDialog):
|
||||
grid.addWidget(self.wifi_pass_input, row, 1)
|
||||
row += 1
|
||||
|
||||
# ── QR Code ──
|
||||
qr_title = QLabel("QR Code")
|
||||
qr_title.setFont(QFont("", 13, QFont.Weight.Bold))
|
||||
qr_title.setStyleSheet("color: #2196F3; padding-top: 5px;")
|
||||
grid.addWidget(qr_title, row, 0, 1, 2)
|
||||
# ── Serveur upload ──
|
||||
grid.addWidget(self._section_title("Serveur upload (QR Code / WiFi)"), row, 0, 1, 2)
|
||||
row += 1
|
||||
|
||||
grid.addWidget(self._label("URL d'upload :"), row, 0)
|
||||
self.upload_url_input = self._input(self.config["upload_url"])
|
||||
grid.addWidget(self._label("IP d'écoute :"), row, 0)
|
||||
self.server_ip_input = self._input(self.config["server_ip"], "0.0.0.0 = toutes les interfaces")
|
||||
grid.addWidget(self.server_ip_input, row, 1)
|
||||
row += 1
|
||||
|
||||
grid.addWidget(self._label("Port :"), row, 0)
|
||||
self.server_port_input = self._spinbox(self.config["server_port"], 80, 65535)
|
||||
grid.addWidget(self.server_port_input, row, 1)
|
||||
row += 1
|
||||
|
||||
grid.addWidget(self._label("URL publique (QR) :"), row, 0)
|
||||
self.upload_url_input = self._input(self.config["upload_url"], "https://photo.exemple.fr/upload")
|
||||
grid.addWidget(self.upload_url_input, row, 1)
|
||||
row += 1
|
||||
|
||||
# ── Email ──
|
||||
email_title = QLabel("Email")
|
||||
email_title.setFont(QFont("", 13, QFont.Weight.Bold))
|
||||
email_title.setStyleSheet("color: #2196F3; padding-top: 5px;")
|
||||
grid.addWidget(email_title, row, 0, 1, 2)
|
||||
# ── Email IMAP ──
|
||||
grid.addWidget(self._section_title("Email (réception IMAP)"), row, 0, 1, 2)
|
||||
row += 1
|
||||
|
||||
grid.addWidget(self._label("Adresse email :"), row, 0)
|
||||
grid.addWidget(self._label("Activer :"), row, 0)
|
||||
self.imap_enabled_cb = QCheckBox("Consulter la boîte mail")
|
||||
self.imap_enabled_cb.setFont(QFont("", 12))
|
||||
self.imap_enabled_cb.setChecked(self.config["imap_enabled"])
|
||||
grid.addWidget(self.imap_enabled_cb, row, 1)
|
||||
row += 1
|
||||
|
||||
grid.addWidget(self._label("Adresse affichée :"), row, 0)
|
||||
self.email_input = self._input(self.config["email_address"])
|
||||
grid.addWidget(self.email_input, row, 1)
|
||||
row += 1
|
||||
|
||||
grid.addWidget(self._label("Serveur IMAP :"), row, 0)
|
||||
self.imap_server_input = self._input(self.config["imap_server"], "imap.gmail.com")
|
||||
grid.addWidget(self.imap_server_input, row, 1)
|
||||
row += 1
|
||||
|
||||
grid.addWidget(self._label("Port IMAP :"), row, 0)
|
||||
self.imap_port_input = self._spinbox(self.config["imap_port"], 1, 65535)
|
||||
grid.addWidget(self.imap_port_input, row, 1)
|
||||
row += 1
|
||||
|
||||
grid.addWidget(self._label("Utilisateur :"), row, 0)
|
||||
self.imap_user_input = self._input(self.config["imap_user"])
|
||||
grid.addWidget(self.imap_user_input, row, 1)
|
||||
row += 1
|
||||
|
||||
grid.addWidget(self._label("Mot de passe :"), row, 0)
|
||||
self.imap_pass_input = self._password_input(self.config["imap_password"])
|
||||
grid.addWidget(self.imap_pass_input, row, 1)
|
||||
row += 1
|
||||
|
||||
grid.addWidget(self._label("Dossier :"), row, 0)
|
||||
self.imap_folder_input = self._input(self.config["imap_folder"], "INBOX")
|
||||
grid.addWidget(self.imap_folder_input, row, 1)
|
||||
row += 1
|
||||
|
||||
grid.addWidget(self._label("Intervalle (sec) :"), row, 0)
|
||||
self.imap_interval_input = self._spinbox(self.config["imap_interval"], 10, 300)
|
||||
grid.addWidget(self.imap_interval_input, row, 1)
|
||||
row += 1
|
||||
|
||||
# ── Impression ──
|
||||
print_title = QLabel("Impression")
|
||||
print_title.setFont(QFont("", 13, QFont.Weight.Bold))
|
||||
print_title.setStyleSheet("color: #2196F3; padding-top: 5px;")
|
||||
grid.addWidget(print_title, row, 0, 1, 2)
|
||||
grid.addWidget(self._section_title("Impression"), row, 0, 1, 2)
|
||||
row += 1
|
||||
|
||||
grid.addWidget(self._label("Imprimante :"), row, 0)
|
||||
@@ -151,7 +232,7 @@ class ConfigDialog(QDialog):
|
||||
scroll.setWidget(content)
|
||||
layout.addWidget(scroll, 1)
|
||||
|
||||
# Boutons en bas
|
||||
# Boutons
|
||||
buttons = QHBoxLayout()
|
||||
buttons.setSpacing(15)
|
||||
|
||||
@@ -177,36 +258,20 @@ class ConfigDialog(QDialog):
|
||||
|
||||
layout.addLayout(buttons)
|
||||
|
||||
def _label(self, text):
|
||||
lbl = QLabel(text)
|
||||
lbl.setFont(QFont("", 12))
|
||||
lbl.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
|
||||
return lbl
|
||||
|
||||
def _input(self, value, placeholder=""):
|
||||
inp = QLineEdit(value)
|
||||
inp.setFont(QFont("", 12))
|
||||
inp.setMinimumHeight(35)
|
||||
inp.setStyleSheet("""
|
||||
QLineEdit {
|
||||
border: 2px solid #ccc;
|
||||
border-radius: 6px;
|
||||
padding: 5px 10px;
|
||||
background: white;
|
||||
}
|
||||
QLineEdit:focus {
|
||||
border-color: #2196F3;
|
||||
}
|
||||
""")
|
||||
if placeholder:
|
||||
inp.setPlaceholderText(placeholder)
|
||||
return inp
|
||||
|
||||
def _save(self):
|
||||
self.config["wifi_ap_name"] = self.wifi_name_input.text()
|
||||
self.config["wifi_ap_password"] = self.wifi_pass_input.text()
|
||||
self.config["server_ip"] = self.server_ip_input.text()
|
||||
self.config["server_port"] = self.server_port_input.value()
|
||||
self.config["upload_url"] = self.upload_url_input.text()
|
||||
self.config["email_address"] = self.email_input.text()
|
||||
self.config["imap_enabled"] = self.imap_enabled_cb.isChecked()
|
||||
self.config["imap_server"] = self.imap_server_input.text()
|
||||
self.config["imap_port"] = self.imap_port_input.value()
|
||||
self.config["imap_user"] = self.imap_user_input.text()
|
||||
self.config["imap_password"] = self.imap_pass_input.text()
|
||||
self.config["imap_folder"] = self.imap_folder_input.text()
|
||||
self.config["imap_interval"] = self.imap_interval_input.value()
|
||||
self.config["printer_name"] = self.printer_input.text()
|
||||
self.config["print_format"] = self.format_combo.currentText()
|
||||
save_config(self.config)
|
||||
|
||||
Reference in New Issue
Block a user