Загрузить файлы в «/»

This commit is contained in:
allecks 2025-02-09 23:16:20 +01:00
parent b8b62f37b1
commit 34cc4a3569
5 changed files with 325 additions and 0 deletions

BIN
break.mp3 Normal file

Binary file not shown.

BIN
default.mp3 Normal file

Binary file not shown.

BIN
icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

107
model.py Normal file
View file

@ -0,0 +1,107 @@
from icecream import ic
from dataclasses import dataclass
from random import randint
import pygame
import time
import sys
import os
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
class Queue(object):
def __init__(self):
self.tasks = []
self.task_slots = {}
self.task_brake = self.set_break()
self.run_task = False
self.task_slots_max = 6
self.current_task = None
self.current_task_time = 0
self.current_task_time_current = 0
self.current_task_time_max = 0
pygame.mixer.init()
def sound(self):
sound = pygame.mixer.Sound(resource_path(self.current_task.sound))
sound.play()
def set_break(self):
task_id = -1
task_name = f"Перерыв 10 минут"
task_count = 0
task_description = f"Десятиминутный перерыв"
task_time = 0
task_sound = f"./sounds/break.mp3"
return Task(task_id, task_name, task_count, task_description, task_time, task_sound, False)
def create_task(self, name, description = '', num = 0):
task_id = num
task_name = name
task_count = 0
task_description = description
task_time = 0
task_sound = f"./sounds/default.mp3"
self.task_slots[str(num)]=Task(task_id, task_name, task_count, task_description, task_time, task_sound, False)
def delete_task(self, num):
del self.task_slots[str(num)]
def start_unic_task(self, num):
task_keys = [key for key in list(self.task_slots.keys()) if not self.task_slots[key].finished]
if num in task_keys:
result = num
d = dice()
if d == 5:
self.current_task = self.task_brake
self.current_task_time = timers[d]
self.current_task_time_max = time.time() + self.current_task_time
else:
self.current_task = self.task_slots[result]
self.current_task_time = timers[d]
self.current_task_time_max = time.time() + self.current_task_time
else:
return
def start_task(self):
task_keys = [key for key in list(self.task_slots.keys()) if not self.task_slots[key].finished]
ic(task_keys)
result = task_keys[randint(0, len(task_keys) - 1)]
d = dice()
if d == 5:
self.current_task = self.task_brake
self.current_task_time = timers[d]
self.current_task_time_max = time.time() + self.current_task_time
else:
self.current_task = self.task_slots[result]
self.current_task_time = timers[d]
self.current_task_time_max = time.time() + self.current_task_time
def dice():
return randint(0,5)
@dataclass
class Task:
id: int
name: str
count: int #1-6
description: str
time: int #seconds
sound: str #path to sound file
finished: bool
timers = [
600, #10minutes
1200, #20minutes
1800, #30minutes
2400, #40minutes
3000, #50minutes
600, #10minutes break
]

218
view.py Normal file
View file

@ -0,0 +1,218 @@
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()