Added Mail interface and POP client, pop connections still needs to be closes when program is finished
This commit is contained in:
parent
128ab84429
commit
36e1a225e6
|
@ -2,11 +2,7 @@
|
||||||
<module type="PYTHON_MODULE" version="4">
|
<module type="PYTHON_MODULE" version="4">
|
||||||
<component name="NewModuleRootManager">
|
<component name="NewModuleRootManager">
|
||||||
<content url="file://$MODULE_DIR$" />
|
<content url="file://$MODULE_DIR$" />
|
||||||
<orderEntry type="jdk" jdkName="Python 3.12" jdkType="Python SDK" />
|
<orderEntry type="jdk" jdkName="Python 3.13" jdkType="Python SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
<component name="PyDocumentationSettings">
|
|
||||||
<option name="format" value="PLAIN" />
|
|
||||||
<option name="myDocStringFormat" value="Plain" />
|
|
||||||
</component>
|
|
||||||
</module>
|
</module>
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="Black">
|
<component name="Black">
|
||||||
<option name="sdkName" value="Python 3.12" />
|
<option name="sdkName" value="Python 3.13" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12" project-jdk-type="Python SDK" />
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13" project-jdk-type="Python SDK" />
|
||||||
</project>
|
</project>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -8,10 +8,11 @@ from email.mime.multipart import MIMEMultipart
|
||||||
import sqlite3
|
import sqlite3
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
class EmailClientPOP:
|
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.pop_server = pop_server
|
||||||
self.smtp = smtp_server
|
self.smtp_server = smtp_server
|
||||||
self.email = email
|
self.email = email
|
||||||
self.password = password
|
self.password = password
|
||||||
self.pop_port = pop_port
|
self.pop_port = pop_port
|
||||||
|
@ -19,7 +20,7 @@ class EmailClientPOP:
|
||||||
self.pop_conn = None
|
self.pop_conn = None
|
||||||
self.smtp_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.db_file = os.path.join("resources/db_email", "emails.db")
|
||||||
self.init_database()
|
self.init_database()
|
||||||
|
|
||||||
|
@ -40,8 +41,169 @@ class EmailClientPOP:
|
||||||
received_at DATETIME
|
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.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
print(f"Base de datos inicializada: {self.db_file}")
|
print(f"Base de datos inicializada: {self.db_file}")
|
||||||
except sqlite3.Error as e:
|
except sqlite3.Error as e:
|
||||||
print(f"Error al inicializar la base de datos: {e}")
|
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()
|
||||||
|
|
Binary file not shown.
|
@ -6,7 +6,7 @@ from src.services.processes_manager import ProcessManager
|
||||||
from src.services.system_monitor import SystemMonitor
|
from src.services.system_monitor import SystemMonitor
|
||||||
from src.services.tetris_game import TetrisGame
|
from src.services.tetris_game import TetrisGame
|
||||||
from src.services.threads_manager import ThreadsManager
|
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):
|
class CenteredWindow(ctk.CTk):
|
||||||
|
@ -16,9 +16,9 @@ class CenteredWindow(ctk.CTk):
|
||||||
self.title(title)
|
self.title(title)
|
||||||
self.after_tasks = []
|
self.after_tasks = []
|
||||||
|
|
||||||
#Configurar Email Client
|
# Configurar Email Client IMAP
|
||||||
self.email_client = EmailClientImap(
|
self.email_client = EmailClientPOP(
|
||||||
imap_server="192.168.120.103",
|
pop_server="192.168.120.103",
|
||||||
smtp_server="192.168.120.103",
|
smtp_server="192.168.120.103",
|
||||||
email="dennis@psp.ieslamar.org",
|
email="dennis@psp.ieslamar.org",
|
||||||
password="1234"
|
password="1234"
|
||||||
|
@ -28,21 +28,21 @@ class CenteredWindow(ctk.CTk):
|
||||||
self.process_manager = ProcessManager()
|
self.process_manager = ProcessManager()
|
||||||
self.system_monitor = None
|
self.system_monitor = None
|
||||||
|
|
||||||
# Obtener la resolucion de la pantalla:
|
# Obtener la resolución de la pantalla:
|
||||||
screen_width = self.winfo_screenwidth()
|
screen_width = self.winfo_screenwidth()
|
||||||
screen_height = self.winfo_screenheight()
|
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_width = int(screen_width * width_percentage)
|
||||||
window_height = int(screen_height * height_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_x = (screen_width - window_width) // 2
|
||||||
position_y = (screen_height - window_height) // 2
|
position_y = (screen_height - window_height) // 2
|
||||||
|
|
||||||
self.geometry(f"{window_width}x{window_height}+{position_x}+{position_y}")
|
self.geometry(f"{window_width}x{window_height}+{position_x}+{position_y}")
|
||||||
|
|
||||||
#Configura la ventana
|
# Configura la ventana
|
||||||
self.configure_window()
|
self.configure_window()
|
||||||
|
|
||||||
self.protocol("WM_DELETE_WINDOW", self.on_close)
|
self.protocol("WM_DELETE_WINDOW", self.on_close)
|
||||||
|
@ -62,7 +62,6 @@ class CenteredWindow(ctk.CTk):
|
||||||
|
|
||||||
self.thread_manager.start_threads()
|
self.thread_manager.start_threads()
|
||||||
|
|
||||||
|
|
||||||
def on_close(self):
|
def on_close(self):
|
||||||
"""Maneja el cierre de la ventana"""
|
"""Maneja el cierre de la ventana"""
|
||||||
self.thread_manager.stop_threads()
|
self.thread_manager.stop_threads()
|
||||||
|
@ -91,10 +90,16 @@ class CenteredWindow(ctk.CTk):
|
||||||
# Secciones y botones
|
# Secciones y botones
|
||||||
sections = {
|
sections = {
|
||||||
"Aplicaciones": [
|
"Aplicaciones": [
|
||||||
("Abrir Chrome", lambda: self.process_manager.open_resource("browser", "https://google.com", "Cannot open browser")),
|
("Abrir Chrome",
|
||||||
("Visual Studio Code", lambda: self.process_manager.open_resource("program", r"C:\Program Files\Microsoft VS Code\Code.exe", "Can't find VSCode")),
|
lambda: self.process_manager.open_resource("browser", "https://google.com", "Cannot open browser")),
|
||||||
("Explorador de Windows", lambda: self.process_manager.open_resource("program", "explorer.exe", "Can't open Windows Explorer")),
|
("Visual Studio Code",
|
||||||
("Notepad++", lambda: self.process_manager.open_resource("program", r"C:\Program Files\Notepad++\notepad++.exe", "Can't open Notepad++"))
|
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++"))
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,14 +133,14 @@ class CenteredWindow(ctk.CTk):
|
||||||
self.left_panel = left_panel
|
self.left_panel = left_panel
|
||||||
self.left_panel.url_entry = url_entry
|
self.left_panel.url_entry = url_entry
|
||||||
self.left_panel.url_entry_chrome = url_entry_chrome
|
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)
|
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)
|
stop_button.pack(pady=5, padx=10)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def create_center_panel(self):
|
def create_center_panel(self):
|
||||||
# Panel central con pestañas
|
# Panel central con pestañas
|
||||||
center_panel = ctk.CTkFrame(self)
|
center_panel = ctk.CTkFrame(self)
|
||||||
|
@ -151,6 +156,9 @@ class CenteredWindow(ctk.CTk):
|
||||||
if tab_name == "Radio":
|
if tab_name == "Radio":
|
||||||
self.create_radio_tab(tab)
|
self.create_radio_tab(tab)
|
||||||
|
|
||||||
|
if tab_name == "Correos":
|
||||||
|
self.create_email_tab(tab)
|
||||||
|
|
||||||
if tab_name == "Scrapping":
|
if tab_name == "Scrapping":
|
||||||
text_widget = ctk.CTkTextbox(tab, width=500, height=400)
|
text_widget = ctk.CTkTextbox(tab, width=500, height=400)
|
||||||
text_widget.pack(fill=ctk.BOTH, expand=True, padx=10, pady=10)
|
text_widget.pack(fill=ctk.BOTH, expand=True, padx=10, pady=10)
|
||||||
|
@ -192,33 +200,25 @@ class CenteredWindow(ctk.CTk):
|
||||||
self.tetris_game = TetrisGame(game_frame)
|
self.tetris_game = TetrisGame(game_frame)
|
||||||
self.tetris_game.pack()
|
self.tetris_game.pack()
|
||||||
|
|
||||||
# else:
|
# else:
|
||||||
# Agregar contenido genérico a otras pestañas
|
# Agregar contenido genérico a otras pestañas
|
||||||
#label = ctk.CTkLabel(tab, text=f"Contenido de {tab_name}", font=("Arial", 12))
|
# label = ctk.CTkLabel(tab, text=f"Contenido de {tab_name}", font=("Arial", 12))
|
||||||
#label.pack(pady=10)
|
# label.pack(pady=10)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def start_tetris_game(self):
|
def start_tetris_game(self):
|
||||||
"""Método para iniciar el juego."""
|
"""Método para iniciar el juego."""
|
||||||
if not self.tetris_game.running:
|
if not self.tetris_game.running:
|
||||||
self.tetris_game.running = True
|
self.tetris_game.running = True
|
||||||
#self.tetris_game.update_game()
|
# self.tetris_game.update_game()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def pause_tetris_game(self):
|
def pause_tetris_game(self):
|
||||||
"""Método para pausar el juego."""
|
"""Método para pausar el juego."""
|
||||||
self.tetris_game.running = False
|
self.tetris_game.running = False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def restart_tetris_game(self):
|
def restart_tetris_game(self):
|
||||||
"""Método para reiniciar el juego."""
|
"""Método para reiniciar el juego."""
|
||||||
self.tetris_game.reset_game()
|
self.tetris_game.reset_game()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def create_right_panel(self):
|
def create_right_panel(self):
|
||||||
# Panel derecho
|
# Panel derecho
|
||||||
right_panel = ctk.CTkFrame(self, width=250)
|
right_panel = ctk.CTkFrame(self, width=250)
|
||||||
|
@ -236,7 +236,8 @@ class CenteredWindow(ctk.CTk):
|
||||||
|
|
||||||
# Lista de alumnos
|
# Lista de alumnos
|
||||||
for i in range(1, 4):
|
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_label.pack(anchor=ctk.W, pady=5, padx=10)
|
||||||
|
|
||||||
student_info = ctk.CTkLabel(
|
student_info = ctk.CTkLabel(
|
||||||
|
@ -247,8 +248,6 @@ class CenteredWindow(ctk.CTk):
|
||||||
)
|
)
|
||||||
student_info.pack(anchor=ctk.W, padx=10)
|
student_info.pack(anchor=ctk.W, padx=10)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def create_bottom_bar(self):
|
def create_bottom_bar(self):
|
||||||
# Crear la barra inferior
|
# Crear la barra inferior
|
||||||
self.bottom_bar = ctk.CTkFrame(self, fg_color="lightblue", height=40)
|
self.bottom_bar = ctk.CTkFrame(self, fg_color="lightblue", height=40)
|
||||||
|
@ -258,7 +257,8 @@ class CenteredWindow(ctk.CTk):
|
||||||
self.info_labels = {
|
self.info_labels = {
|
||||||
"hora": ctk.CTkLabel(self.bottom_bar, text="Hora: --:--:--", font=("Arial", 12), text_color="black"),
|
"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"),
|
"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"),
|
"emails": ctk.CTkLabel(self.bottom_bar, text="Correos sin leer: 0", font=("Arial", 12), text_color="black"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,8 +266,6 @@ class CenteredWindow(ctk.CTk):
|
||||||
for label in self.info_labels.values():
|
for label in self.info_labels.values():
|
||||||
label.pack(side=ctk.LEFT, padx=10, pady=5)
|
label.pack(side=ctk.LEFT, padx=10, pady=5)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def dummy_action(self):
|
def dummy_action(self):
|
||||||
print("Acción no implementada")
|
print("Acción no implementada")
|
||||||
|
|
||||||
|
@ -321,3 +319,88 @@ class CenteredWindow(ctk.CTk):
|
||||||
self.radio_player.stop()
|
self.radio_player.stop()
|
||||||
self.radio_controls["play_button"].configure(state=tk.NORMAL)
|
self.radio_controls["play_button"].configure(state=tk.NORMAL)
|
||||||
self.radio_controls["stop_button"].configure(state=tk.DISABLED)
|
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}")
|
||||||
|
|
Loading…
Reference in New Issue