@@ -868,9 +868,6 @@ def resizeEvent(self, event):
868868# =================================================================
869869# CLASE: PreviewListWidget
870870# =================================================================
871- # =================================================================
872- # CLASE: PreviewListWidget (LIMPIA)
873- # =================================================================
874871class PreviewListWidget (QListWidget ):
875872 """
876873 QListWidget personalizado:
@@ -1121,23 +1118,31 @@ def _open_preview(self):
11211118# -----------------------------------------------------------------
11221119class PhotoDetailDialog (QDialog ):
11231120 metadata_changed = Signal (str , str , str )
1121+
11241122 def _setup_ui (self ):
11251123 main_layout = QVBoxLayout (self )
11261124 self .main_splitter = QSplitter (Qt .Horizontal )
11271125 main_layout .addWidget (self .main_splitter )
1126+
1127+ # Panel Izquierdo: Imagen
11281128 self .image_label = ZoomableClickableLabel (self .original_path , self )
11291129 self .image_label .is_thumbnail_view = False
11301130 self .main_splitter .addWidget (self .image_label )
1131+
1132+ # Panel Derecho: Solo fechas (SIN EXIF)
11311133 right_panel_widget = QWidget ()
11321134 right_panel_layout = QVBoxLayout (right_panel_widget )
1133- right_panel_widget .setMinimumWidth (300 )
1134- right_panel_widget .setMaximumWidth (450 )
1135- date_group = QGroupBox ("Fecha (Base de Datos)" )
1135+ right_panel_widget .setMinimumWidth (250 )
1136+ right_panel_widget .setMaximumWidth (350 )
1137+
1138+ date_group = QGroupBox ("Editar Fecha" )
11361139 date_layout = QGridLayout (date_group )
1140+
11371141 date_layout .addWidget (QLabel ("Año:" ), 0 , 0 )
11381142 self .year_edit = QLineEdit ()
1139- self .year_edit .setPlaceholderText ("Ej: 2024 o 'Sin Fecha' " )
1143+ self .year_edit .setPlaceholderText ("Ej: 2024" )
11401144 date_layout .addWidget (self .year_edit , 0 , 1 )
1145+
11411146 date_layout .addWidget (QLabel ("Mes:" ), 1 , 0 )
11421147 self .month_combo = QComboBox ()
11431148 self .month_combo .addItem ("Mes Desconocido" , "00" )
@@ -1146,121 +1151,91 @@ def _setup_ui(self):
11461151 try :
11471152 month_name = datetime .datetime .strptime (month_str , "%m" ).strftime ("%B" ).capitalize ()
11481153 except ValueError :
1149- month_name = datetime . date ( 2000 , i , 1 ). strftime ( "%B" ). capitalize ( )
1154+ month_name = str ( i )
11501155 self .month_combo .addItem (month_name , month_str )
11511156 date_layout .addWidget (self .month_combo , 1 , 1 )
1152- exif_group = QGroupBox ("Datos EXIF (Solo Lectura)" )
1153- exif_layout = QVBoxLayout (exif_group )
1154- self .metadata_table = QTableWidget ()
1155- self .metadata_table .setColumnCount (2 )
1156- self .metadata_table .setHorizontalHeaderLabels (["Campo" , "Valor" ])
1157- self .metadata_table .horizontalHeader ().setSectionResizeMode (0 , QHeaderView .ResizeMode .ResizeToContents )
1158- self .metadata_table .horizontalHeader ().setSectionResizeMode (1 , QHeaderView .ResizeMode .Stretch )
1159- self .metadata_table .setEditTriggers (QAbstractItemView .EditTrigger .NoEditTriggers )
1160- exif_layout .addWidget (self .metadata_table )
1157+
11611158 right_panel_layout .addWidget (date_group )
1162- right_panel_layout .addWidget (exif_group , 1 )
1159+ right_panel_layout .addStretch (1 ) # Relleno para empujar hacia arriba
1160+
11631161 self .main_splitter .addWidget (right_panel_widget )
1162+
1163+ # Botones
11641164 self .button_box = QDialogButtonBox (QDialogButtonBox .StandardButton .Save | QDialogButtonBox .StandardButton .Cancel )
11651165 self .button_box .accepted .connect (self ._save_metadata )
11661166 self .button_box .rejected .connect (self .reject )
11671167 main_layout .addWidget (self .button_box )
1168- self .main_splitter .setSizes ([int (self .width () * 0.7 ), int (self .width () * 0.3 )])
1168+
1169+ # Ajuste de tamaños (más espacio para la foto)
1170+ self .main_splitter .setSizes ([800 , 250 ])
1171+
11691172 def __init__ (self , original_path , db_manager : VisageVaultDB , parent = None ):
11701173 super ().__init__ (parent )
11711174 self .original_path = original_path
11721175 self .db = db_manager
1173- self .exif_dict = {}
1174- self .date_time_tag_info = None
11751176 self .setWindowTitle (Path (original_path ).name )
11761177 self .resize (1000 , 800 )
1178+
11771179 self ._setup_ui ()
11781180 self ._load_photo ()
1179- self ._load_metadata ()
1181+ self ._load_current_date () # Renombrado de _load_metadata
1182+
11801183 def _load_photo (self ):
1184+ # ... (MANTENER EL CÓDIGO DE CARGA DE IMAGEN/RAW IGUAL QUE ANTES) ...
1185+ # (No copies esto, solo deja el método _load_photo tal cual lo tenías)
11811186 try :
1182- # Definir extensiones RAW (deben coincidir con las de los otros archivos)
1187+ # Definir extensiones RAW
11831188 RAW_EXTENSIONS = ('.nef' , '.cr2' , '.cr3' , '.crw' , '.arw' , '.srf' , '.orf' , '.rw2' , '.raf' , '.pef' , '.dng' , '.raw' )
11841189 file_suffix = Path (self .original_path ).suffix .lower ()
1185- pixmap = QPixmap () # Empezar con un pixmap vacío
1190+ pixmap = QPixmap ()
11861191
11871192 if file_suffix in RAW_EXTENSIONS :
1188- # 1. Usar rawpy para leer el archivo RAW
11891193 with rawpy .imread (self .original_path ) as raw :
1190- # postprocess() aplica correcciones de color y devuelve un array numpy (H, W, 3)
11911194 rgb_array = raw .postprocess ()
1192-
1193- # 2. Convertir el array de numpy a QImage
11941195 height , width , channel = rgb_array .shape
11951196 bytes_per_line = 3 * width
1196- # .copy() es crucial para que QImage tome propiedad de los datos
11971197 q_image = QImage (rgb_array .data , width , height , bytes_per_line , QImage .Format .Format_RGB888 ).copy ()
1198-
1199- # 3. Convertir QImage a QPixmap
12001198 pixmap = QPixmap .fromImage (q_image )
1201-
12021199 else :
1203- # 4. Lógica original para JPG, PNG, etc.
12041200 pixmap = QPixmap (self .original_path )
12051201
1206- if pixmap .isNull ():
1207- raise Exception ("QPixmap está vacío después de cargar (formato no soportado o archivo corrupto)." )
1208-
12091202 self .image_label .setOriginalPixmap (pixmap )
1210-
12111203 except Exception as e :
1212- print (f"Error detallado al cargar { self .original_path } : { e } " )
1213- self .image_label .setText (f"Error al cargar imagen: { e } " )
1204+ self .image_label .setText (f"Error: { e } " )
12141205
1215- def _load_metadata (self ):
1216- self .exif_dict = metadata_reader .get_exif_dict (self .original_path )
1217- self .metadata_table .setRowCount (0 )
1206+ def _load_current_date (self ):
1207+ """Carga solo la fecha actual de la BD o del archivo."""
12181208 current_year , current_month = self .db .get_photo_date (self .original_path )
1209+
1210+ # Si no está en BD, usar la función simple de metadata_reader
12191211 if current_year is None or current_month is None :
1220- exif_year , exif_month = metadata_reader .get_photo_date (self .original_path )
1221- if current_year is None :
1222- current_year = exif_year
1223- if current_month is None :
1224- current_month = exif_month
1212+ current_year , current_month = metadata_reader .get_photo_date (self .original_path )
1213+
12251214 self .year_edit .setText (current_year or "Sin Fecha" )
12261215 month_index = self .month_combo .findData (current_month or "00" )
12271216 self .month_combo .setCurrentIndex (month_index if month_index != - 1 else 0 )
1228- if not self .exif_dict :
1229- self .metadata_table .insertRow (0 )
1230- self .metadata_table .setItem (0 , 0 , QTableWidgetItem ("Info" ))
1231- self .metadata_table .setItem (0 , 1 , QTableWidgetItem ("No se encontraron metadatos EXIF." ))
1232- return
1233- row = 0
1234- for ifd_name , tags in self .exif_dict .items ():
1235- if not isinstance (tags , dict ): continue
1236- for tag_id , value in tags .items ():
1237- self .metadata_table .insertRow (row )
1238- tag_name = piexif .TAGS [ifd_name ].get (tag_id , {"name" : f"UnknownTag_{ tag_id } " })["name" ]
1239- if isinstance (value , bytes ):
1240- try : value_str = piexif .helper .decode_bytes (value )
1241- except : value_str = str (value )
1242- else :
1243- value_str = str (value )
1244- self .metadata_table .setItem (row , 0 , QTableWidgetItem (tag_name ))
1245- self .metadata_table .setItem (row , 1 , QTableWidgetItem (value_str ))
1246- row += 1
1217+
12471218 def _save_metadata (self ):
1219+ # ... (MANTENER IGUAL QUE ANTES) ...
1220+ # Solo cambia la BD, lo cual es correcto según tus instrucciones.
12481221 try :
12491222 new_year_str = self .year_edit .text ()
12501223 new_month_str = self .month_combo .currentData ()
1224+
1225+ # Validación simple
12511226 if not (new_year_str == "Sin Fecha" or (len (new_year_str ) == 4 and new_year_str .isdigit ())):
12521227 from PySide6 .QtWidgets import QMessageBox
1253- QMessageBox .warning (self ,
1254- "Datos Inválidos" ,
1255- "El Año debe ser 'Sin Fecha' o un número de 4 dígitos (ej: 2024)." )
1228+ QMessageBox .warning (self , "Datos Inválidos" , "Año inválido." )
12561229 return
1257- old_year , old_month = self .db .get_photo_date (self .original_path )
1258- if old_year != new_year_str or old_month != new_month_str :
1259- self .db .update_photo_date (self .original_path , new_year_str , new_month_str )
1260- self .metadata_changed .emit (self .original_path , new_year_str , new_month_str )
1230+
1231+ # Guardar en BD
1232+ self .db .update_photo_date (self .original_path , new_year_str , new_month_str )
1233+
1234+ # Notificar cambio
1235+ self .metadata_changed .emit (self .original_path , new_year_str , new_month_str )
12611236 self .accept ()
12621237 except Exception as e :
1263- print (f"Error al guardar la fecha en la BD : { e } " )
1238+ print (f"Error al guardar: { e } " )
12641239
12651240# =================================================================
12661241# CLASE: DIÁLOGO DE ETIQUETADO DE GRUPOS (CLUSTERS) (Sin cambios)
@@ -3571,19 +3546,6 @@ def _finish_cloud_preview(self, local_path):
35713546 self ._set_status ("Imagen descargada. Abriendo visor..." )
35723547 self ._open_preview_dialog (local_path )
35733548
3574- def _download_for_preview (self , file_id , local_path ):
3575- """Descarga y abre el diálogo de vista previa rápida."""
3576- try :
3577- local_manager = DriveManager ()
3578- local_manager .download_file (file_id , local_path )
3579-
3580- # Abrir la vista previa (ImagePreviewDialog) en el hilo principal
3581- QTimer .singleShot (0 , lambda : self ._open_preview_dialog (local_path ))
3582- QTimer .singleShot (0 , lambda : self ._set_status ("Vista previa lista." ))
3583- except Exception as e :
3584- print (f"Error descarga preview: { e } " )
3585- QTimer .singleShot (0 , lambda : self ._set_status ("Error al descargar para vista previa." ))
3586-
35873549 @Slot (QListWidgetItem )
35883550 def _on_drive_item_double_clicked (self , item ):
35893551 file_data = item .data (Qt .UserRole )
@@ -4882,17 +4844,6 @@ def _on_drive_scan_finished(self, total_count):
48824844
48834845 self ._set_status (f"Listo. { self .cloud_photo_count } fotos disponibles." )
48844846
4885- @Slot (list )
4886- def _add_drive_items (self , items ):
4887- """
4888- Solo actualiza la estructura en memoria (RAM).
4889- La inserción en BD ya la hizo el worker.
4890- """
4891- # ELIMINADO: self.db.bulk_upsert_drive_photos(...) <- Esto congelaba la UI
4892-
4893- self ._classify_drive_items_in_memory (items )
4894- self ._set_status (f"Sincronizando... { self .cloud_photo_count } fotos procesadas." )
4895-
48964847 def _display_cloud_photos (self ):
48974848 """Dibuja la interfaz de Nube EXACTAMENTE igual que Fotos (Estilo nativo)."""
48984849
@@ -5003,41 +4954,6 @@ def _display_cloud_photos(self):
50034954 self .cloud_container_layout .addStretch (1 )
50044955 QTimer .singleShot (100 , self ._load_visible_cloud_thumbnails )
50054956
5006- @Slot (QTreeWidgetItem , QTreeWidgetItem )
5007- def _scroll_to_cloud_item (self , current , previous ):
5008- """Navegación rápida al hacer clic en el árbol de fechas."""
5009- if not current : return
5010-
5011- key = ""
5012- if current .parent (): # Es un mes
5013- key = current .data (0 , Qt .UserRole ) # "2023-05"
5014- else : # Es un año
5015- key = current .text (0 ) # "2023"
5016-
5017- target_widget = self .cloud_group_widgets .get (key )
5018- if target_widget :
5019- self .cloud_scroll_area .ensureWidgetVisible (target_widget , 0 , 0 )
5020- # Forzar carga de miniaturas en la nueva posición
5021- QTimer .singleShot (200 , self ._load_visible_cloud_thumbnails )
5022-
5023- # ----------------------------------------------------------------------
5024- # FUNCIONES AUXILIARES QUE FALTAN (Pegar dentro de VisageVaultApp)
5025- # ----------------------------------------------------------------------
5026-
5027- def _calculate_list_height (self , num_items , icon_size , viewport_width ):
5028- """Calcula la altura necesaria para una lista sin scrollbar."""
5029- # Ajuste de márgenes (icono + padding)
5030- item_w = icon_size + 20
5031- item_h = icon_size + 40
5032-
5033- # Columnas que caben en el ancho actual
5034- cols = max (1 , (viewport_width - 30 ) // item_w )
5035-
5036- # Filas necesarias
5037- rows = (num_items + cols - 1 ) // cols
5038-
5039- return rows * item_h
5040-
50414957 @Slot (QTreeWidgetItem , QTreeWidgetItem )
50424958 def _scroll_to_cloud_item (self , current , previous ):
50434959 """Navegación rápida al hacer clic en el árbol de fechas."""
0 commit comments