Añadir email y chat
This commit is contained in:
parent
22d3fb98ff
commit
83c4994194
219
main.py
219
main.py
|
|
@ -3,8 +3,8 @@ from tkinter import Menu, ttk, messagebox, filedialog
|
|||
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
||||
import os
|
||||
import threading
|
||||
from PIL import Image, ImageTk
|
||||
|
||||
# Importaciones de módulos de lógica
|
||||
import utility_thread as ut
|
||||
import monitor_logic as ml
|
||||
import alarm_logic as al
|
||||
|
|
@ -15,6 +15,8 @@ import camel_game_logic as cgl
|
|||
import audio_player_logic as apl
|
||||
import external_launcher as el
|
||||
import scraping_logic as sl
|
||||
import email_logic as eml
|
||||
import chat_logic as cl
|
||||
|
||||
# --- CLASE ALARMLISTFRAME ---
|
||||
class AlarmListFrame(tk.Frame):
|
||||
|
|
@ -88,11 +90,14 @@ class MainApplication(tk.Tk):
|
|||
self.selected_alarm_is_active = False
|
||||
self.camel_threads = []
|
||||
self.winner_name = None
|
||||
# Variables para el scraping
|
||||
|
||||
self.scraping_search_term_var = None
|
||||
self.scraping_results_text = None
|
||||
self.DEBUG_HTML_FILE = "amazon_debugging_output.html"
|
||||
|
||||
self.chat_display = None
|
||||
self.chat_net = cl.ChatNetwork(self.receive_chat_message)
|
||||
self.chat_net.start_server()
|
||||
|
||||
self.configure_layout()
|
||||
self.create_widgets()
|
||||
|
|
@ -102,14 +107,16 @@ class MainApplication(tk.Tk):
|
|||
self.start_alarm_checker()
|
||||
nm.start_network_monitoring_thread(self)
|
||||
|
||||
# INICIALIZAR EL REPRODUCTOR DE MÚSICA
|
||||
self.music_player = apl.MusicPlayer(self)
|
||||
self.protocol("WM_DELETE_WINDOW", self.on_closing)
|
||||
self.protocol("WM_DELETE_WINDOW", self.on_closing)
|
||||
|
||||
|
||||
def on_closing(self):
|
||||
"""Detiene la música y destruye la ventana al cerrar la app."""
|
||||
self.music_player.stop_music()
|
||||
self.destroy()
|
||||
if hasattr(self, 'chat_net'):
|
||||
self.chat_net.stop()
|
||||
|
||||
def configure_layout(self):
|
||||
self.columnconfigure(0, weight=0)
|
||||
|
|
@ -133,9 +140,11 @@ class MainApplication(tk.Tk):
|
|||
self.create_audio_player_tab()
|
||||
self.create_external_launcher_tab()
|
||||
self.create_scraping_tab()
|
||||
self.create_email_tab()
|
||||
|
||||
self.notebook.bind('<<NotebookTabChanged>>', self.on_tab_change)
|
||||
self.update_activity_status("Inicio de la aplicación")
|
||||
self.create_chat_tab()
|
||||
|
||||
|
||||
def create_menu(self):
|
||||
|
|
@ -393,7 +402,6 @@ class MainApplication(tk.Tk):
|
|||
tab_scraping.columnconfigure(0, weight=1)
|
||||
tab_scraping.rowconfigure(1, weight=1)
|
||||
|
||||
# 1. Controles Superiores (Término y Botón)
|
||||
frame_controls = ttk.Frame(tab_scraping, padding=10)
|
||||
frame_controls.grid(row=0, column=0, sticky='ew', pady=(0, 10))
|
||||
frame_controls.columnconfigure(1, weight=1)
|
||||
|
|
@ -405,7 +413,6 @@ class MainApplication(tk.Tk):
|
|||
|
||||
ttk.Button(frame_controls, text="START SCRAPING", command=self.start_scraping_callback).grid(row=0, column=2, padx=10, sticky='e')
|
||||
|
||||
# 2. Área de Resultados (Texto)
|
||||
frame_results = ttk.Frame(tab_scraping, relief=tk.SUNKEN, borderwidth=2)
|
||||
frame_results.grid(row=1, column=0, sticky='nsew', padx=5, pady=5)
|
||||
frame_results.columnconfigure(0, weight=1)
|
||||
|
|
@ -440,7 +447,6 @@ class MainApplication(tk.Tk):
|
|||
self.scraping_results_text.delete("1.0", tk.END)
|
||||
self.scraping_results_text.insert("1.0", f"Buscando productos en Amazon para '{search_term}' usando Playwright. Esto puede tardar unos segundos...\n")
|
||||
|
||||
# LLAMADA CLAVE: Inicia el proceso asíncrono en un hilo de trabajo
|
||||
sl.start_playwright_scraper(search_term, self)
|
||||
|
||||
def _display_scraping_results(self, results, search_term):
|
||||
|
|
@ -682,6 +688,205 @@ class MainApplication(tk.Tk):
|
|||
def start_alarm_checker(self):
|
||||
self.after(100, al.check_alarms, self.root, self.alarm_list_widget, self.show_alarm_popup)
|
||||
|
||||
|
||||
|
||||
# --- GESTIÓN DE EMAIL ---
|
||||
|
||||
def create_email_tab(self):
|
||||
"""Inicializa la pestaña de correo."""
|
||||
self.tab_email = ttk.Frame(self.notebook)
|
||||
self.notebook.add(self.tab_email, text="Correo ✉️")
|
||||
self.current_user = ""
|
||||
self.current_pass = ""
|
||||
self.show_email_login_screen()
|
||||
|
||||
def logout_email(self):
|
||||
"""Limpia la sesión y vuelve al login."""
|
||||
self.current_user = ""
|
||||
self.current_pass = ""
|
||||
self.show_email_login_screen()
|
||||
self.update_activity_status("Sesión de correo cerrada.")
|
||||
|
||||
def show_email_inbox(self, email_list):
|
||||
"""Bandeja de entrada responsive."""
|
||||
for widget in self.tab_email.winfo_children(): widget.destroy()
|
||||
|
||||
navbar = tk.Frame(self.tab_email, bg="white", height=50)
|
||||
navbar.pack(fill="x")
|
||||
ttk.Button(navbar, text="📝 Redactar", command=self.open_compose_window).pack(side="left", padx=10)
|
||||
ttk.Button(navbar, text="🔄 Actualizar", command=self.refresh_inbox).pack(side="left")
|
||||
ttk.Button(navbar, text="🚪 Cerrar Sesión", command=self.logout_email).pack(side="right", padx=10)
|
||||
|
||||
container = tk.Frame(self.tab_email, bg="#f0f2f5")
|
||||
container.pack(fill="both", expand=True)
|
||||
|
||||
canvas = tk.Canvas(container, bg="#f0f2f5", highlightthickness=0)
|
||||
sb = ttk.Scrollbar(container, command=canvas.yview)
|
||||
self.mail_frame = tk.Frame(canvas, bg="#f0f2f5")
|
||||
|
||||
self.mail_frame.bind("<Configure>", lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
|
||||
c_win = canvas.create_window((0,0), window=self.mail_frame, anchor="nw")
|
||||
canvas.bind("<Configure>", lambda e: canvas.itemconfig(c_win, width=e.width))
|
||||
|
||||
canvas.configure(yscrollcommand=sb.set)
|
||||
canvas.pack(side="left", fill="both", expand=True)
|
||||
sb.pack(side="right", fill="y")
|
||||
|
||||
for m in email_list: self.create_mail_card(m)
|
||||
|
||||
def show_email_login_screen(self):
|
||||
for widget in self.tab_email.winfo_children(): widget.destroy()
|
||||
|
||||
container = tk.Frame(self.tab_email, bg="#f5f7fa")
|
||||
container.place(relx=0, rely=0, relwidth=1, relheight=1)
|
||||
|
||||
card = tk.Frame(container, bg="white", padx=40, pady=40, highlightbackground="#d1d9e6", highlightthickness=1)
|
||||
card.place(relx=0.5, rely=0.5, anchor="center")
|
||||
|
||||
tk.Label(card, text="Acceso Correo", font=("Arial", 16, "bold"), bg="white").pack(pady=(0, 20))
|
||||
|
||||
tk.Label(card, text="Usuario", bg="white").pack(anchor="w")
|
||||
self.ent_user = tk.Entry(card, width=30, highlightthickness=1)
|
||||
self.ent_user.insert(0, "alumno@10.10.0.101")
|
||||
self.ent_user.pack(pady=5)
|
||||
|
||||
tk.Label(card, text="Contraseña", bg="white").pack(anchor="w")
|
||||
self.ent_pass = tk.Entry(card, show="*", width=30, highlightthickness=1)
|
||||
self.ent_pass.pack(pady=5)
|
||||
|
||||
tk.Button(card, text="ENTRAR", bg="#3498db", fg="white", font=("Arial", 10, "bold"),
|
||||
command=self.do_email_login, padx=20, pady=10).pack(pady=20, fill="x")
|
||||
|
||||
def do_email_login(self):
|
||||
"""Realiza la conexión inicial."""
|
||||
u, p = self.ent_user.get(), self.ent_pass.get()
|
||||
success, data = eml.fetch_emails_logic(u, p)
|
||||
if success:
|
||||
self.current_user, self.current_pass = u, p
|
||||
self.show_email_inbox(data)
|
||||
else:
|
||||
messagebox.showerror("Error", "Credenciales incorrectas o error de red")
|
||||
|
||||
def refresh_inbox(self):
|
||||
"""Actualiza la bandeja."""
|
||||
success, data = eml.fetch_emails_logic(self.current_user, self.current_pass)
|
||||
if success: self.show_email_inbox(data)
|
||||
|
||||
def create_mail_card(self, mail):
|
||||
"""Tarjetas expandibles de correo."""
|
||||
card = tk.Frame(self.mail_frame, bg="white", highlightbackground="#ddd", highlightthickness=1)
|
||||
card.pack(fill="x", pady=5, padx=15)
|
||||
|
||||
header = tk.Label(card, text=f"De: {mail['sender']}\nAsunto: {mail['subject']}",
|
||||
font=("Arial", 10, "bold"), bg="white", justify="left", anchor="w", pady=10, padx=10)
|
||||
header.pack(fill="x")
|
||||
|
||||
body_box = tk.Frame(card, bg="#f9f9f9")
|
||||
self.img_refs = []
|
||||
|
||||
def expand(event):
|
||||
if body_box.winfo_ismapped(): body_box.pack_forget()
|
||||
else:
|
||||
success, data = eml.fetch_email_full_data(self.current_user, self.current_pass, mail['id'])
|
||||
if success:
|
||||
for w in body_box.winfo_children(): w.destroy()
|
||||
txt = tk.Text(body_box, height=8, bg="#f9f9f9", bd=0, padx=10, pady=10)
|
||||
txt.insert("1.0", data['body'])
|
||||
txt.config(state="disabled")
|
||||
txt.pack(fill="x")
|
||||
|
||||
for img in data['images']:
|
||||
try:
|
||||
photo = ImageTk.PhotoImage(Image.open(img).convert("RGB").resize((300, 300)))
|
||||
self.img_refs.append(photo)
|
||||
tk.Label(body_box, image=photo, bg="#f9f9f9").pack(pady=5)
|
||||
except: pass
|
||||
|
||||
for f_path in data['files']:
|
||||
tk.Button(body_box, text=f"📄 Abrir: {os.path.basename(f_path)}",
|
||||
fg="blue", command=lambda p=f_path: os.system(f'xdg-open "{p}"'),
|
||||
bg="#f9f9f9", bd=0).pack(anchor="w", padx=20, pady=5)
|
||||
|
||||
body_box.pack(fill="x")
|
||||
|
||||
header.bind("<Button-1>", expand)
|
||||
|
||||
def open_compose_window(self):
|
||||
comp = tk.Toplevel(self); comp.title("Redactar"); comp.geometry("400x500")
|
||||
tk.Label(comp, text="Para:").pack(padx=10, anchor="w")
|
||||
e_to = tk.Entry(comp); e_to.pack(fill="x", padx=10)
|
||||
tk.Label(comp, text="Asunto:").pack(padx=10, anchor="w")
|
||||
e_sub = tk.Entry(comp); e_sub.pack(fill="x", padx=10)
|
||||
|
||||
self.attachment_path = None
|
||||
lbl_file = tk.Label(comp, text="Sin archivo")
|
||||
def attach():
|
||||
self.attachment_path = filedialog.askopenfilename()
|
||||
if self.attachment_path: lbl_file.config(text=os.path.basename(self.attachment_path), fg="blue")
|
||||
|
||||
tk.Button(comp, text="📎 Adjuntar", command=attach).pack(pady=5)
|
||||
lbl_file.pack()
|
||||
txt = tk.Text(comp, height=10); txt.pack(fill="both", expand=True, padx=10, pady=10)
|
||||
|
||||
def send():
|
||||
s, m = eml.send_email_logic(self.current_user, e_to.get(), e_sub.get(), txt.get("1.0", "end"), self.current_pass, self.attachment_path)
|
||||
if s: messagebox.showinfo("OK", "Enviado"); comp.destroy()
|
||||
else: messagebox.showerror("Error", m)
|
||||
|
||||
tk.Button(comp, text="ENVIAR 🚀", bg="#2ecc71", fg="white", command=send).pack(pady=10)
|
||||
|
||||
|
||||
|
||||
# --- GESTIÓN DEL CHAT ---
|
||||
|
||||
def create_chat_tab(self):
|
||||
import os
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
|
||||
tab_chat = ttk.Frame(self.notebook)
|
||||
self.notebook.add(tab_chat, text="Chat Grupal 💬", padding=15)
|
||||
|
||||
tab_chat.columnconfigure(0, weight=1)
|
||||
tab_chat.rowconfigure(2, weight=1)
|
||||
|
||||
mi_pid = os.getpid()
|
||||
|
||||
lbl_pid = tk.Label(tab_chat, text=f"📍 TU NÚMERO DE PROCESO (PID) ES: {mi_pid}",
|
||||
font=("Arial", 14, "bold"), fg="#2c3e50", bg="#ecf0f1", pady=10, relief="groove")
|
||||
lbl_pid.grid(row=0, column=0, sticky="ew", pady=(0, 10))
|
||||
|
||||
tk.Label(tab_chat, text="Sala general (todos los procesos leen y escriben aquí):",
|
||||
font=("Arial", 10, "bold"), anchor="w").grid(row=1, column=0, sticky="ew")
|
||||
|
||||
self.chat_display = tk.Text(tab_chat, state='disabled', height=15, bg="#fdfdfd", font=("Consolas", 11))
|
||||
self.chat_display.grid(row=2, column=0, sticky="nsew", pady=5)
|
||||
|
||||
frame_input = ttk.Frame(tab_chat)
|
||||
frame_input.grid(row=3, column=0, sticky="ew", pady=(5, 0))
|
||||
|
||||
self.chat_entry = ttk.Entry(frame_input, font=("Arial", 11))
|
||||
self.chat_entry.pack(side="left", fill="x", expand=True, padx=(0, 5))
|
||||
self.chat_entry.bind("<Return>", lambda e: self.send_chat_message())
|
||||
|
||||
ttk.Button(frame_input, text="Enviar 🚀", command=self.send_chat_message).pack(side="right")
|
||||
|
||||
def send_chat_message(self):
|
||||
msg = self.chat_entry.get()
|
||||
if msg.strip():
|
||||
if self.chat_net.send_message(msg):
|
||||
self.chat_entry.delete(0, tk.END)
|
||||
|
||||
def receive_chat_message(self, message):
|
||||
import tkinter as tk
|
||||
def _actualizar_ui():
|
||||
if self.chat_display and self.chat_display.winfo_exists():
|
||||
self.chat_display.config(state='normal')
|
||||
self.chat_display.insert(tk.END, message + "\n")
|
||||
self.chat_display.see(tk.END)
|
||||
self.chat_display.config(state='disabled')
|
||||
|
||||
self.after(0, _actualizar_ui)
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = MainApplication()
|
||||
|
|
|
|||
Loading…
Reference in New Issue