| import os |
| import threading |
| import queue |
| import webbrowser |
| from pathlib import Path |
| import tkinter as tk |
| from tkinter import ttk, scrolledtext, messagebox, filedialog |
|
|
| from bot import BotRunner |
| from config import DEFAULT_CREDENTIALS_FILE, save_credentials |
|
|
|
|
| LOG_POLL_MS = 200 |
|
|
|
|
| class GUI: |
| def __init__(self, root: tk.Tk): |
| self.root = root |
| root.title("ADM PURCHASING TOOLS") |
| root.geometry("760x620") |
|
|
| self.log_queue = queue.Queue() |
| self.stop_event = threading.Event() |
| self.worker_thread = None |
|
|
| frm = ttk.Frame(root, padding=12) |
| frm.pack(fill=tk.BOTH, expand=True) |
|
|
| |
| inputs = ttk.Frame(frm) |
| inputs.pack(fill=tk.X) |
|
|
| ttk.Label(inputs, text="Username:").grid(row=0, column=0, sticky=tk.W, pady=4) |
| self.username_var = tk.StringVar() |
| ttk.Entry(inputs, textvariable=self.username_var, width=40).grid(row=0, column=1, sticky=tk.W) |
|
|
| ttk.Label(inputs, text="Password:").grid(row=1, column=0, sticky=tk.W, pady=4) |
| self.password_var = tk.StringVar() |
| ttk.Entry(inputs, textvariable=self.password_var, width=40, show="*").grid(row=1, column=1, sticky=tk.W) |
|
|
| ttk.Label(inputs, text="Studio URL or Name:").grid(row=2, column=0, sticky=tk.W, pady=4) |
| self.studio_var = tk.StringVar() |
| ttk.Entry(inputs, textvariable=self.studio_var, width=60).grid(row=2, column=1, sticky=tk.W) |
|
|
| ttk.Label(inputs, text="Minimum Price:").grid(row=3, column=0, sticky=tk.W, pady=4) |
| self.min_price_var = tk.StringVar(value="6.00") |
| ttk.Entry(inputs, textvariable=self.min_price_var, width=12).grid(row=3, column=1, sticky=tk.W) |
|
|
| |
| btns = ttk.Frame(frm, padding=(0, 8, 0, 8)) |
| btns.pack(fill=tk.X) |
|
|
| self.start_btn = ttk.Button(btns, text="Start", command=self.start) |
| self.start_btn.pack(side=tk.LEFT, padx=6) |
| self.stop_btn = ttk.Button(btns, text="Stop", command=self.stop, state=tk.DISABLED) |
| self.stop_btn.pack(side=tk.LEFT, padx=6) |
| ttk.Button(btns, text="Open Export Folder", command=self.open_exports).pack(side=tk.LEFT, padx=6) |
| ttk.Button(btns, text="Save Credentials", command=self.save_creds).pack(side=tk.LEFT, padx=6) |
|
|
| |
| status_frame = ttk.Frame(frm) |
| status_frame.pack(fill=tk.X) |
| self.status_var = tk.StringVar(value="Ready") |
| ttk.Label(status_frame, textvariable=self.status_var).pack(side=tk.LEFT) |
| self.progress = ttk.Progressbar(status_frame, mode="indeterminate") |
| self.progress.pack(fill=tk.X, padx=8, pady=6) |
|
|
| |
| ttk.Label(frm, text="Logs:").pack(anchor=tk.W) |
| self.log_widget = scrolledtext.ScrolledText(frm, height=20, state=tk.DISABLED) |
| self.log_widget.pack(fill=tk.BOTH, expand=True) |
|
|
| |
| root.after(LOG_POLL_MS, self._poll_log) |
|
|
| def append_log(self, text: str): |
| self.log_widget.configure(state=tk.NORMAL) |
| self.log_widget.insert(tk.END, text + "\n") |
| self.log_widget.see(tk.END) |
| self.log_widget.configure(state=tk.DISABLED) |
|
|
| def _poll_log(self): |
| try: |
| while True: |
| item = self.log_queue.get_nowait() |
| if isinstance(item, dict) and item.get("type") == "status": |
| self.status_var.set(item.get("text", "")) |
| else: |
| self.append_log(str(item)) |
| except queue.Empty: |
| pass |
| finally: |
| self.root.after(LOG_POLL_MS, self._poll_log) |
|
|
| def start(self): |
| username = self.username_var.get().strip() |
| password = self.password_var.get().strip() |
| studio = self.studio_var.get().strip() |
| try: |
| min_price = float(self.min_price_var.get().strip()) |
| except Exception: |
| messagebox.showerror("Invalid input", "Minimum price must be a number") |
| return |
|
|
| if not username or not password or not studio: |
| messagebox.showerror("Missing fields", "Please enter username, password and studio URL/name") |
| return |
|
|
| self.stop_event.clear() |
| self.start_btn.config(state=tk.DISABLED) |
| self.stop_btn.config(state=tk.NORMAL) |
| self.progress.start(10) |
| self.status_var.set("Starting...") |
|
|
| runner = BotRunner( |
| username=username, |
| password=password, |
| studio_input=studio, |
| min_price=min_price, |
| log_queue=self.log_queue, |
| stop_event=self.stop_event, |
| ) |
|
|
| def worker(): |
| try: |
| runner.run() |
| self.log_queue.put({"type": "status", "text": "Completed"}) |
| except Exception as e: |
| self.log_queue.put(f"Error: {e}") |
| finally: |
| self.progress.stop() |
| self.start_btn.config(state=tk.NORMAL) |
| self.stop_btn.config(state=tk.DISABLED) |
|
|
| self.worker_thread = threading.Thread(target=worker, daemon=True) |
| self.worker_thread.start() |
|
|
| def stop(self): |
| if messagebox.askyesno("Stop", "Stop the running job?"): |
| self.stop_event.set() |
| self.status_var.set("Stopping...") |
|
|
| def open_exports(self): |
| p = Path.cwd() |
| webbrowser.open(p.as_uri()) |
|
|
| def save_creds(self): |
| u = self.username_var.get().strip() |
| p = self.password_var.get().strip() |
| if not u or not p: |
| messagebox.showerror("Error", "Provide both username and password to save") |
| return |
| save_credentials(u, p, DEFAULT_CREDENTIALS_FILE) |
| messagebox.showinfo("Saved", f"Credentials saved to {DEFAULT_CREDENTIALS_FILE}") |
|
|
|
|
| def run_gui(): |
| root = tk.Tk() |
| gui = GUI(root) |
| root.mainloop() |
|
|