From 02edb186bbda0fe260c0fac3bfe509eec1b4e6a7 Mon Sep 17 00:00:00 2001 From: bartool Date: Tue, 14 Oct 2025 10:04:01 +0200 Subject: [PATCH] feat: Implement photo capture functionality Implement the logic for capturing and saving photos from the live preview stream. - Add `save_photo` method to `MediaRepository` to handle file saving and database updates. - `MainController` now tracks the selected color and the latest camera frame. - The "Take Photo" button is enabled only when a color is selected. - Pressing the button saves the current preview frame to the correct media folder and refreshes the thumbnail list. - Fixes indentation issues in `main_controller.py` caused by previous faulty replacements. --- controllers/main_controller.py | 32 ++++++++++++++++++++++++++------ core/media.py | 27 +++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/controllers/main_controller.py b/controllers/main_controller.py index ee83ab5..8e77613 100644 --- a/controllers/main_controller.py +++ b/controllers/main_controller.py @@ -19,6 +19,10 @@ class MainController: self.media_repo = MediaRepository() self.camera_manager = CameraManager() + # --- State --- + self.selected_color_name: str | None = None + self._latest_pixmap: QPixmap | None = None + # --- UI Widgets --- self.color_list: ColorListWidget = view.color_list_widget self.thumbnail_list: ThumbnailListWidget = view.thumbnail_widget @@ -33,6 +37,9 @@ class MainController: self.db.connect() self.media_repo.sync_media() + # Disable button by default + self.photo_button.setEnabled(False) + # Initialize state machine self.state: CameraState = NoCamerasState() self.state.enter_state(self) @@ -77,6 +84,9 @@ class MainController: @Slot(str) def on_color_selected(self, color_name: str): + self.selected_color_name = color_name + self.photo_button.setEnabled(True) + color_id = self.db.get_color_id(color_name) if color_id is not None: media_items = self.db.get_media_for_color(color_id) @@ -109,7 +119,8 @@ class MainController: @Slot(QPixmap) def on_frame_ready(self, pixmap: QPixmap): - """Displays a new frame from the camera.""" + """Displays a new frame from the camera and stores it.""" + self._latest_pixmap = pixmap self.split_view.set_live_image(pixmap) @Slot(str) @@ -151,7 +162,6 @@ class MainController: self.on_camera_error("No cameras detected.") return - # For now, just start the first detected camera. camera_id = detected_cameras[0]['id'] self.camera_manager.start_camera(camera_id) @@ -161,7 +171,17 @@ class MainController: def take_photo(self): """Takes a photo with the active camera.""" - print("Taking photo...") # Placeholder - # This needs to be implemented in CameraManager and called here. - # e.g., self.camera_manager.take_photo() - self.split_view.toggle_live_view() # This seems like a UI toggle, maybe rename? \ No newline at end of file + if self.selected_color_name is None: + print("Cannot take photo: No color selected.") + # Optionally: show a message to the user in the UI + return + + if self._latest_pixmap is None or self._latest_pixmap.isNull(): + print("Cannot take photo: No frame available.") + return + + print(f"Taking photo for color: {self.selected_color_name}") + self.media_repo.save_photo(self._latest_pixmap, self.selected_color_name) + + # Refresh thumbnail list + self.on_color_selected(self.selected_color_name) \ No newline at end of file diff --git a/core/media.py b/core/media.py index c02bfc1..aa24dc2 100644 --- a/core/media.py +++ b/core/media.py @@ -1,5 +1,7 @@ from pathlib import Path import shutil +from datetime import datetime +from PySide6.QtGui import QPixmap from core.database import db_manager MEDIA_DIR = Path("media") @@ -9,6 +11,31 @@ class MediaRepository: def __init__(self): self.db = db_manager + def save_photo(self, pixmap: QPixmap, color_name: str): + """Saves a pixmap to the media directory for the given color.""" + color_id = self.db.get_color_id(color_name) + if color_id is None: + print(f"Error: Could not find color ID for {color_name}") + return + + # Create directory if it doesn't exist + color_dir = MEDIA_DIR / color_name + color_dir.mkdir(parents=True, exist_ok=True) + + # Generate unique filename + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f") + filename = f"photo_{timestamp}.jpg" + file_path = color_dir / filename + + # Save the pixmap + if not pixmap.save(str(file_path), "JPG", 95): + print(f"Error: Failed to save pixmap to {file_path}") + return + + # Add to database + self.db.add_media(color_id, str(file_path), 'photo') + print(f"Saved photo to {file_path}") + def sync_media(self): disk_colors = {d.name for d in MEDIA_DIR.iterdir() if d.is_dir()} db_colors = {c["name"] for c in self.db.get_all_colors()}