aur/ptodo.py
2026-02-01 20:31:35 +01:00

258 lines
10 KiB
Python

#!/usr/bin/env python
import inspect
import json
import os
import pickle
import time
from rich.align import Align
from rich.console import Console
from rich.panel import Panel
from rich.prompt import Prompt
from rich.table import Table
FILENAME = "TODOLIST.json"
PICKLE_FILE = "my_data.pkl"
console = Console()
def load_todos():
if os.path.exists(FILENAME):
with open(FILENAME, "r") as f:
data = json.load(f)
if data and isinstance(data[0], str):
return [{"task": t, "done": False} for t in data]
return data
return []
def save_todos(todos):
with open(FILENAME, "w") as f:
json.dump(todos, f, indent=4)
def get_task_table(todos):
table = Table(show_header=True, header_style="bold magenta", expand=True)
table.add_column("#", style="dim", width=4, justify="center")
table.add_column("Task", style="cyan")
table.add_column("Status", justify="right")
if not todos:
return Panel("No tasks found! Get to work!", style="red")
for idx, item in enumerate(todos, 1):
# Check if done to change display
task_text = item["task"]
if item["done"]:
status = "[bold green]✔ Done[/bold green]"
display_task = f"[strike dim]{task_text}[/strike dim]"
else:
status = "[yellow]Pending[/yellow]"
display_task = task_text
table.add_row(str(idx), display_task, status)
return table
logo = r"""
[bold #cba6f7]___________________ ________ ________ .____ .___ ____________________[/bold #cba6f7]
[bold #cba6f7]\__ ___/\_____ \ \______ \ \_____ \ | | | |/ _____/\__ ___/[/bold #cba6f7]
[bold #89b4fa] | | / | \ | | \ / | \| | | |\_____ \ | |[/bold #89b4fa]
[bold #89b4fa] | | / | \| ` \ / | \ |___| |/ \ | |[/bold #89b4fa]
[bold #89b4fa] |____| \_______ /_______ / \_______ /_______ \___/_______ / |____|[/bold #89b4fa]
[#585b70] \/ \/ \/ \/ \/[/#585b70]
"""
def colorscemes():
global logo
print_header()
console.print("\n[1] [bold pink]Catppuchin (Mocha)[/bold pink]")
console.print("[2] [bold blue1]Tokyo Night[/bold blue1]")
console.print("[3] [bold orange]Dracula[/bold orange]")
console.print("[4] [bold red]Gruvbox[/bold red]")
console.print("[5] [bold blue]Nord[/bold blue]")
choice = Prompt.ask("\nChoose", choices=["1", "2", "3", "4", "5"])
if choice == "1":
logo = inspect.cleandoc(r"""
[bold #cba6f7]___________________ ________ ________ .____ .___ ____________________[/bold #cba6f7]
[bold #cba6f7]\__ ___/\_____ \ \______ \ \_____ \ | | | |/ _____/\__ ___/[/bold #cba6f7]
[bold #89b4fa] | | / | \ | | \ / | \| | | |\_____ \ | |[/bold #89b4fa]
[bold #89b4fa] | | / | \| ` \ / | \ |___| |/ \ | |[/bold #89b4fa]
[bold #89b4fa] |____| \_______ /_______ / \_______ /_______ \___/_______ / |____|[/bold #89b4fa]
[#585b70] \/ \/ \/ \/ \/[/#585b70]
""")
print_header()
time.sleep(1)
elif choice == "2":
logo = inspect.cleandoc(r"""
[bold #7aa2f7]___________________ ________ ________ .____ .___ ____________________[/bold #7aa2f7]
[bold #7aa2f7]\__ ___/\_____ \ \______ \ \_____ \ | | | |/ _____/\__ ___/[/bold #7aa2f7]
[bold #bb9af7] | | / | \ | | \ / | \| | | |\_____ \ | |[/bold #bb9af7]
[bold #bb9af7] | | / | \| ` \ / | \ |___| |/ \ | |[/bold #bb9af7]
[bold #bb9af7] |____| \_______ /_______ / \_______ /_______ \___/_______ / |____|[/bold #bb9af7]
[#565f89] \/ \/ \/ \/ \/[/#565f89]
""")
print_header()
time.sleep(1)
elif choice == "3":
logo = inspect.cleandoc(r"""
[bold #ff79c6]___________________ ________ ________ .____ .___ ____________________[/bold #ff79c6]
[bold #ff79c6]\__ ___/\_____ \ \______ \ \_____ \ | | | |/ _____/\__ ___/[/bold #ff79c6]
[bold #bd93f9] | | / | \ | | \ / | \| | | |\_____ \ | |[/bold #bd93f9]
[bold #bd93f9] | | / | \| ` \ / | \ |___| |/ \ | |[/bold #bd93f9]
[bold #bd93f9] |____| \_______ /_______ / \_______ /_______ \___/_______ / |____|[/bold #bd93f9]
[#6272a4] \/ \/ \/ \/ \/[/#6272a4]
""")
print_header()
time.sleep(1)
elif choice == "4":
logo = inspect.cleandoc(r"""
[bold #fb4934]___________________ ________ ________ .____ .___ ____________________[/bold #fb4934]
[bold #fb4934]\__ ___/\_____ \ \______ \ \_____ \ | | | |/ _____/\__ ___/[/bold #fb4934]
[bold #fabd2f] | | / | \ | | \ / | \| | | |\_____ \ | |[/bold #fabd2f]
[bold #fabd2f] | | / | \| ` \ / | \ |___| |/ \ | |[/bold #fabd2f]
[bold #fabd2f] |____| \_______ /_______ / \_______ /_______ \___/_______ / |____|[/bold #fabd2f]
[#928374] \/ \/ \/ \/ \/[/#928374]
""")
print_header()
time.sleep(1)
elif choice == "5":
logo = inspect.cleandoc(r"""
[bold #88C0D0]___________________ ________ ________ .____ .___ ____________________[/bold #88C0D0]
[bold #88C0D0]\__ ___/\_____ \ \______ \ \_____ \ | | | |/ _____/\__ ___/[/bold #88C0D0]
[bold #81A1C1] | | / | \ | | \ / | \| | | |\_____ \ | |[/bold #81A1C1]
[bold #81A1C1] | | / | \| ` \ / | \ |___| |/ \ | |[/bold #81A1C1]
[bold #81A1C1] |____| \_______ /_______ / \_______ /_______ \___/_______ / |____|[/bold #81A1C1]
[#4C566A] \/ \/ \/ \/ \/[/#4C566A]
""")
def print_header():
os.system("cls" if os.name == "nt" else "clear")
console.print(Align.center(logo))
def add_mode(todos):
while True:
print_header()
console.print(get_task_table(todos))
task = Prompt.ask("\n[bold green]Add Task[/bold green] (or 'exit')")
if task.lower() == "exit":
break
if task == "":
console.print("Please enter something")
time.sleep(1)
else:
todos.append({"task": task, "done": False})
save_todos(todos)
console.print(f"[green]Added:[/green] {task}")
def complete_mode(todos):
while True:
print_header()
console.print(get_task_table(todos))
task_num = Prompt.ask("\n[bold green]Complete Number[/bold green] (or 'exit')")
if task_num.lower() == "exit":
break
if task_num.isdigit():
idx = int(task_num) - 1
if 0 <= idx < len(todos):
todos[idx]["done"] = True
save_todos(todos)
console.print("[green]Task marked as done![/green]")
else:
console.print("[red]Invalid number![/red]")
def remove_mode(todos):
while True:
print_header()
console.print(get_task_table(todos))
task_num = Prompt.ask("\n[bold red]Delete Number[/bold red] (or 'exit')")
if task_num.lower() == "exit":
break
if task_num.isdigit():
idx = int(task_num) - 1
if 0 <= idx < len(todos):
removed = todos.pop(idx)["task"]
save_todos(todos)
console.print(f"[red]Removed:[/red] {removed}")
else:
console.print("[red]Invalid number![/red]")
def removeAll_mode(todos):
while True:
print_header()
console.print(get_task_table(todos))
task_1 = Prompt.ask(
"\n[bold red]ARE YOU SURE YOU WANT TO REMO0VE ALL TASKS?! Type 'YES' [/bold red] (or 'exit')"
)
if task_1.lower() == "exit":
break
elif task_1 == "YES":
os.remove(FILENAME)
break
else:
console.print("[red]Invalid number![/red]")
def app():
while True:
todos = load_todos()
print_header()
console.print(
Panel(
get_task_table(todos), title="Current To-Do List", border_style="blue"
)
)
console.print("\n[1] [bold green]Add Task[/bold green]")
console.print("[2] [bold blue1]Complete Task[/bold blue1]")
console.print("[3] [bold orange]Remove Task[/bold orange]")
console.print("[4] [bold red]Remove all[/bold red]")
console.print("[5] [bold white]Exit[/bold white]")
console.print("[6] [bold purple]Settings[/bold purple]")
choice = Prompt.ask("\nChoose", choices=["1", "2", "3", "4", "5", "exit", "6"])
if choice == "1":
add_mode(todos)
elif choice == "2":
complete_mode(todos)
elif choice == "3":
remove_mode(todos)
elif choice == "4":
removeAll_mode(todos)
elif choice == "5":
console.print("[bold yellow]Goodbye![/bold yellow]")
break
elif choice == "exit":
console.print("[bold yellow]Goodbye![/bold yellow]")
break
elif choice == "6":
colorscemes()
def load_logo():
global logo
if os.path.exists(PICKLE_FILE):
try:
with open(PICKLE_FILE, "rb") as f:
logo = pickle.load(f)
except Exception:
pass
def save_logo():
with open(PICKLE_FILE, "wb") as f:
pickle.dump(logo, f)
load_logo()
app()
save_logo()