diff --git a/.idea/MutiFunctionProgramProject.iml b/.idea/MutiFunctionProgramProject.iml
index 07abf20..d8b3f6c 100644
--- a/.idea/MutiFunctionProgramProject.iml
+++ b/.idea/MutiFunctionProgramProject.iml
@@ -2,11 +2,7 @@
-
+
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index db8786c..1d3ce46 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,7 +1,7 @@
-
+
-
+
\ No newline at end of file
diff --git a/src/resources/db_email/emails.db b/src/resources/db_email/emails.db
new file mode 100644
index 0000000..3e8da67
Binary files /dev/null and b/src/resources/db_email/emails.db differ
diff --git a/src/services/__pycache__/Radio_Player.cpython-313.pyc b/src/services/__pycache__/Radio_Player.cpython-313.pyc
index a2bbd35..74cb7f7 100644
Binary files a/src/services/__pycache__/Radio_Player.cpython-313.pyc and b/src/services/__pycache__/Radio_Player.cpython-313.pyc differ
diff --git a/src/services/__pycache__/email_client_pop.cpython-313.pyc b/src/services/__pycache__/email_client_pop.cpython-313.pyc
new file mode 100644
index 0000000..1cb6d17
Binary files /dev/null and b/src/services/__pycache__/email_client_pop.cpython-313.pyc differ
diff --git a/src/services/__pycache__/scrapper.cpython-313.pyc b/src/services/__pycache__/scrapper.cpython-313.pyc
index 6c9e88b..dc095e1 100644
Binary files a/src/services/__pycache__/scrapper.cpython-313.pyc and b/src/services/__pycache__/scrapper.cpython-313.pyc differ
diff --git a/src/services/__pycache__/tetris_game.cpython-313.pyc b/src/services/__pycache__/tetris_game.cpython-313.pyc
index 6610eca..3f8f3af 100644
Binary files a/src/services/__pycache__/tetris_game.cpython-313.pyc and b/src/services/__pycache__/tetris_game.cpython-313.pyc differ
diff --git a/src/services/__pycache__/threads_manager.cpython-313.pyc b/src/services/__pycache__/threads_manager.cpython-313.pyc
index 103a7ae..1040893 100644
Binary files a/src/services/__pycache__/threads_manager.cpython-313.pyc and b/src/services/__pycache__/threads_manager.cpython-313.pyc differ
diff --git a/src/services/email_client_pop.py b/src/services/email_client_pop.py
index 5c6ce9d..11cc23d 100644
--- a/src/services/email_client_pop.py
+++ b/src/services/email_client_pop.py
@@ -8,10 +8,11 @@ from email.mime.multipart import MIMEMultipart
import sqlite3
from datetime import datetime
+
class EmailClientPOP:
- def __init__(self, pop_server, smtp_server, email, password, pop_port = 110, smtp_port=25):
+ def __init__(self, pop_server, smtp_server, email, password, pop_port=110, smtp_port=25):
self.pop_server = pop_server
- self.smtp = smtp_server
+ self.smtp_server = smtp_server
self.email = email
self.password = password
self.pop_port = pop_port
@@ -19,7 +20,7 @@ class EmailClientPOP:
self.pop_conn = None
self.smtp_conn = None
- #Ruta del archivo SQLite:
+ # Ruta del archivo SQLite:
self.db_file = os.path.join("resources/db_email", "emails.db")
self.init_database()
@@ -40,8 +41,169 @@ class EmailClientPOP:
received_at DATETIME
)
""")
+ cursor.execute("""
+ CREATE TABLE IF NOT EXISTS sent_emails (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ recipient TEXT NOT NULL,
+ subject TEXT,
+ body TEXT,
+ sent_at DATETIME
+ )
+ """)
conn.commit()
conn.close()
print(f"Base de datos inicializada: {self.db_file}")
except sqlite3.Error as e:
- print(f"Error al inicializar la base de datos: {e}")
\ No newline at end of file
+ print(f"Error al inicializar la base de datos: {e}")
+
+ def connect_pop(self):
+ """Conexión al servidor POP"""
+ try:
+ self.pop_conn = poplib.POP3(self.pop_server, self.pop_port)
+ self.pop_conn.user(self.email)
+ self.pop_conn.pass_(self.password)
+ print("Conexión POP exitosa")
+ except Exception as e:
+ print(f"Error al conectar al servidor POP: {e}")
+ self.pop_conn = None
+
+ def connect_smtp(self):
+ """Conexión al servidor SMTP"""
+ try:
+ self.smtp_conn = smtplib.SMTP(self.smtp_server, self.smtp_port)
+ self.smtp_conn.login(self.email, self.password)
+ print("Conexión SMTP exitosa")
+ except Exception as e:
+ print(f"Error al conectar al servidor SMTP: {e}")
+ self.smtp_conn = None
+
+ def is_connected(self):
+ """Verifica si hay una conexión válida tanto de POP como de SMTP"""
+ return self.pop_conn is not None and self.smtp_conn is not None
+
+ def reconnect(self):
+ """Intenta reconectar a los servidores POP y SMTP"""
+ print("Intentando reconectar al servidor de correo...")
+ self.connect_pop()
+ self.connect_smtp()
+
+ def fetch_unread_count(self):
+ """Obtener el número de correos (POP3 no distingue entre leídos y no leídos)"""
+ try:
+ if not self.pop_conn:
+ self.connect_pop()
+ num_messages = len(self.pop_conn.list()[1])
+ return num_messages # Total de mensajes
+ except Exception as e:
+ print(f"Error al obtener el conteo de correos: {e}")
+ return 0
+
+ def fetch_emails(self, save_to_db=True):
+ """Obtiene correos desde el servidor POP"""
+ try:
+ if not self.pop_conn:
+ self.connect_pop()
+
+ emails = []
+ num_messages = len(self.pop_conn.list()[1])
+ for i in range(1, num_messages + 1):
+ raw_messages = b"\n".join(self.pop_conn.retr(i)[1])
+ msg = email.message_from_bytes(raw_messages)
+ subject, encoding = decode_header(msg["Subject"])[0]
+ if isinstance(subject, bytes):
+ subject = subject.decode(encoding or "utf-8")
+ sender = msg.get("From")
+ body = ""
+ if msg.is_multipart():
+ for part in msg.walk():
+ if part.get_content_type() == "text/plain":
+ body = part.get_payload(decode=True).decode("utf-8", errors="ignore")
+ else:
+ body = msg.get_payload(decode=True).decode("utf-8", errors="ignore")
+
+ email_data = {
+ "sender": sender,
+ "subject": subject,
+ "body": body,
+ "received_at": datetime.now().isoformat()
+ }
+ emails.append(email_data)
+
+ if save_to_db:
+ self.save_email_to_db(email_data)
+
+ return emails
+ except Exception as e:
+ print(f"Error al obtener los correos: {e}")
+ return []
+
+ def fetch_folders(self):
+ """POP3 no tiene carpetas, devuelve un mensaje indicando esto"""
+ print("El protocolo POP3 no soporta carpetas. Devuelve solo la bandeja de entrada.")
+ return ["INBOX"]
+
+ def save_email_to_db(self, email_data):
+ """Guarda un correo recibido en la base de datos."""
+ try:
+ conn = sqlite3.connect(self.db_file)
+ cursor = conn.cursor()
+ cursor.execute("""
+ INSERT INTO emails (sender, subject, body, received_at)
+ VALUES (?, ?, ?, ?)
+ """, (email_data["sender"], email_data["subject"], email_data["body"], email_data["received_at"]))
+ conn.commit()
+ conn.close()
+ print("Correo recibido guardado en la base de datos.")
+ except sqlite3.Error as e:
+ print(f"Error al guardar correo recibido: {e}")
+
+ def send_mail(self, recipient, subject, body, save_to_db=True):
+ """Envía un correo usando SMTP"""
+ try:
+ if not self.smtp_conn:
+ self.connect_smtp()
+
+ msg = MIMEMultipart()
+ msg["From"] = self.email
+ msg["To"] = recipient
+ msg["Subject"] = subject
+ msg.attach(MIMEText(body, "plain"))
+ self.smtp_conn.sendmail(self.email, recipient, msg.as_string())
+ print(f"Correo ha sido enviado a {recipient}")
+
+ if save_to_db:
+ self.save_sent_mail_to_db({
+ "recipient": recipient,
+ "subject": subject,
+ "body": body,
+ "sent_at": datetime.now().isoformat()
+ })
+ except Exception as e:
+ print(f"Error al enviar correo: {e}")
+
+ def save_sent_mail_to_db(self, email_data):
+ """Guarda un correo enviado en la base de datos."""
+ try:
+ conn = sqlite3.connect(self.db_file)
+ cursor = conn.cursor()
+ cursor.execute("""
+ INSERT INTO sent_emails (recipient, subject, body, sent_at)
+ VALUES (?, ?, ?, ?)
+ """, (email_data["recipient"], email_data["subject"], email_data["body"], email_data["sent_at"]))
+ conn.commit()
+ conn.close()
+ print("Correo enviado guardado en la base de datos.")
+ except sqlite3.Error as e:
+ print(f"Error al guardar correo enviado: {e}")
+
+ def list_emails(self, limit=10):
+ """Lista correos recientes (máximo `limit`)"""
+ emails = self.fetch_emails()
+ return emails[:limit]
+
+ def close_connections(self):
+ """Cierra las conexiones POP y SMTP"""
+ if self.pop_conn:
+ self.pop_conn.quit()
+ if self.smtp_conn:
+ self.smtp_conn.quit()
diff --git a/src/ui/__pycache__/centered_window.cpython-313.pyc b/src/ui/__pycache__/centered_window.cpython-313.pyc
index 20a2c4c..ed43031 100644
Binary files a/src/ui/__pycache__/centered_window.cpython-313.pyc and b/src/ui/__pycache__/centered_window.cpython-313.pyc differ
diff --git a/src/ui/centered_window.py b/src/ui/centered_window.py
index b893300..555ff3d 100644
--- a/src/ui/centered_window.py
+++ b/src/ui/centered_window.py
@@ -6,7 +6,7 @@ from src.services.processes_manager import ProcessManager
from src.services.system_monitor import SystemMonitor
from src.services.tetris_game import TetrisGame
from src.services.threads_manager import ThreadsManager
-from src.services.email_client_imap import EmailClientImap
+from src.services.email_client_pop import EmailClientPOP
class CenteredWindow(ctk.CTk):
@@ -16,9 +16,9 @@ class CenteredWindow(ctk.CTk):
self.title(title)
self.after_tasks = []
- #Configurar Email Client
- self.email_client = EmailClientImap(
- imap_server="192.168.120.103",
+ # Configurar Email Client IMAP
+ self.email_client = EmailClientPOP(
+ pop_server="192.168.120.103",
smtp_server="192.168.120.103",
email="dennis@psp.ieslamar.org",
password="1234"
@@ -28,21 +28,21 @@ class CenteredWindow(ctk.CTk):
self.process_manager = ProcessManager()
self.system_monitor = None
- # Obtener la resolucion de la pantalla:
+ # Obtener la resolución de la pantalla:
screen_width = self.winfo_screenwidth()
screen_height = self.winfo_screenheight()
- # Calcula el tamaño de la ventana según procentaje de la pantalla:
+ # Calcula el tamaño de la ventana según porcentaje de la pantalla:
window_width = int(screen_width * width_percentage)
window_height = int(screen_height * height_percentage)
- # Calcular la posicion para centrar la ventana:
+ # Calcular la posición para centrar la ventana:
position_x = (screen_width - window_width) // 2
position_y = (screen_height - window_height) // 2
self.geometry(f"{window_width}x{window_height}+{position_x}+{position_y}")
- #Configura la ventana
+ # Configura la ventana
self.configure_window()
self.protocol("WM_DELETE_WINDOW", self.on_close)
@@ -62,7 +62,6 @@ class CenteredWindow(ctk.CTk):
self.thread_manager.start_threads()
-
def on_close(self):
"""Maneja el cierre de la ventana"""
self.thread_manager.stop_threads()
@@ -70,7 +69,7 @@ class CenteredWindow(ctk.CTk):
if hasattr(self, "tetris_game") and self.tetris_game.running:
self.tetris_game.stop_game()
- if "tetris_game" in self.thread_manager.tasks:
+ if "tetris_game" in self.thread_manager.tasks:
self.thread_manager.tasks["tetris_game"].stop()
if hasattr(self.thread_manager, "scrapper"):
@@ -91,10 +90,16 @@ class CenteredWindow(ctk.CTk):
# Secciones y botones
sections = {
"Aplicaciones": [
- ("Abrir Chrome", lambda: self.process_manager.open_resource("browser", "https://google.com", "Cannot open browser")),
- ("Visual Studio Code", lambda: self.process_manager.open_resource("program", r"C:\Program Files\Microsoft VS Code\Code.exe", "Can't find VSCode")),
- ("Explorador de Windows", lambda: self.process_manager.open_resource("program", "explorer.exe", "Can't open Windows Explorer")),
- ("Notepad++", lambda: self.process_manager.open_resource("program", r"C:\Program Files\Notepad++\notepad++.exe", "Can't open Notepad++"))
+ ("Abrir Chrome",
+ lambda: self.process_manager.open_resource("browser", "https://google.com", "Cannot open browser")),
+ ("Visual Studio Code",
+ lambda: self.process_manager.open_resource("program", r"C:\Program Files\Microsoft VS Code\Code.exe",
+ "Can't find VSCode")),
+ ("Explorador de Windows",
+ lambda: self.process_manager.open_resource("program", "explorer.exe", "Can't open Windows Explorer")),
+ ("Notepad++",
+ lambda: self.process_manager.open_resource("program", r"C:\Program Files\Notepad++\notepad++.exe",
+ "Can't open Notepad++"))
]
}
@@ -104,13 +109,13 @@ class CenteredWindow(ctk.CTk):
url_entry_chrome.pack(pady=5, padx=10)
# Botón para abrir la URL ingresada
- internet_access_button = ctk.CTkButton(
- left_panel,
- text="Buscar URL",
- command=lambda: self.process_manager.open_resource("browser", url_entry_chrome.get(), "Cannot open browser")
- )
+ internet_access_button = ctk.CTkButton(
+ left_panel,
+ text="Buscar URL",
+ command=lambda: self.process_manager.open_resource("browser", url_entry_chrome.get(), "Cannot open browser")
+ )
internet_access_button.pack(pady=5, padx=10)
-
+
for section, buttons in sections.items():
if section:
section_label = ctk.CTkLabel(left_panel, text=section, font=("Arial", 12, "bold"))
@@ -122,20 +127,20 @@ class CenteredWindow(ctk.CTk):
scrapping_label = ctk.CTkLabel(left_panel, text="Scrapping", font=("Arial", 12, "bold"))
scrapping_label.pack(anchor=ctk.W, pady=5, padx=10)
- url_entry = ctk.CTkEntry(left_panel, placeholder_text="Introduce la URL para scrapear")
- url_entry.pack(pady=5, padx=10)
+ url_entry = ctk.CTkEntry(left_panel, placeholder_text="Introduce la URL para scrapear")
+ url_entry.pack(pady=5, padx=10)
self.left_panel = left_panel
self.left_panel.url_entry = url_entry
self.left_panel.url_entry_chrome = url_entry_chrome
- start_button = ctk.CTkButton(left_panel, text="Iniciar Scrapping", command=self.thread_manager.scrapper.start_scraping)
+ start_button = ctk.CTkButton(left_panel, text="Iniciar Scrapping",
+ command=self.thread_manager.scrapper.start_scraping)
start_button.pack(pady=5, padx=10)
- stop_button = ctk.CTkButton(left_panel, text="Detener Scrapping", command=self.thread_manager.scrapper.stop_scraping)
+ stop_button = ctk.CTkButton(left_panel, text="Detener Scrapping",
+ command=self.thread_manager.scrapper.stop_scraping)
stop_button.pack(pady=5, padx=10)
-
-
def create_center_panel(self):
# Panel central con pestañas
center_panel = ctk.CTkFrame(self)
@@ -147,9 +152,12 @@ class CenteredWindow(ctk.CTk):
# Crear pestañas y manejar contenido por separado
for tab_name in ["Scrapping", "Radio", "Correos", "Juego", "Sistema"]:
tab = tab_view.add(tab_name)
-
- if tab_name == "Radio":
- self.create_radio_tab(tab)
+
+ if tab_name == "Radio":
+ self.create_radio_tab(tab)
+
+ if tab_name == "Correos":
+ self.create_email_tab(tab)
if tab_name == "Scrapping":
text_widget = ctk.CTkTextbox(tab, width=500, height=400)
@@ -161,11 +169,11 @@ class CenteredWindow(ctk.CTk):
if tab_name == "Sistema":
# Crear un frame para los gráficos del sistema
- system_frame = ctk.CTkFrame(tab)
- system_frame.pack(fill=ctk.BOTH, expand=True, padx=5, pady=5)
+ system_frame = ctk.CTkFrame(tab)
+ system_frame.pack(fill=ctk.BOTH, expand=True, padx=5, pady=5)
# Inicializar SystemMonitor con el frame de la pestaña
- self.system_monitor = SystemMonitor(system_frame)
+ self.system_monitor = SystemMonitor(system_frame)
# Asignar el system_monitor al thread_manager
self.thread_manager.set_system_monitor(self.system_monitor)
@@ -192,33 +200,25 @@ class CenteredWindow(ctk.CTk):
self.tetris_game = TetrisGame(game_frame)
self.tetris_game.pack()
- # else:
- # Agregar contenido genérico a otras pestañas
- #label = ctk.CTkLabel(tab, text=f"Contenido de {tab_name}", font=("Arial", 12))
- #label.pack(pady=10)
-
-
+ # else:
+ # Agregar contenido genérico a otras pestañas
+ # label = ctk.CTkLabel(tab, text=f"Contenido de {tab_name}", font=("Arial", 12))
+ # label.pack(pady=10)
def start_tetris_game(self):
"""Método para iniciar el juego."""
if not self.tetris_game.running:
self.tetris_game.running = True
- #self.tetris_game.update_game()
-
-
+ # self.tetris_game.update_game()
def pause_tetris_game(self):
"""Método para pausar el juego."""
self.tetris_game.running = False
-
-
def restart_tetris_game(self):
"""Método para reiniciar el juego."""
self.tetris_game.reset_game()
-
-
def create_right_panel(self):
# Panel derecho
right_panel = ctk.CTkFrame(self, width=250)
@@ -236,7 +236,8 @@ class CenteredWindow(ctk.CTk):
# Lista de alumnos
for i in range(1, 4):
- student_label = ctk.CTkLabel(right_panel, text=f"Alumno {i}", font=("Arial", 12, "bold"), text_color="black")
+ student_label = ctk.CTkLabel(right_panel, text=f"Alumno {i}", font=("Arial", 12, "bold"),
+ text_color="black")
student_label.pack(anchor=ctk.W, pady=5, padx=10)
student_info = ctk.CTkLabel(
@@ -247,8 +248,6 @@ class CenteredWindow(ctk.CTk):
)
student_info.pack(anchor=ctk.W, padx=10)
-
-
def create_bottom_bar(self):
# Crear la barra inferior
self.bottom_bar = ctk.CTkFrame(self, fg_color="lightblue", height=40)
@@ -258,7 +257,8 @@ class CenteredWindow(ctk.CTk):
self.info_labels = {
"hora": ctk.CTkLabel(self.bottom_bar, text="Hora: --:--:--", font=("Arial", 12), text_color="black"),
"fecha": ctk.CTkLabel(self.bottom_bar, text="Fecha: --/--/----", font=("Arial", 12), text_color="black"),
- "temperatura": ctk.CTkLabel(self.bottom_bar, text="Temperatura local: --°C", font=("Arial", 12), text_color="black"),
+ "temperatura": ctk.CTkLabel(self.bottom_bar, text="Temperatura local: --°C", font=("Arial", 12),
+ text_color="black"),
"emails": ctk.CTkLabel(self.bottom_bar, text="Correos sin leer: 0", font=("Arial", 12), text_color="black"),
}
@@ -266,58 +266,141 @@ class CenteredWindow(ctk.CTk):
for label in self.info_labels.values():
label.pack(side=ctk.LEFT, padx=10, pady=5)
-
-
def dummy_action(self):
print("Acción no implementada")
-
- def create_radio_tab(self, tab):
- """Crea la interfaz para la funcionalidad de emisoras de radio."""
- self.radio_player = self.thread_manager.radio_player
+
+ def create_radio_tab(self, tab):
+ """Crea la interfaz para la funcionalidad de emisoras de radio."""
+ self.radio_player = self.thread_manager.radio_player
# Lista de emisoras
- radio_stations = {
- "Box Radio UK": "http://uk2.internet-radio.com:8024/",
- "Jazz Radio": "http://us2.internet-radio.com:8443/",
- "Deep House Radio": "http://uk7.internet-radio.com:8000/",
- }
+ radio_stations = {
+ "Box Radio UK": "http://uk2.internet-radio.com:8024/",
+ "Jazz Radio": "http://us2.internet-radio.com:8443/",
+ "Deep House Radio": "http://uk7.internet-radio.com:8000/",
+ }
# Dropdown para seleccionar emisora
- self.selected_station = ctk.StringVar(value="Selecciona una emisora")
- station_menu = ctk.CTkOptionMenu(tab, variable=self.selected_station, values=list(radio_stations.keys()))
- station_menu.pack(pady=10)
+ self.selected_station = ctk.StringVar(value="Selecciona una emisora")
+ station_menu = ctk.CTkOptionMenu(tab, variable=self.selected_station, values=list(radio_stations.keys()))
+ station_menu.pack(pady=10)
# Botón para reproducir
- play_button = ctk.CTkButton(
- tab,
- text="Reproducir",
- command=lambda: self.start_radio(radio_stations[self.selected_station.get()])
- )
- play_button.pack(pady=5)
+ play_button = ctk.CTkButton(
+ tab,
+ text="Reproducir",
+ command=lambda: self.start_radio(radio_stations[self.selected_station.get()])
+ )
+ play_button.pack(pady=5)
# Botón para detener
- stop_button = ctk.CTkButton(
- tab,
- text="Detener",
- command=self.stop_radio,
+ stop_button = ctk.CTkButton(
+ tab,
+ text="Detener",
+ command=self.stop_radio,
state=tk.DISABLED # Deshabilitado inicialmente
- )
- stop_button.pack(pady=5)
+ )
+ stop_button.pack(pady=5)
# Guardar referencias para habilitar/deshabilitar botones
- self.radio_controls = {"play_button": play_button, "stop_button": stop_button}
+ self.radio_controls = {"play_button": play_button, "stop_button": stop_button}
- def start_radio(self, url):
- """Inicia la reproducción de radio y actualiza los botones."""
- if url == "Selecciona una emisora":
- tk.messagebox.showwarning("Advertencia", "Por favor, selecciona una emisora válida.")
- return
- self.radio_player.play(url)
- self.radio_controls["play_button"].configure(state=tk.DISABLED)
- self.radio_controls["stop_button"].configure(state=tk.NORMAL)
+ def start_radio(self, url):
+ """Inicia la reproducción de radio y actualiza los botones."""
+ if url == "Selecciona una emisora":
+ tk.messagebox.showwarning("Advertencia", "Por favor, selecciona una emisora válida.")
+ return
+ self.radio_player.play(url)
+ self.radio_controls["play_button"].configure(state=tk.DISABLED)
+ self.radio_controls["stop_button"].configure(state=tk.NORMAL)
- def stop_radio(self):
- """Detiene la reproducción de radio y actualiza los botones."""
- self.radio_player.stop()
- self.radio_controls["play_button"].configure(state=tk.NORMAL)
- self.radio_controls["stop_button"].configure(state=tk.DISABLED)
\ No newline at end of file
+ def stop_radio(self):
+ """Detiene la reproducción de radio y actualiza los botones."""
+ self.radio_player.stop()
+ self.radio_controls["play_button"].configure(state=tk.NORMAL)
+ self.radio_controls["stop_button"].configure(state=tk.DISABLED)
+
+ def create_email_tab(self, tab):
+ """Crea una interfaz moderna para gestionar los correos con customtkinter."""
+ # Configurar el grid para permitir que los elementos se expandan
+ tab.grid_columnconfigure(0, weight=1)
+ tab.grid_rowconfigure(0, weight=1)
+
+ # Crear un marco principal para la pestaña
+ main_frame = ctk.CTkFrame(tab)
+ main_frame.grid(row=0, column=0, sticky="nsew", padx=10, pady=10)
+
+ # Lista de correos en un marco
+ listbox_frame = ctk.CTkFrame(main_frame)
+ listbox_frame.grid(row=0, column=0, sticky="nsew", padx=10, pady=10)
+
+ # Crear una lista de correos con un scrollbar
+ self.email_listbox = ctk.CTkTextbox(listbox_frame, width=800, height=800)
+ self.email_listbox.grid(row=0, column=0, sticky="nsew", padx=10, pady=10)
+ self.email_listbox.configure(state="disabled") # Inicialmente deshabilitada
+
+ scrollbar = ctk.CTkScrollbar(listbox_frame, command=self.email_listbox.yview)
+ scrollbar.grid(row=0, column=1, sticky="ns")
+ self.email_listbox.configure(yscrollcommand=scrollbar.set)
+
+ # Frame para botones de acción
+ button_frame = ctk.CTkFrame(main_frame)
+ button_frame.grid(row=1, column=0, sticky="ew", padx=10, pady=10)
+
+ # Crear botones para acciones: Marcar como leído, Eliminar, Actualizar
+ mark_read_button = ctk.CTkButton(
+ button_frame, text="Marcar como leído", command=self.mark_email_as_read, fg_color="green"
+ )
+ mark_read_button.grid(row=0, column=0, padx=5, pady=5, sticky="ew")
+
+ delete_button = ctk.CTkButton(
+ button_frame, text="Eliminar correo", command=self.delete_email, fg_color="red"
+ )
+ delete_button.grid(row=0, column=1, padx=5, pady=5, sticky="ew")
+
+ refresh_button = ctk.CTkButton(
+ button_frame, text="Actualizar", command=self.refresh_email_list, fg_color="blue"
+ )
+ refresh_button.grid(row=0, column=2, padx=5, pady=5, sticky="ew")
+
+ # Expandir las filas y columnas del marco principal
+ main_frame.grid_rowconfigure(0, weight=1)
+ main_frame.grid_columnconfigure(0, weight=1)
+
+ def refresh_email_list(self):
+ """Actualiza la lista de correos en la interfaz."""
+ try:
+ if not self.email_client.is_connected():
+ self.email_client.reconnect()
+
+ if self.email_client.is_connected():
+ emails = self.email_client.fetch_emails()
+ self.email_listbox.delete(0, tk.END)
+ for email in emails:
+ self.email_listbox.insert(tk.END, f"{email['subject']} - {email['from']}")
+ else:
+ print("No hay conexión al servidor de correo.")
+ except Exception as e:
+ print(f"Error al actualizar la lista de correos: {e}")
+
+ def mark_email_as_read(self):
+ """Marca el correo seleccionado como leído."""
+ selected_index = self.email_listbox.curselection()
+ if not selected_index:
+ print("No se ha seleccionado ningún correo.")
+ return
+
+ selected_email = self.email_listbox.get(selected_index)
+ # Aquí puedes agregar la lógica para marcar el correo como leído
+ print(f"Correo marcado como leído: {selected_email}")
+
+ def delete_email(self):
+ """Elimina el correo seleccionado."""
+ selected_index = self.email_listbox.curselection()
+ if not selected_index:
+ print("No se ha seleccionado ningún correo.")
+ return
+
+ selected_email = self.email_listbox.get(selected_index)
+ # Aquí puedes agregar la lógica para eliminar el correo
+ print(f"Correo eliminado: {selected_email}")