diff --git a/src/ui/screens/home_screen.py b/src/ui/screens/home_screen.py index 36cd228..f9840ef 100644 --- a/src/ui/screens/home_screen.py +++ b/src/ui/screens/home_screen.py @@ -1,132 +1,419 @@ -"""Écran d'accueil — choix du mode d'import.""" +"""Écran d'accueil — choix du mode d'import avec instructions.""" from PyQt6.QtWidgets import ( - QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel + QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, + QStackedWidget, QSizePolicy ) -from PyQt6.QtCore import Qt -from PyQt6.QtGui import QFont +from PyQt6.QtCore import Qt, QTimer +from PyQt6.QtGui import QFont, QPixmap, QImage from services.usb_watcher import UsbWatcher +WIFI_AP_NAME = "Photostation" +WIFI_AP_PASSWORD = "photo1234" +EMAIL_ADDRESS = "photo@photostation.local" + +BTN_STYLE = """ + QPushButton {{ + background-color: {bg}; + color: white; + border-radius: 15px; + padding: 20px; + }} + QPushButton:pressed {{ + background-color: {pressed}; + }} +""" +BTN_BLUE = BTN_STYLE.format(bg="#2196F3", pressed="#1976D2") +BTN_GREEN = BTN_STYLE.format(bg="#4CAF50", pressed="#388E3C") + +BACK_BTN_STYLE = """ + QPushButton { + background-color: #757575; + color: white; + border-radius: 10px; + padding: 10px 30px; + } + QPushButton:pressed { background-color: #616161; } +""" + +INFO_STYLE = """ + QLabel { + color: #333; + padding: 10px; + } +""" + +HIGHLIGHT_STYLE = """ + QLabel { + background-color: #E3F2FD; + border: 2px solid #2196F3; + border-radius: 10px; + padding: 15px; + color: #1565C0; + font-size: 20px; + } +""" + +ERROR_STYLE = """ + QLabel { + background-color: #FFEBEE; + border: 2px solid #F44336; + border-radius: 10px; + padding: 15px; + color: #C62828; + } +""" + +SUCCESS_STYLE = """ + QLabel { + background-color: #E8F5E9; + border: 2px solid #4CAF50; + border-radius: 10px; + padding: 15px; + color: #2E7D32; + } +""" + class HomeScreen(QWidget): def __init__(self, main_window): super().__init__() self.main_window = main_window + self._usb_photos = [] + self._usb_mount = None self._setup_ui() self._setup_usb_watcher() def _setup_ui(self): layout = QVBoxLayout(self) - layout.setAlignment(Qt.AlignmentFlag.AlignCenter) - layout.setSpacing(40) + layout.setContentsMargins(20, 20, 20, 20) + layout.setSpacing(20) - # Titre + # Titre (toujours visible) title = QLabel("Photostation") - title.setFont(QFont("", 48, QFont.Weight.Bold)) + title.setFont(QFont("", 42, QFont.Weight.Bold)) title.setAlignment(Qt.AlignmentFlag.AlignCenter) layout.addWidget(title) - subtitle = QLabel("Sélectionnez un mode d'import") - subtitle.setFont(QFont("", 20)) + # Zone switchable : choix des modes OU instructions d'un mode + self.stack = QStackedWidget() + layout.addWidget(self.stack, 1) + + # Page 0 : Choix des modes + self.stack.addWidget(self._build_mode_selection()) + # Page 1 : Instructions USB + self.stack.addWidget(self._build_usb_instructions()) + # Page 2 : Instructions WiFi + self.stack.addWidget(self._build_wifi_instructions()) + # Page 3 : Instructions QR Code + self.stack.addWidget(self._build_qr_instructions()) + # Page 4 : Instructions Email + self.stack.addWidget(self._build_email_instructions()) + + # ─── Page 0 : Sélection des modes ─── + + def _build_mode_selection(self): + page = QWidget() + layout = QVBoxLayout(page) + layout.setAlignment(Qt.AlignmentFlag.AlignCenter) + layout.setSpacing(30) + + subtitle = QLabel("Comment souhaitez-vous envoyer vos photos ?") + subtitle.setFont(QFont("", 18)) subtitle.setAlignment(Qt.AlignmentFlag.AlignCenter) layout.addWidget(subtitle) - # Status USB - self.usb_status = QLabel("") - self.usb_status.setFont(QFont("", 14)) - self.usb_status.setAlignment(Qt.AlignmentFlag.AlignCenter) - self.usb_status.setStyleSheet("color: #4CAF50;") - layout.addWidget(self.usb_status) - - # Boutons d'import buttons_layout = QHBoxLayout() buttons_layout.setSpacing(20) modes = [ - ("USB", "Clé USB", self._import_usb), - ("WiFi", "Depuis téléphone", self._import_wifi), - ("QR Code", "Scanner pour envoyer", self._import_qr), - ("Email", "Recevoir par mail", self._import_email), + ("USB", "Clé USB", self._show_usb), + ("WiFi", "Depuis téléphone", self._show_wifi), + ("QR Code", "Scanner pour\nenvoyer", self._show_qr), + ("Email", "Recevoir par\nmail", self._show_email), ] - self.buttons = {} + self.mode_buttons = {} for label, desc, callback in modes: - btn = self._create_mode_button(label, desc) + btn = QPushButton(f"{label}\n\n{desc}") + btn.setFont(QFont("", 16)) + btn.setMinimumSize(200, 150) + btn.setStyleSheet(BTN_BLUE) btn.clicked.connect(callback) buttons_layout.addWidget(btn) - self.buttons[label] = btn + self.mode_buttons[label] = btn layout.addLayout(buttons_layout) + return page - def _create_mode_button(self, label, description): - btn = QPushButton(f"{label}\n{description}") - btn.setFont(QFont("", 16)) - btn.setMinimumSize(200, 150) - btn.setStyleSheet(""" - QPushButton { - background-color: #2196F3; - color: white; - border-radius: 15px; - padding: 20px; - } - QPushButton:pressed { - background-color: #1976D2; - } - QPushButton:disabled { - background-color: #9E9E9E; - } - """) - return btn + # ─── Page 1 : USB ─── + + def _build_usb_instructions(self): + page = QWidget() + layout = QVBoxLayout(page) + layout.setAlignment(Qt.AlignmentFlag.AlignCenter) + layout.setSpacing(25) + + # Instruction principale + instruction = QLabel("Insérez votre clé USB dans le port\nde la borne") + instruction.setFont(QFont("", 24)) + instruction.setAlignment(Qt.AlignmentFlag.AlignCenter) + layout.addWidget(instruction) + + # Zone de status (change dynamiquement) + self.usb_status_label = QLabel("En attente de la clé USB...") + self.usb_status_label.setFont(QFont("", 18)) + self.usb_status_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.usb_status_label.setMinimumHeight(70) + self.usb_status_label.setStyleSheet(HIGHLIGHT_STYLE) + layout.addWidget(self.usb_status_label) + + # Bouton continuer (masqué tant que pas de clé) + self.usb_continue_btn = QPushButton("Continuer") + self.usb_continue_btn.setFont(QFont("", 18, QFont.Weight.Bold)) + self.usb_continue_btn.setMinimumSize(250, 60) + self.usb_continue_btn.setStyleSheet(BTN_GREEN) + self.usb_continue_btn.clicked.connect(self._import_usb) + self.usb_continue_btn.hide() + layout.addWidget(self.usb_continue_btn, alignment=Qt.AlignmentFlag.AlignCenter) + + # Bouton retour + back = QPushButton("Retour") + back.setFont(QFont("", 14)) + back.setStyleSheet(BACK_BTN_STYLE) + back.clicked.connect(self._show_modes) + layout.addWidget(back, alignment=Qt.AlignmentFlag.AlignCenter) + + return page + + # ─── Page 2 : WiFi ─── + + def _build_wifi_instructions(self): + page = QWidget() + layout = QVBoxLayout(page) + layout.setAlignment(Qt.AlignmentFlag.AlignCenter) + layout.setSpacing(25) + + instruction = QLabel("Connectez-vous au réseau WiFi\nde la borne depuis votre téléphone") + instruction.setFont(QFont("", 24)) + instruction.setAlignment(Qt.AlignmentFlag.AlignCenter) + layout.addWidget(instruction) + + # Infos réseau + info_box = QWidget() + info_layout = QVBoxLayout(info_box) + info_layout.setSpacing(10) + + net_name = QLabel(f"Nom du réseau : {WIFI_AP_NAME}") + net_name.setFont(QFont("", 22, QFont.Weight.Bold)) + net_name.setAlignment(Qt.AlignmentFlag.AlignCenter) + net_name.setStyleSheet(HIGHLIGHT_STYLE) + info_layout.addWidget(net_name) + + net_pass = QLabel(f"Mot de passe : {WIFI_AP_PASSWORD}") + net_pass.setFont(QFont("", 22, QFont.Weight.Bold)) + net_pass.setAlignment(Qt.AlignmentFlag.AlignCenter) + net_pass.setStyleSheet(HIGHLIGHT_STYLE) + info_layout.addWidget(net_pass) + + layout.addWidget(info_box) + + step2 = QLabel("Une fois connecté, une page s'ouvrira\nautomatiquement pour envoyer vos photos") + step2.setFont(QFont("", 16)) + step2.setAlignment(Qt.AlignmentFlag.AlignCenter) + step2.setStyleSheet("color: #666;") + layout.addWidget(step2) + + # Status connexions + self.wifi_status_label = QLabel("En attente de connexion...") + self.wifi_status_label.setFont(QFont("", 16)) + self.wifi_status_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.wifi_status_label.setStyleSheet(INFO_STYLE) + layout.addWidget(self.wifi_status_label) + + back = QPushButton("Retour") + back.setFont(QFont("", 14)) + back.setStyleSheet(BACK_BTN_STYLE) + back.clicked.connect(self._show_modes) + layout.addWidget(back, alignment=Qt.AlignmentFlag.AlignCenter) + + return page + + # ─── Page 3 : QR Code ─── + + def _build_qr_instructions(self): + page = QWidget() + layout = QVBoxLayout(page) + layout.setAlignment(Qt.AlignmentFlag.AlignCenter) + layout.setSpacing(20) + + instruction = QLabel("Scannez ce QR code avec votre téléphone\npour envoyer vos photos") + instruction.setFont(QFont("", 24)) + instruction.setAlignment(Qt.AlignmentFlag.AlignCenter) + layout.addWidget(instruction) + + # QR Code affiché + self.qr_image_label = QLabel() + self.qr_image_label.setFixedSize(250, 250) + self.qr_image_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.qr_image_label.setStyleSheet("background-color: white; border: 2px solid #ccc; border-radius: 10px;") + layout.addWidget(self.qr_image_label, alignment=Qt.AlignmentFlag.AlignCenter) + + # URL affichée en texte aussi + self.qr_url_label = QLabel("") + self.qr_url_label.setFont(QFont("", 14)) + self.qr_url_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.qr_url_label.setStyleSheet("color: #666;") + layout.addWidget(self.qr_url_label) + + hint = QLabel("Envoyez vos photos depuis la page web\nqui s'ouvrira sur votre téléphone") + hint.setFont(QFont("", 16)) + hint.setAlignment(Qt.AlignmentFlag.AlignCenter) + hint.setStyleSheet("color: #666;") + layout.addWidget(hint) + + # Status réception + self.qr_status_label = QLabel("En attente de photos...") + self.qr_status_label.setFont(QFont("", 16)) + self.qr_status_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.qr_status_label.setStyleSheet(INFO_STYLE) + layout.addWidget(self.qr_status_label) + + back = QPushButton("Retour") + back.setFont(QFont("", 14)) + back.setStyleSheet(BACK_BTN_STYLE) + back.clicked.connect(self._show_modes) + layout.addWidget(back, alignment=Qt.AlignmentFlag.AlignCenter) + + return page + + # ─── Page 4 : Email ─── + + def _build_email_instructions(self): + page = QWidget() + layout = QVBoxLayout(page) + layout.setAlignment(Qt.AlignmentFlag.AlignCenter) + layout.setSpacing(25) + + instruction = QLabel("Envoyez vos photos par email\nà l'adresse suivante :") + instruction.setFont(QFont("", 24)) + instruction.setAlignment(Qt.AlignmentFlag.AlignCenter) + layout.addWidget(instruction) + + # Adresse email mise en évidence + self.email_address_label = QLabel(EMAIL_ADDRESS) + self.email_address_label.setFont(QFont("", 28, QFont.Weight.Bold)) + self.email_address_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.email_address_label.setStyleSheet(HIGHLIGHT_STYLE) + self.email_address_label.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse) + layout.addWidget(self.email_address_label) + + hint = QLabel("Joignez vos photos en pièce jointe\net envoyez depuis votre téléphone") + hint.setFont(QFont("", 16)) + hint.setAlignment(Qt.AlignmentFlag.AlignCenter) + hint.setStyleSheet("color: #666;") + layout.addWidget(hint) + + # Status réception + self.email_status_label = QLabel("En attente de réception...") + self.email_status_label.setFont(QFont("", 16)) + self.email_status_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.email_status_label.setStyleSheet(INFO_STYLE) + layout.addWidget(self.email_status_label) + + back = QPushButton("Retour") + back.setFont(QFont("", 14)) + back.setStyleSheet(BACK_BTN_STYLE) + back.clicked.connect(self._show_modes) + layout.addWidget(back, alignment=Qt.AlignmentFlag.AlignCenter) + + return page + + # ─── Navigation entre pages ─── + + def _show_modes(self): + self.stack.setCurrentIndex(0) + + def _show_usb(self): + self._update_usb_status() + self.stack.setCurrentIndex(1) + + def _show_wifi(self): + self.stack.setCurrentIndex(2) + + def _show_qr(self): + self._generate_qr() + self.stack.setCurrentIndex(3) + + def _show_email(self): + self.stack.setCurrentIndex(4) + + # ─── USB ─── def _setup_usb_watcher(self): self.usb_watcher = UsbWatcher(self) self.usb_watcher.usb_inserted.connect(self._on_usb_inserted) self.usb_watcher.usb_removed.connect(self._on_usb_removed) self.usb_watcher.start() - self._usb_photos = [] - self._usb_mount = None def _on_usb_inserted(self, mount_path, photos): self._usb_mount = mount_path self._usb_photos = photos - count = len(photos) - self.usb_status.setText(f"Clé USB détectée — {count} photo{'s' if count != 1 else ''}") - self.buttons["USB"].setStyleSheet(""" - QPushButton { - background-color: #4CAF50; - color: white; - border-radius: 15px; - padding: 20px; - } - QPushButton:pressed { background-color: #388E3C; } - """) + self.mode_buttons["USB"].setStyleSheet(BTN_GREEN) + self._update_usb_status() def _on_usb_removed(self, mount_path): if mount_path == self._usb_mount: self._usb_mount = None self._usb_photos = [] - self.usb_status.setText("") - self.buttons["USB"].setStyleSheet(""" - QPushButton { - background-color: #2196F3; - color: white; - border-radius: 15px; - padding: 20px; - } - QPushButton:pressed { background-color: #1976D2; } - """) + self.mode_buttons["USB"].setStyleSheet(BTN_BLUE) + self._update_usb_status() + + def _update_usb_status(self): + if self._usb_photos: + count = len(self._usb_photos) + self.usb_status_label.setText( + f"Clé USB détectée — {count} photo{'s' if count != 1 else ''} trouvée{'s' if count != 1 else ''}" + ) + self.usb_status_label.setStyleSheet(SUCCESS_STYLE) + self.usb_continue_btn.show() + else: + self.usb_status_label.setText("Clé USB non détectée\nInsérez votre clé USB puis patientez quelques secondes") + self.usb_status_label.setStyleSheet(ERROR_STYLE) + self.usb_continue_btn.hide() def _import_usb(self): if self._usb_photos: self.main_window.import_screen.set_photos(self._usb_photos) self.main_window.show_import() - def _import_wifi(self): - self.main_window.show_import() + # ─── QR Code ─── - def _import_qr(self): - self.main_window.show_import() + def _generate_qr(self): + try: + import qrcode + import io - def _import_email(self): - self.main_window.show_import() + upload_url = f"http://192.168.4.1/upload" + qr = qrcode.QRCode(version=1, box_size=8, border=2) + qr.add_data(upload_url) + qr.make(fit=True) + img = qr.make_image(fill_color="black", back_color="white") + + # PIL Image -> QPixmap + buffer = io.BytesIO() + img.save(buffer, format="PNG") + buffer.seek(0) + qimage = QImage() + qimage.loadFromData(buffer.read()) + pixmap = QPixmap.fromImage(qimage) + + self.qr_image_label.setPixmap( + pixmap.scaled(230, 230, Qt.AspectRatioMode.KeepAspectRatio, + Qt.TransformationMode.SmoothTransformation) + ) + self.qr_url_label.setText(upload_url) + except ImportError: + self.qr_image_label.setText("Module qrcode\nnon installé") + self.qr_url_label.setText("")