218 lines
8.6 KiB
Python
218 lines
8.6 KiB
Python
import tkinter as tk
|
|
from tktooltip import ToolTip
|
|
from tkinter import ttk
|
|
from tkinter.messagebox import askyesno
|
|
from tkinter.filedialog import askopenfilename, asksaveasfilename
|
|
from icecream import ic
|
|
from functools import partial
|
|
from threading import Thread
|
|
import time
|
|
import model
|
|
import json
|
|
import matplotlib.pyplot as plt
|
|
|
|
|
|
queue = model.Queue()
|
|
|
|
btns = {}
|
|
|
|
root = tk.Tk()
|
|
root.title("Прям очень Таскер")
|
|
root.geometry("250x350")
|
|
root.option_add("*tearOff", tk.FALSE)
|
|
root.iconbitmap(default=model.resource_path("icon.ico"))
|
|
|
|
def save_session():
|
|
path = asksaveasfilename(filetypes=[("Json", '*.json')], defaultextension=".json")
|
|
ic(path)
|
|
data = {
|
|
"tasks": [task.__dict__ for id, task in queue.task_slots.items()],
|
|
"break": queue.task_brake.__dict__
|
|
}
|
|
with open(path, "w", encoding="utf-8") as f:
|
|
json.dump(data, f, ensure_ascii=False, indent=4)
|
|
|
|
def build_plt():
|
|
labels = [task.name for id, task in queue.task_slots.items()] + [queue.task_brake.name]
|
|
times = [int(task.time/60) for id, task in queue.task_slots.items()] + [int(queue.task_brake.time/60)]
|
|
ic(labels)
|
|
ic(times)
|
|
plt.figure(figsize=(len(labels), 2))
|
|
plt.bar(labels, times)
|
|
plt.title("Статистика выполнения")
|
|
plt.show()
|
|
# plt.savefig("chart.png")
|
|
|
|
def load_session():
|
|
path = askopenfilename(filetypes=[("Json", '*.json')])
|
|
ic(path)
|
|
with open(path, "r", encoding="utf-8") as f:
|
|
data = json.load(f)
|
|
queue.task_slots = {str(task["id"]): model.Task(**task) for task in data["tasks"]}
|
|
queue.task_brake = model.Task(**data["break"]) if data["break"] else None
|
|
refrash()
|
|
|
|
def refrash():
|
|
for id, task in queue.task_slots.items():
|
|
btns[str(id)]["text"] = f"{id} {task.name} ({task.count})"
|
|
if hasattr(btns[str(id)], 'toolTip'):
|
|
btns[str(id)].toolTip.on_leave()
|
|
btns[str(id)].toolTip.destroy()
|
|
btns[str(id)].toolTip = ToolTip(btns[str(id)], msg=task.description)
|
|
|
|
def start_task_unic(num, event):
|
|
if not queue.run_task:
|
|
queue.run_task = True
|
|
queue.start_unic_task(str(num))
|
|
btnLabel.bind("<Button-1>", pause_task)
|
|
btnLabel.bind("<Button-3>", stop_task)
|
|
if hasattr(btnLabel, 'toolTip'):
|
|
btnLabel.toolTip.on_leave()
|
|
btnLabel.toolTip.destroy()
|
|
btnLabel.toolTip = ToolTip(btnLabel, msg=queue.current_task.description)
|
|
Thread(target=do_task).start()
|
|
|
|
def start_task(event):
|
|
if not queue.run_task:
|
|
queue.run_task = True
|
|
queue.start_task()
|
|
btnLabel.bind("<Button-1>", pause_task)
|
|
btnLabel.bind("<Button-3>", stop_task)
|
|
if hasattr(btnLabel, 'toolTip'):
|
|
btnLabel.toolTip.on_leave()
|
|
btnLabel.toolTip.destroy()
|
|
btnLabel.toolTip = ToolTip(btnLabel, msg=queue.current_task.description)
|
|
Thread(target=do_task).start()
|
|
|
|
def restore_task(event):
|
|
queue.run_task = True
|
|
queue.current_task_time_max = queue.current_task_time_current + time.time()
|
|
Thread(target=do_task).start()
|
|
btnLabel.bind("<Button-1>", pause_task)
|
|
|
|
def pause_task(event):
|
|
myText = f"{btnLabel.cget('text')}\nПауза"
|
|
queue.run_task = False
|
|
time.sleep(0.2)
|
|
ic(myText)
|
|
btnLabel["text"] = myText
|
|
btnLabel.bind("<Button-1>", restore_task)
|
|
|
|
def stop_task(event):
|
|
queue.run_task = False
|
|
btnLabel["text"] = "Начать"
|
|
btnLabel.bind("<Button-1>", start_task)
|
|
if hasattr(btnLabel, 'toolTip'):
|
|
btnLabel.toolTip.on_leave()
|
|
btnLabel.toolTip.destroy()
|
|
btnLabel.toolTip = ToolTip(btnLabel, msg="Начать задачу")
|
|
|
|
|
|
def do_task():
|
|
ic(queue.current_task.name)
|
|
while queue.current_task_time_max > time.time() and queue.run_task:
|
|
queue.current_task_time_current = queue.current_task_time_max - time.time()
|
|
m, s = divmod(queue.current_task_time_current, 60)
|
|
btnLabel["text"] = f"{queue.current_task.name}\n{int(m)} минут {int(s)} секкунд"
|
|
time.sleep(1)
|
|
if queue.run_task:
|
|
queue.current_task.count += 1
|
|
queue.current_task.time += queue.current_task_time
|
|
if queue.current_task.id > 0:
|
|
ic(queue.task_slots)
|
|
if queue.task_slots[str(queue.current_task.id)].finished:
|
|
btns[str(queue.current_task.id)]["text"] = f"{queue.current_task.id} {queue.current_task.name} ({queue.current_task.count})\nЗавершено"
|
|
else:
|
|
btns[str(queue.current_task.id)]["text"] = f"{queue.current_task.id} {queue.current_task.name} ({queue.current_task.count})"
|
|
queue.sound()
|
|
stop_task(0)
|
|
|
|
def submit(window, btn, num, name, description, event=0):
|
|
name = name.get()
|
|
description = description.get()
|
|
ic(name, description)
|
|
btn["text"] = f"{num} {name} (0)"
|
|
if hasattr(btn, 'toolTip'):
|
|
btn.toolTip.on_leave()
|
|
btn.toolTip.destroy()
|
|
btn.toolTip = ToolTip(btn, msg=description)
|
|
queue.create_task(name, description, num)
|
|
window.destroy()
|
|
|
|
def finish_unfinished_task(btn, num, event):
|
|
if str(num) in queue.task_slots.keys():
|
|
if queue.task_slots[str(num)].finished:
|
|
result = askyesno(title="Подтвержение операции", message="Отменить завершение задачи?")
|
|
else:
|
|
result = askyesno(title="Подтвержение операции", message="Завершить задачу?")
|
|
if result:
|
|
queue.task_slots[str(num)].finished = False if queue.task_slots[str(num)].finished else True
|
|
if queue.task_slots[str(num)].finished:
|
|
btns[str(num)]["text"] = f"{queue.task_slots[str(num)].id} {queue.task_slots[str(num)].name} ({queue.task_slots[str(num)].count})\nЗавершено"
|
|
else:
|
|
btns[str(num)]["text"] = f"{queue.task_slots[str(num)].id} {queue.task_slots[str(num)].name} ({queue.task_slots[str(num)].count})"
|
|
|
|
|
|
def click(btn, num, event):
|
|
if (str(num) in queue.task_slots.keys()):
|
|
start_task_unic(num, 1)
|
|
else:
|
|
ic(event, btn, num)
|
|
window = tk.Toplevel()
|
|
window.title("Новая задача")
|
|
window.geometry("250x200")
|
|
label = ttk.Label(window, text=f"Имя задачи:")
|
|
input_name = ttk.Entry(window)
|
|
label_description = ttk.Label(window, text=f"Описание задачи (если необходимо):")
|
|
input_description = ttk.Entry(window)
|
|
window.bind('<Return>', partial(submit, window, btn, num, input_name, input_description))
|
|
button_sambit = ttk.Button(window, text="Создать задачу", command = partial(submit, window, btn, num, input_name, input_description))
|
|
label.pack(fill="both")
|
|
input_name.pack(expand=True, fill="both")
|
|
label_description.pack(fill="both")
|
|
input_description.pack(expand=True, fill="both")
|
|
input_name.focus()
|
|
button_sambit.pack(expand=True, fill="both")
|
|
window.grab_set()
|
|
window.attributes("-topmost",True)
|
|
|
|
def clear_task(btn, num, event):
|
|
result = askyesno(title="Подтвержение операции", message="Хотите удалить задачу?")
|
|
if result:
|
|
btn["text"] = f"{num} ____________ ()"
|
|
queue.delete_task(num)
|
|
|
|
|
|
for c in range(2): root.columnconfigure(index=c, weight=1)
|
|
for r in range(4): root.rowconfigure(index=r, weight=1)
|
|
|
|
for i in range(0,6):
|
|
btn = ttk.Button(text=f"{i+1} ____________ ()")
|
|
btn.bind("<Button-1>", partial(click, btn, i+1))
|
|
btn.bind("<Button-3>", partial(clear_task, btn, i+1))
|
|
btn.bind("<Button-2>", partial(finish_unfinished_task, btn, i+1))
|
|
btn.grid(column=(i%2), row=(i//2), sticky="nsew")
|
|
btns[str(i+1)] = btn
|
|
ic(btns)
|
|
|
|
btnLabel = ttk.Button(text=f"Начать")
|
|
btnLabel.bind("<Button-1>", start_task)
|
|
btnLabel.bind("<Button-3>", stop_task)
|
|
btnLabel.grid(column=0, row=3, columnspan=2, sticky="nsew")
|
|
|
|
main_menu = tk.Menu()
|
|
file_menu = tk.Menu()
|
|
file_menu.add_command(label="Сохранить сессию", command=save_session)
|
|
file_menu.add_command(label="Загрузить сессию", command=load_session)
|
|
# file_menu.add_separator()
|
|
# file_menu.add_command(label="Выход")
|
|
|
|
main_menu.add_cascade(label="Файл", menu=file_menu)
|
|
main_menu.add_cascade(label="График сессии", command=build_plt)
|
|
main_menu.add_cascade(label="Закрепить", command= lambda: root.attributes("-topmost",True))
|
|
|
|
root.config(menu=main_menu)
|
|
|
|
root.update_idletasks()
|
|
root.mainloop()
|
|
|