diff --git a/app/__pycache__/emailClient.cpython-313.pyc b/app/__pycache__/emailClient.cpython-313.pyc index 7fba0fa..9c7521f 100644 Binary files a/app/__pycache__/emailClient.cpython-313.pyc and b/app/__pycache__/emailClient.cpython-313.pyc differ diff --git a/app/__pycache__/emailTab.cpython-313.pyc b/app/__pycache__/emailTab.cpython-313.pyc index 3a44dad..fe807a5 100644 Binary files a/app/__pycache__/emailTab.cpython-313.pyc and b/app/__pycache__/emailTab.cpython-313.pyc differ diff --git a/app/__pycache__/game.cpython-313.pyc b/app/__pycache__/game.cpython-313.pyc index 2960753..b8d9c6c 100644 Binary files a/app/__pycache__/game.cpython-313.pyc and b/app/__pycache__/game.cpython-313.pyc differ diff --git a/app/__pycache__/gestor_tareas.cpython-313.pyc b/app/__pycache__/gestor_tareas.cpython-313.pyc index 70349d0..f7d04ca 100644 Binary files a/app/__pycache__/gestor_tareas.cpython-313.pyc and b/app/__pycache__/gestor_tareas.cpython-313.pyc differ diff --git a/app/__pycache__/graphics.cpython-313.pyc b/app/__pycache__/graphics.cpython-313.pyc index f983f7a..669e1d9 100644 Binary files a/app/__pycache__/graphics.cpython-313.pyc and b/app/__pycache__/graphics.cpython-313.pyc differ diff --git a/app/__pycache__/monitorization.cpython-313.pyc b/app/__pycache__/monitorization.cpython-313.pyc index e99ef99..0facb1c 100644 Binary files a/app/__pycache__/monitorization.cpython-313.pyc and b/app/__pycache__/monitorization.cpython-313.pyc differ diff --git a/app/__pycache__/panel_derecho.cpython-313.pyc b/app/__pycache__/panel_derecho.cpython-313.pyc index 86e2c71..4fe1c29 100644 Binary files a/app/__pycache__/panel_derecho.cpython-313.pyc and b/app/__pycache__/panel_derecho.cpython-313.pyc differ diff --git a/app/__pycache__/panel_izquierdo.cpython-313.pyc b/app/__pycache__/panel_izquierdo.cpython-313.pyc index b9542a7..2aa786a 100644 Binary files a/app/__pycache__/panel_izquierdo.cpython-313.pyc and b/app/__pycache__/panel_izquierdo.cpython-313.pyc differ diff --git a/app/__pycache__/scraping.cpython-313.pyc b/app/__pycache__/scraping.cpython-313.pyc index 0a019d2..6268993 100644 Binary files a/app/__pycache__/scraping.cpython-313.pyc and b/app/__pycache__/scraping.cpython-313.pyc differ diff --git a/app/__pycache__/todo_list.cpython-313.pyc b/app/__pycache__/todo_list.cpython-313.pyc index e57b98b..503c65f 100644 Binary files a/app/__pycache__/todo_list.cpython-313.pyc and b/app/__pycache__/todo_list.cpython-313.pyc differ diff --git a/app/email/__pycache__/emailClient.cpython-313.pyc b/app/email/__pycache__/emailClient.cpython-313.pyc new file mode 100644 index 0000000..1dc266f Binary files /dev/null and b/app/email/__pycache__/emailClient.cpython-313.pyc differ diff --git a/app/email/__pycache__/emailTab.cpython-313.pyc b/app/email/__pycache__/emailTab.cpython-313.pyc new file mode 100644 index 0000000..ec1f0e9 Binary files /dev/null and b/app/email/__pycache__/emailTab.cpython-313.pyc differ diff --git a/app/email/__pycache__/reciveEmailTab.cpython-313.pyc b/app/email/__pycache__/reciveEmailTab.cpython-313.pyc new file mode 100644 index 0000000..1c76d5d Binary files /dev/null and b/app/email/__pycache__/reciveEmailTab.cpython-313.pyc differ diff --git a/app/email/emailClient.py b/app/email/emailClient.py new file mode 100644 index 0000000..5d48c58 --- /dev/null +++ b/app/email/emailClient.py @@ -0,0 +1,133 @@ +# emailClient.py +import datetime +import smtplib +import imaplib +import email +from email.mime.text import MIMEText +from email.mime.multipart import MIMEMultipart +import threading +import traceback + +class EmailClient: + def __init__(self): + self.server_ip = "s1.ieslamar.org" + self.ports = { + "SMTP": 25, + "SMTP-S": 465, + "SMTP-SUBMISSION": 587, + "IMAP": 143, + "IMAP-S": 993 + } + + def enviar_correo(self, email_user, password, destinatario, asunto, mensaje): + def enviar(): + try: + with smtplib.SMTP(self.server_ip, self.ports["SMTP"], local_hostname="localhost") as smtp: + smtp.login(email_user, password) + msg = MIMEMultipart() + msg["From"] = email_user + msg["To"] = destinatario + msg["Subject"] = asunto + msg["Date"] = datetime.datetime.now().strftime("%a, %d %b %Y %H:%M:%S %z") + msg.attach(MIMEText(mensaje, "plain")) + + smtp.sendmail(email_user, destinatario, msg.as_string()) + print("Correo enviado correctamente.") + except Exception as e: + print(f"Error al enviar el correo: {e}") + traceback.print_exc() + + thread = threading.Thread(target=enviar) + thread.start() + + def recibir_correos(self, email_user, password, callback): + """Recupera todos los correos (leídos y no leídos) del buzón de entrada.""" + def recibir(): + try: + with imaplib.IMAP4_SSL(self.server_ip, self.ports["IMAP-S"]) as mail: + mail.login(email_user, password) + mail.select("inbox") + + status, mensajes = mail.search(None, 'ALL') # Obtener todos los correos + lista_mensajes = mensajes[0].split() + + correos = [] + for num in lista_mensajes: + # Obtener el mensaje completo junto con sus FLAGS + status, data = mail.fetch(num, '(RFC822 FLAGS)') + if not data or len(data) < 2 or not isinstance(data[0], tuple): + continue # Evitar errores si no hay datos válidos + + mensaje_bytes = data[0][1] + mensaje = email.message_from_bytes(mensaje_bytes) + + # Obtener las banderas del mensaje + status, flag_data = mail.fetch(num, '(FLAGS)') + flags = flag_data[0].decode() if flag_data and flag_data[0] else "" + + # Determinar si está leído o no + leido = '\\Seen' in flags + + correos.append({ + "id": num.decode(), + "from": mensaje["From"], + "subject": mensaje["Subject"], + "date": mensaje["Date"], + "read": leido + }) + + callback(correos) # Enviar la lista de correos a la GUI + except Exception as e: + print(f"Error al recibir correos: {e}") + + threading.Thread(target=recibir).start() + + + def eliminar_correo(self, email_user, password, correo_id): + def eliminar(): + try: + with imaplib.IMAP4_SSL(self.server_ip, self.ports["IMAP-S"]) as mail: + mail.login(email_user, password) + mail.select("inbox") + + mail.store(correo_id, "+FLAGS", "\\Deleted") + mail.expunge() + except Exception as e: + print(f"Error al eliminar el correo: {e}") + + threading.Thread(target=eliminar).start() + + + def obtener_contenido_correo(self, email_user, password, correo_id, callback): + def obtener(): + try: + with imaplib.IMAP4_SSL(self.server_ip, self.ports["IMAP-S"]) as mail: + mail.login(email_user, password) + mail.select("inbox") + + status, data = mail.fetch(correo_id, '(RFC822)') + mensaje = email.message_from_bytes(data[0][1]) + + # Obtener el cuerpo del mensaje + cuerpo = "" + if mensaje.is_multipart(): + for parte in mensaje.walk(): + if parte.get_content_type() == "text/plain": + cuerpo = parte.get_payload(decode=True).decode() + else: + cuerpo = mensaje.get_payload(decode=True).decode() + + # Marcar como leído + mail.store(correo_id, '+FLAGS', '\\Seen') + + callback({ + "from": mensaje["From"], + "subject": mensaje["Subject"], + "date": mensaje["Date"], + "body": cuerpo + }) + except Exception as e: + print(f"Error al obtener el contenido del correo: {e}") + + thread = threading.Thread(target=obtener) + thread.start() diff --git a/app/email/emailTab.py b/app/email/emailTab.py new file mode 100644 index 0000000..a2342a9 --- /dev/null +++ b/app/email/emailTab.py @@ -0,0 +1,70 @@ +import tkinter as tk +from tkinter import ttk, messagebox +from app.email.emailClient import EmailClient +import threading + +class EmailTab: + def __init__(self, notebook, panel_derecho): + self.panel_derecho = panel_derecho # Referencia al Panel Derecho + self.email_client = EmailClient() + + self.tab = ttk.Frame(notebook) + notebook.add(self.tab, text="\U0001F4E7 Correo") + self.setup_ui() + + def setup_ui(self): + """Configura la interfaz gráfica de la pestaña de correo.""" + frame_principal = tk.Frame(self.tab, bg="white", padx=10, pady=10) + frame_principal.pack(fill="both", expand=True) + frame_principal.columnconfigure(0, weight=1) + + # Enviar correo + tk.Label(frame_principal, text="✉️ Enviar Correo", font=("Helvetica", 14, "bold"), bg="white").grid(row=1, column=0, pady=5) + + frame_envio = tk.Frame(frame_principal, bg="white") + frame_envio.grid(row=2, column=0, pady=5, sticky="ew") + frame_envio.columnconfigure(1, weight=1) + + tk.Label(frame_envio, text="Para:", font=("Helvetica", 11), bg="white").grid(row=0, column=0, sticky="w") + self.entry_destinatario = tk.Entry(frame_envio, font=("Helvetica", 11)) + self.entry_destinatario.grid(row=0, column=1, sticky="ew", padx=5) + + tk.Label(frame_envio, text="Asunto:", font=("Helvetica", 11), bg="white").grid(row=1, column=0, sticky="w") + self.entry_asunto = tk.Entry(frame_envio, font=("Helvetica", 11)) + self.entry_asunto.grid(row=1, column=1, sticky="ew", padx=5) + + tk.Label(frame_envio, text="Mensaje:", font=("Helvetica", 11), bg="white").grid(row=2, column=0, sticky="w", pady=3) + self.text_mensaje = tk.Text(frame_envio, height=5, font=("Helvetica", 11)) + self.text_mensaje.grid(row=3, column=0, columnspan=2, sticky="ew", padx=5) + + # Botón de enviar + tk.Button( + frame_envio, text="📨 Enviar Correo", + font=("Helvetica", 11, "bold"), bg="green", fg="white", + command=self.enviar_correo + ).grid(row=4, column=0, columnspan=2, pady=10) + + def enviar_correo(self): + """Envía un correo en un hilo separado.""" + email, password = self.panel_derecho.get_credentials() # Obtener credenciales del panel derecho + + if not email or not password: + messagebox.showerror("Error", "⚠️ Debes iniciar sesión primero en el Panel Derecho.") + return + + def envio(): + self.email_client.enviar_correo( + email, + password, + self.entry_destinatario.get(), + self.entry_asunto.get(), + self.text_mensaje.get("1.0", tk.END).strip() + ) + messagebox.showinfo("Éxito", "✅ Correo enviado correctamente.") + self.entry_destinatario.delete(0, tk.END) + self.entry_asunto.delete(0, tk.END) + self.text_mensaje.delete("1.0", tk.END) + + threading.Thread(target=envio, daemon=True).start() + + diff --git a/app/email/reciveEmailTab.py b/app/email/reciveEmailTab.py new file mode 100644 index 0000000..c2de70b --- /dev/null +++ b/app/email/reciveEmailTab.py @@ -0,0 +1,106 @@ +import tkinter as tk +from tkinter import ttk, messagebox +from app.email.emailClient import EmailClient + +class ReciveEmailTab: + def __init__(self, notebook, panel_derecho): + self.email_client = EmailClient() + self.panel_derecho = panel_derecho + self.correos = [] + + self.tab = ttk.Frame(notebook) + notebook.add(self.tab, text="📩 Recibir Correo") + self.setup_ui() + + def setup_ui(self): + frame_principal = tk.Frame(self.tab, bg="white", padx=10, pady=10) + frame_principal.pack(fill="both", expand=True) + + # Botones de recibir y eliminar correos + frame_botones = ttk.Frame(frame_principal) + frame_botones.pack(fill="x", pady=5) + + tk.Button( + frame_botones, text="🔄 Recibir Correos", font=("Helvetica", 11, "bold"), bg="blue", fg="white", + command=self.obtener_correos_con_estado + ).pack(side="left", padx=5) + + tk.Button( + frame_botones, text="🗑️ Eliminar Correo", font=("Helvetica", 11, "bold"), bg="red", fg="white", + command=self.eliminar_correo + ).pack(side="right", padx=5) + + # Lista de correos + self.tree = ttk.Treeview(frame_principal, columns=("Leído", "De", "Asunto", "Fecha"), show="headings") + self.tree.heading("Leído", text="📌") + self.tree.heading("De", text="De") + self.tree.heading("Asunto", text="Asunto") + self.tree.heading("Fecha", text="Fecha") + self.tree.column("Leído", width=30, anchor="center") + self.tree.bind("", self.abrir_correo) + self.tree.pack(fill="both", expand=True) + + def obtener_correos_con_estado(self): + email, password = self.panel_derecho.get_credentials() + + if not email or not password: + messagebox.showerror("Error", "⚠️ Debes iniciar sesión primero.") + return + + def actualizar_lista(correos): + self.tree.delete(*self.tree.get_children()) # Limpiar la lista + self.correos = correos # Guardar la lista de correos + + for correo in correos: + estado_icono = "✅" if correo["read"] else "🔴" + self.tree.insert("", "end", values=(estado_icono, correo["from"], correo["subject"], correo["date"])) + + self.email_client.recibir_correos(email, password, actualizar_lista) + + + def abrir_correo(self, event): + email, password = self.panel_derecho.get_credentials() + + selected_item = self.tree.selection() + if not selected_item: + return + + index = self.tree.index(selected_item[0]) + correo = self.correos[index] + + def mostrar_correo(datos): + ventana = tk.Toplevel() + ventana.title("📩 Detalle del Correo") + ventana.geometry("500x400") + + tk.Label(ventana, text=f"De: {datos['from']}", font=("Helvetica", 11, "bold")).pack(pady=5) + tk.Label(ventana, text=f"Asunto: {datos['subject']}", font=("Helvetica", 11, "bold")).pack(pady=5) + tk.Label(ventana, text=f"Fecha: {datos['date']}", font=("Helvetica", 10)).pack(pady=5) + + text_area = tk.Text(ventana, wrap="word", font=("Helvetica", 11)) + text_area.insert("1.0", datos["body"]) + text_area.pack(expand=True, fill="both", padx=10, pady=10) + + # Actualizar el icono en la lista de correos + self.tree.item(selected_item[0], values=("✅", correo["from"], correo["subject"], correo["date"])) + + self.email_client.obtener_contenido_correo(email, password, correo["id"], mostrar_correo) + + def eliminar_correo(self): + email, password = self.panel_derecho.get_credentials() + + selected_item = self.tree.selection() + if not selected_item: + messagebox.showwarning("Aviso", "⚠️ Selecciona un correo para eliminar.") + return + + index = self.tree.index(selected_item[0]) + correo = self.correos[index] + + def confirmar_eliminacion(): + self.email_client.eliminar_correo(email, password, correo["id"]) + self.tree.delete(selected_item[0]) # Eliminar de la lista + + respuesta = messagebox.askyesno("Eliminar Correo", "¿Estás seguro de que deseas eliminar este correo?") + if respuesta: + confirmar_eliminacion() diff --git a/app/emailClient.py b/app/emailClient.py deleted file mode 100644 index 4b8a44c..0000000 --- a/app/emailClient.py +++ /dev/null @@ -1,59 +0,0 @@ -# emailClient.py -import smtplib -import imaplib -import email -from email.mime.text import MIMEText -from email.mime.multipart import MIMEMultipart -import threading - -class EmailClient: - def __init__(self): - self.server_ip = "192.168.120.103" - self.ports = { - "SMTP": 25, - "SMTP-S": 465, - "SMTP-SUBMISSION": 587, - "IMAP": 143, - "IMAP-S": 993 - } - - def enviar_correo(self, email_user, password, destinatario, asunto, mensaje): - def enviar(): - try: - with smtplib.SMTP(self.server_ip, self.ports["SMTP"]) as smtp: - smtp.login(email_user, password) - msg = MIMEMultipart() - msg["From"] = email_user - msg["To"] = destinatario - msg["Subject"] = asunto - msg.attach(MIMEText(mensaje, "plain")) - smtp.sendmail(email_user, destinatario, msg.as_string()) - print("Correo enviado correctamente.") - except Exception as e: - print(f"Error al enviar el correo: {e}") - - thread = threading.Thread(target=enviar) - thread.start() - - def recibir_correos(self, email_user, password, text_widget): - def recibir(): - try: - with imaplib.IMAP4_SSL(self.server_ip, self.ports["IMAP-S"]) as mail: - mail.login(email_user, password) - mail.select("inbox") - status, mensajes_no_leidos = mail.search(None, 'UNSEEN') - no_leidos = mensajes_no_leidos[0].split() - - text_widget.delete("1.0", "end") - text_widget.insert("end", f"Tienes {len(no_leidos)} correos no leídos.\n") - - for num in no_leidos: - status, data = mail.fetch(num, '(RFC822)') - mensaje = email.message_from_bytes(data[0][1]) - text_widget.insert("end", f"[NO LEÍDO] {mensaje['Subject']}\n") - mail.store(num, '+FLAGS', '\\Seen') - except Exception as e: - text_widget.insert("end", f"Error al recibir correos: {e}\n") - - thread = threading.Thread(target=recibir) - thread.start() diff --git a/app/emailTab.py b/app/emailTab.py deleted file mode 100644 index 875fea7..0000000 --- a/app/emailTab.py +++ /dev/null @@ -1,68 +0,0 @@ -# emailTab.py -import tkinter as tk -from tkinter import ttk -from app.emailClient import EmailClient - -class EmailTab: - def __init__(self, notebook): - self.email_client = EmailClient() - self.tab = ttk.Frame(notebook) - notebook.add(self.tab, text="Correo") - self.setup_ui() - - def setup_ui(self): - # Campos de entrada para credenciales - tk.Label(self.tab, text="Correo electrónico:").grid(row=0, column=0, sticky="e", padx=5, pady=5) - self.entry_email = tk.Entry(self.tab) - self.entry_email.grid(row=0, column=1, padx=5, pady=5) - - tk.Label(self.tab, text="Contraseña:").grid(row=1, column=0, sticky="e", padx=5, pady=5) - self.entry_password = tk.Entry(self.tab, show="*") - self.entry_password.grid(row=1, column=1, padx=5, pady=5) - - # Campos de entrada para enviar correo - tk.Label(self.tab, text="Destinatario:").grid(row=2, column=0, sticky="e", padx=5, pady=5) - self.entry_destinatario = tk.Entry(self.tab) - self.entry_destinatario.grid(row=2, column=1, padx=5, pady=5) - - tk.Label(self.tab, text="Asunto:").grid(row=3, column=0, sticky="e", padx=5, pady=5) - self.entry_asunto = tk.Entry(self.tab) - self.entry_asunto.grid(row=3, column=1, padx=5, pady=5) - - tk.Label(self.tab, text="Mensaje:").grid(row=4, column=0, sticky="ne", padx=5, pady=5) - self.text_mensaje = tk.Text(self.tab, height=5, width=40) - self.text_mensaje.grid(row=4, column=1, padx=5, pady=5) - - # Botón para enviar correo - tk.Button( - self.tab, - text="Enviar Correo", - command=self.enviar_correo - ).grid(row=5, column=1, pady=10) - - # Área de texto para mostrar correos recibidos - self.text_correos = tk.Text(self.tab, height=10, width=60) - self.text_correos.grid(row=6, column=0, columnspan=2, padx=5, pady=5) - - # Botón para recibir correos - tk.Button( - self.tab, - text="Recibir Correos", - command=self.recibir_correos - ).grid(row=7, column=1, pady=10) - - def enviar_correo(self): - self.email_client.enviar_correo( - self.entry_email.get(), - self.entry_password.get(), - self.entry_destinatario.get(), - self.entry_asunto.get(), - self.text_mensaje.get("1.0", tk.END).strip() - ) - - def recibir_correos(self): - self.email_client.recibir_correos( - self.entry_email.get(), - self.entry_password.get(), - self.text_correos - ) diff --git a/app/game.py b/app/game.py index 0ab6962..98f2386 100644 --- a/app/game.py +++ b/app/game.py @@ -1,8 +1,6 @@ -import pygame import threading import random import time -import tkinter as tk from tkinter import Frame, Canvas, messagebox, Button class HiloJuego: diff --git a/app/gestor_tareas.py b/app/gestor_tareas.py index 1a361e1..89a0697 100644 --- a/app/gestor_tareas.py +++ b/app/gestor_tareas.py @@ -8,12 +8,10 @@ class GestorTareas: def __init__(self, frame): self.frame = frame - # Configurar estilo para ttk.Frame style = ttk.Style() style.configure("Custom.TFrame", background="white") self.frame.configure(style="Custom.TFrame") - # Título self.title_label = ttk.Label( self.frame, text="Administrador de Tareas", font=("Helvetica", 16, "bold"), background="white" ) diff --git a/app/graphics.py b/app/graphics.py index f49e994..cf51a97 100644 --- a/app/graphics.py +++ b/app/graphics.py @@ -1,3 +1,4 @@ +from tkinter import messagebox import requests import yfinance as yf import threading @@ -33,7 +34,7 @@ def actualizar_grafico_criptomonedas_api(canvas, ax): ax.legend() canvas.draw() except Exception as e: - print(f"Error al obtener datos de criptomonedas: {e}") + messagebox.showerror("ERROR", f"Error al obtener datos de criptomonedas: {e}") time.sleep(60) @@ -57,7 +58,7 @@ def actualizar_grafico_ibex_api(canvas, ax): ax.legend() canvas.draw() except Exception as e: - print(f"Error al obtener datos del IBEX: {e}") + messagebox.showerror("ERROR", f"Error al obtener datos de IBEX: {e}") time.sleep(60) diff --git a/app/monitorization.py b/app/monitorization.py index 4231ef3..04fafc2 100644 --- a/app/monitorization.py +++ b/app/monitorization.py @@ -1,7 +1,5 @@ from tkinter import messagebox -import threading import time -import datetime import psutil def monitor_cpu_usage(label): diff --git a/app/panel_derecho/__pycache__/chat.cpython-313.pyc b/app/panel_derecho/__pycache__/chat.cpython-313.pyc new file mode 100644 index 0000000..cc258ff Binary files /dev/null and b/app/panel_derecho/__pycache__/chat.cpython-313.pyc differ diff --git a/app/panel_derecho/__pycache__/panel_derecho.cpython-313.pyc b/app/panel_derecho/__pycache__/panel_derecho.cpython-313.pyc new file mode 100644 index 0000000..82680cd Binary files /dev/null and b/app/panel_derecho/__pycache__/panel_derecho.cpython-313.pyc differ diff --git a/app/chat.py b/app/panel_derecho/chat.py similarity index 84% rename from app/chat.py rename to app/panel_derecho/chat.py index b9f905c..99e9c38 100644 --- a/app/chat.py +++ b/app/panel_derecho/chat.py @@ -1,8 +1,9 @@ import socket import threading +from tkinter import messagebox class Chat: - def __init__(self, server='127.0.0.1', port=3333): + def __init__(self, server='127.0.0.1' , port=3333): #192.168.120.106 self.server = server self.port = port self.client_socket = None @@ -18,18 +19,18 @@ class Chat: print("Conectado al servidor de chat.") self.escuchar_mensajes() except Exception as e: - print(f"Error, no se pudo conectar al servidor: {e}") + messagebox.showerror("ERROR", f"Error, no se pudo conectar al servidor: {e}") self.connected = False def enviar_mensaje(self, mensaje): """Enviar un mensaje al servidor.""" if not self.connected: - raise ConnectionError("No estás conectado al servidor.") + messagebox.showerror("ERROR", "No estas conectado al servidor") try: self.client_socket.send(mensaje.encode('utf-8')) print("Mensaje Enviado") except Exception as e: - raise ConnectionError(f"Error al enviar el mensaje: {e}") + messagebox.showerror("ERROR",f"Error al enviar el mensaje: {e}") def escuchar_mensajes(self): """Escucha mensajes entrantes desde el servidor.""" diff --git a/app/panel_derecho.py b/app/panel_derecho/panel_derecho.py similarity index 62% rename from app/panel_derecho.py rename to app/panel_derecho/panel_derecho.py index 92a076b..c5920bd 100644 --- a/app/panel_derecho.py +++ b/app/panel_derecho/panel_derecho.py @@ -1,12 +1,14 @@ import tkinter as tk from tkinter import messagebox -from app.chat import Chat +from app.panel_derecho.chat import Chat import threading import time import pygame # Para reproducir música class PanelDerecho: def __init__(self, frame): + self.usuario_email = None + self.usuario_password = None # Inicializar el cliente de chat self.chat_client = Chat() try: @@ -22,13 +24,28 @@ class PanelDerecho: self.frame.configure(bg="lightblue", width=200) self.frame.grid_propagate(False) self.frame.columnconfigure(0, weight=1) + + # Botón de iniciar sesión (y cerrar sesión) + frame_login = tk.Frame(frame, bg="lightblue") + frame_login.grid(row=0, column=0, pady=5, sticky="ew") - # Título del chat - chat_label = tk.Label(self.frame, text="Chat", font=("Helvetica", 12, "bold"), bg="white", fg="red") - chat_label.grid(row=0, column=0, sticky="ew", pady=5, padx=5) + self.btn_login = tk.Button( + frame_login, text="🔑 Iniciar Sesión", + font=("Helvetica", 11, "bold"), bg="orange", fg="white", + command=self.mostrar_login + ) + self.btn_login.pack(padx=5) + + self.btn_logout = tk.Button( + frame_login, text="🚪 Cerrar Sesión", + font=("Helvetica", 11, "bold"), bg="red", fg="white", + command=self.cerrar_sesion + ) + self.btn_logout.pack(padx=5) + self.btn_logout.pack_forget() # Ocultar hasta iniciar sesión # Área de entrada de mensaje - mensaje_label = tk.Label(self.frame, text="Mensaje", font=("Helvetica", 10), bg="lightblue") + mensaje_label = tk.Label(self.frame, text="CHAT", font=("Helvetica", 10), bg="lightblue") mensaje_label.grid(row=1, column=0, sticky="w", padx=5) self.entrada_mensaje = tk.Text(self.frame, height=5, bg="lightyellow", wrap="word") self.entrada_mensaje.grid(row=2, column=0, sticky="ew", padx=5, pady=5) @@ -62,6 +79,62 @@ class PanelDerecho: # Iniciar actualización de mensajes self.iniciar_actualizacion_mensajes() + + def mostrar_login(self): + login_window = tk.Toplevel() + login_window.title("Iniciar Sesión") + login_window.geometry("300x200") + + tk.Label(login_window, text="Correo Electrónico:", font=("Helvetica", 11)).pack(pady=5) + entry_email = tk.Entry(login_window, width=30) + entry_email.pack(pady=5) + + tk.Label(login_window, text="Contraseña:", font=("Helvetica", 11)).pack(pady=5) + entry_password = tk.Entry(login_window, width=30, show="*") + entry_password.pack(pady=5) + + def validar_login(): + email = entry_email.get() + password = entry_password.get() + + if not email or not password: + messagebox.showerror("Error", "⚠️ Debes ingresar ambos campos.") + return + + self.set_credentials(email, password) + messagebox.showinfo("Éxito", "✅ Inicio de sesión exitoso.") + self.btn_login.pack_forget() + self.btn_logout.pack() + login_window.destroy() + + tk.Button( + login_window, text="🔑 Iniciar Sesión", + font=("Helvetica", 11, "bold"), + bg="orange", fg="white", + command=validar_login + ).pack(pady=10) + + def cerrar_sesion(self): + """Cierra sesión y elimina las credenciales almacenadas.""" + self.clear_credentials() + messagebox.showinfo("Sesión Cerrada", "🚪 Has cerrado sesión correctamente.") + self.btn_logout.pack_forget() + self.btn_login.pack() + + def set_credentials(self, email, password): + """Establece las credenciales de inicio de sesión.""" + self.usuario_email = email + self.usuario_password = password + + def clear_credentials(self): + """Limpia las credenciales de inicio de sesión.""" + self.usuario_email = None + self.usuario_password = None + + def get_credentials(self): + """Devuelve las credenciales de usuario (email, password).""" + return self.usuario_email, self.usuario_password + def enviar_mensaje(self): """Enviar un mensaje al servidor.""" @@ -126,4 +199,4 @@ class PanelDerecho: """Reinicia la música desde el principio.""" pygame.mixer.music.stop() pygame.mixer.music.play() - messagebox.showinfo("Reproducción", "Reproduciendo desde el principio.") + messagebox.showinfo("Reproducción", "Reproduciendo desde el principio.") \ No newline at end of file diff --git a/app/panel_izquierdo/__pycache__/panel_izquierdo.cpython-313.pyc b/app/panel_izquierdo/__pycache__/panel_izquierdo.cpython-313.pyc new file mode 100644 index 0000000..914b714 Binary files /dev/null and b/app/panel_izquierdo/__pycache__/panel_izquierdo.cpython-313.pyc differ diff --git a/app/panel_izquierdo.py b/app/panel_izquierdo/panel_izquierdo.py similarity index 93% rename from app/panel_izquierdo.py rename to app/panel_izquierdo/panel_izquierdo.py index 4f18d40..15fa9a9 100644 --- a/app/panel_izquierdo.py +++ b/app/panel_izquierdo/panel_izquierdo.py @@ -26,18 +26,22 @@ class PanelIzquierdo: self.weather_label.pack(pady=5) #self.update_weather() Comentado para que no gaste limite de requests en la api - # Sección: Scrapping + # Sección: Scraping scraping_frame = tk.Frame(self.frame, bg="white", bd=2, relief="sunken") scraping_frame.grid(row=1, column=0, sticky="ew", padx=5, pady=5) scraping_title = tk.Label(scraping_frame, text="Scraping", bg="white", font=("Helvetica", 12, "bold"), fg="navy") scraping_title.pack(pady=5) + self.entry_url = tk.Entry(scraping_frame, font=("Helvetica", 10), width=30) + self.entry_url.pack(pady=5) + self.entry_url.insert(0, "https://www.amazon.es/") # URL por defecto + boton_scrapping = tk.Button( scraping_frame, - text="Iniciar Scrapping", + text="Iniciar Scraping", command=lambda: threading.Thread( target=scraping.iniciar_scraping_y_insercion, - args=("https://www.amazon.es/", text_widget) + args=(self.entry_url.get(), text_widget) ).start(), bg="lightgreen" ) @@ -55,7 +59,6 @@ class PanelIzquierdo: self.news_label.pack(pady=5) #self.update_news() Comentado para que no gaste limite de requests en la api - # Configuración para que las filas crezcan dinámicamente self.frame.rowconfigure(2, weight=1) def update_weather(self): diff --git a/app/scraping.py b/app/scraping.py index f01fa0c..385c96b 100644 --- a/app/scraping.py +++ b/app/scraping.py @@ -1,3 +1,4 @@ +from tkinter import messagebox import requests from bs4 import BeautifulSoup import threading @@ -31,9 +32,9 @@ def extraer_enlaces(url, cola, text_widget): cola.put(enlace_str) if text_widget: text_widget.insert('end', enlace_str + "\n") - print("Extracción de enlaces completada.") + messagebox.showinfo("Scraping", "Extracción de enlaces completada.") else: - print(f"Error al acceder a la URL: {respuesta.status_code}") + messagebox.showerror("ERROR", f"Error al acceder a la URL: {respuesta.status_code}") except requests.exceptions.RequestException as e: print(f"Error durante la solicitud HTTP: {e}") @@ -67,7 +68,6 @@ def insertar_enlaces_mysql(cola): print("Inserción en la base de datos finalizada.") -# Función para iniciar el scraping y la inserción en hilos def iniciar_scraping_y_insercion(url, text_widget): cola_enlaces = Queue() # Configurar los hilos como daemon diff --git a/app/todo_list.py b/app/todo_list.py index 30a54d1..89836c1 100644 --- a/app/todo_list.py +++ b/app/todo_list.py @@ -1,12 +1,69 @@ import tkinter as tk +from tkinter import ttk import threading -import time + +def crear_solapa_todo(tab): + """Crea una pestaña de To-Do List que usa TODO el espacio disponible.""" + + tareas = [] + + # Configurar el frame principal para que use todo el espacio + frame_principal = ttk.Frame(tab, padding=10) + frame_principal.grid(row=0, column=0, sticky="nsew") + + tab.columnconfigure(0, weight=1) + tab.rowconfigure(0, weight=1) + frame_principal.columnconfigure(0, weight=1) + frame_principal.rowconfigure(1, weight=1) # La lista de tareas ocupa el mayor espacio + + # Estilos para botones de colores + style = ttk.Style() + style.configure("BotonAzul.TButton", font=("Arial", 12, "bold"), foreground="#007BFF", background="#007BFF") + style.configure("BotonRojo.TButton", font=("Arial", 12, "bold"), foreground="#DC3545", background="#DC3545") + style.configure("BotonVerde.TButton", font=("Arial", 12, "bold"), foreground="#28A745", background="#28A745") + + # Entrada para agregar nuevas tareas + entry = ttk.Entry(frame_principal, font=("Arial", 14)) + entry.grid(row=0, column=0, padx=5, pady=5, sticky="ew") + + # Marco para la lista con scroll + frame_lista = ttk.Frame(frame_principal) + frame_lista.grid(row=1, column=0, pady=5, sticky="nsew") + + frame_lista.columnconfigure(0, weight=1) + frame_lista.rowconfigure(0, weight=1) + + # ListBox con scrollbar + todo_listbox = tk.Listbox(frame_lista, font=("Arial", 14), selectbackground="#00A8E8") + todo_listbox.grid(row=0, column=0, sticky="nsew") + + scrollbar = ttk.Scrollbar(frame_lista, orient="vertical", command=todo_listbox.yview) + scrollbar.grid(row=0, column=1, sticky="ns") + todo_listbox.config(yscrollcommand=scrollbar.set) + + # Marco inferior para botones + frame_botones = ttk.Frame(frame_principal) + frame_botones.grid(row=2, column=0, pady=5, sticky="ew") + frame_botones.columnconfigure((0,1,2), weight=1) + + # Botones + boton_agregar = ttk.Button(frame_botones, text="➕ Agregar", style="BotonAzul.TButton", command=lambda: agregar_tarea(entry, todo_listbox, tareas)) + boton_agregar.grid(row=0, column=0, padx=5, sticky="ew") + + boton_eliminar = ttk.Button(frame_botones, text="🗑️ Eliminar", style="BotonRojo.TButton", command=lambda: eliminar_tarea(todo_listbox, tareas)) + boton_eliminar.grid(row=0, column=1, padx=5, sticky="ew") + + boton_marcar = ttk.Button(frame_botones, text="✔️ Marcar", style="BotonVerde.TButton", command=lambda: marcar_tarea(todo_listbox, tareas)) + boton_marcar.grid(row=0, column=2, padx=5, sticky="ew") + + # Inicializar la lista vacía + actualizar_todo_list(todo_listbox, tareas) def actualizar_todo_list(todo_listbox, tareas): - """Actualizar el contenido del ListBox con las tareas actuales.""" + """Actualizar la lista de tareas en la interfaz.""" todo_listbox.delete(0, tk.END) for tarea, completada in tareas: - estado = "[X]" if completada else "[ ]" + estado = "✅" if completada else "⬜" todo_listbox.insert(tk.END, f"{estado} {tarea}") def agregar_tarea(entry, todo_listbox, tareas): @@ -14,13 +71,13 @@ def agregar_tarea(entry, todo_listbox, tareas): def tarea_hilo(): nueva_tarea = entry.get() if nueva_tarea.strip(): - tareas.append((nueva_tarea, False)) # Agregar tarea como no completada + tareas.append((nueva_tarea, False)) # Agregar como tarea no completada todo_listbox.after(0, actualizar_todo_list, todo_listbox, tareas) entry.delete(0, tk.END) threading.Thread(target=tarea_hilo).start() def eliminar_tarea(todo_listbox, tareas): - """Eliminar la tarea seleccionada de la lista en un hilo separado.""" + """Eliminar una tarea de la lista.""" def tarea_hilo(): seleccion = todo_listbox.curselection() if seleccion: @@ -30,39 +87,12 @@ def eliminar_tarea(todo_listbox, tareas): threading.Thread(target=tarea_hilo).start() def marcar_tarea(todo_listbox, tareas): - """Marcar la tarea seleccionada como completada o no completada en un hilo separado.""" + """Marcar la tarea seleccionada como completada o no.""" def tarea_hilo(): seleccion = todo_listbox.curselection() if seleccion: indice = seleccion[0] tarea, completada = tareas[indice] - tareas[indice] = (tarea, not completada) # Alternar el estado de completada + tareas[indice] = (tarea, not completada) # Alternar estado todo_listbox.after(0, actualizar_todo_list, todo_listbox, tareas) threading.Thread(target=tarea_hilo).start() - -def crear_solapa_todo(tab): - """Función para inicializar la funcionalidad de la lista To-Do en la solapa.""" - tareas = [] - - # Entrada para agregar nuevas tareas - entry = tk.Entry(tab, font=("Arial", 12)) - entry.pack(pady=10, padx=10, fill="x") - - # Botón para agregar tareas - boton_agregar = tk.Button(tab, text="Agregar", command=lambda: agregar_tarea(entry, todo_listbox, tareas)) - boton_agregar.pack(pady=5) - - # ListBox para mostrar las tareas - todo_listbox = tk.Listbox(tab, font=("Arial", 12), height=10) - todo_listbox.pack(pady=10, padx=10, fill="both", expand=True) - - # Botón para eliminar tareas - boton_eliminar = tk.Button(tab, text="Eliminar", command=lambda: eliminar_tarea(todo_listbox, tareas)) - boton_eliminar.pack(pady=5) - - # Botón para marcar tareas como completadas o no completadas - boton_marcar = tk.Button(tab, text="Marcar como hecho/no hecho", command=lambda: marcar_tarea(todo_listbox, tareas)) - boton_marcar.pack(pady=5) - - # Inicializar la lista vacía - actualizar_todo_list(todo_listbox, tareas) diff --git a/main.py b/main.py index 7d1c09b..7615d77 100644 --- a/main.py +++ b/main.py @@ -1,24 +1,17 @@ -import tkinter as tk -from tkinter import Menu # Importar el widget Menu -from tkinter import ttk # Importar el widget ttk -from tkinter import messagebox -from app import monitorization -from app import panel_derecho -from app import panel_izquierdo -from app import pomodoro +import tkinter as tk +from tkinter import Menu, ttk, messagebox + +from app import monitorization, pomodoro, game, scraping, gestor_tareas, graphics, todo_list +from app.panel_derecho import panel_derecho +from app.panel_izquierdo import panel_izquierdo +from app.email.emailTab import EmailTab +from app.email.reciveEmailTab import ReciveEmailTab + import threading import time import datetime -import psutil -from app import scraping -from app import game -from app import gestor_tareas from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg import matplotlib.pyplot as plt -import random -from app import graphics -from app import todo_list -from app.emailTab import EmailTab def update_time(status_bar): while True: @@ -114,35 +107,6 @@ style.configure("CustomNotebook.TNotebook.Tab", font=("Arial", 12, "bold")) notebook = ttk.Notebook(frame_superior, style="CustomNotebook.TNotebook") notebook.pack(fill="both", expand=True) -# Crear cinco solapas en el frame superior -for i in range(1, 7): - tab = ttk.Frame(notebook) - if i == 1: - notebook.add(tab, text="Scrapping", padding=4) - text_scrapping = tk.Text(tab, wrap="word") - text_scrapping.pack(fill="both", expand=True) - elif i == 2: # Identificar la solapa 2 - notebook.add(tab, text="Pomodoro", padding=4) - pomodoro.PomodoroTimer(tab) - elif i == 3: - notebook.add(tab, text="Gestor de tareas", padding=4) - gestor_tareas.GestorTareas(tab) - elif i == 4: - notebook.add(tab, text='Juego', padding=4) - game_frame = tk.Frame(tab) - game_frame.pack(fill="both", expand=True) - hilo_juego = game.HiloJuego(game_frame) - elif i == 5: - notebook.add(tab, text='To Do List', padding=4) - todo_list.crear_solapa_todo(tab) - elif i == 6: - EmailTab(notebook) - - else: - notebook.add(tab, text=f"Solapa {i}", padding=4) - # Añadir un Label en cada solapa para diferenciarla - label = ttk.Label(tab, text=f"Contenido de la Solapa {i}") - label.pack(pady=10) # Notebook para las pestañas en el frame inferior notebook_inferior = ttk.Notebook(frame_inferior, style="CustomNotebook.TNotebook") @@ -200,11 +164,45 @@ thread_network_used_monitor = threading.Thread(target=monitorization.monitor_net thread_network_used_monitor.daemon = True thread_network_used_monitor.start() -# Lados verticales +#Iniciar panel derecho panel_d = panel_derecho.PanelDerecho(frame_derecho) -panel_i = panel_izquierdo.PanelIzquierdo(frame_izquierdo, text_scrapping) + +# Crear cinco solapas en el frame superior +for i in range(1, 8): + tab = ttk.Frame(notebook) + if i == 1: + notebook.add(tab, text="👀 Scrapping", padding=4) + text_scrapping = tk.Text(tab, wrap="word") + text_scrapping.pack(fill="both", expand=True) + elif i == 2: # Identificar la solapa 2 + notebook.add(tab, text="🍅 Pomodoro", padding=4) + pomodoro.PomodoroTimer(tab) + elif i == 3: + notebook.add(tab, text="📇 Gestor de tareas", padding=4) + gestor_tareas.GestorTareas(tab) + elif i == 4: + notebook.add(tab, text='🎮 Juego', padding=4) + game_frame = tk.Frame(tab) + game_frame.pack(fill="both", expand=True) + hilo_juego = game.HiloJuego(game_frame) + elif i == 5: + notebook.add(tab, text='📝 To Do List', padding=4) + todo_list.crear_solapa_todo(tab) + elif i == 6: + EmailTab(notebook, panel_d) + elif i == 7: + ReciveEmailTab(notebook, panel_d) + + else: + notebook.add(tab, text=f"Solapa {i}", padding=4) + # Añadir un Label en cada solapa para diferenciarla + label = ttk.Label(tab, text=f"Contenido de la Solapa {i}") + label.pack(pady=10) + +# Panel izquierdo +panel_i = panel_izquierdo.PanelIzquierdo(frame_izquierdo, text_scrapping) root.protocol("WM_DELETE_WINDOW", detener_aplicacion) # Ejecución de la aplicación -root.mainloop() +root.mainloop() \ No newline at end of file