commit f736363f102ea43e8336b5725a646f2e51408b57 Author: NVitschDEV Date: Sat Jan 31 20:44:51 2026 +0100 Initial release diff --git a/.SRCINFO b/.SRCINFO new file mode 100644 index 000000000000..cea68b7c0648 --- /dev/null +++ b/.SRCINFO @@ -0,0 +1,11 @@ +pkgbase = ptodo + pkgdesc = My cool python script + pkgver = 1.0 + pkgrel = 1 + arch = any + depends = python + depends = python-rich + source = ptodo.py + sha256sums = 8b46988ddf1a9cbd4ed3579231be0dd4cdd353839ea0cc36bf450377dce34495 + +pkgname = ptodo diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000000..26739eb426b7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 NVitschDEV + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/PKGBUILD b/PKGBUILD new file mode 100644 index 000000000000..779d1ee24bc1 --- /dev/null +++ b/PKGBUILD @@ -0,0 +1,13 @@ +pkgname=ptodo +pkgver=1.0 +pkgrel=1 +pkgdesc="My cool python script" +arch=('any') +depends=('python' 'python-rich') +source=("ptodo.py") +sha256sums=('8b46988ddf1a9cbd4ed3579231be0dd4cdd353839ea0cc36bf450377dce34495') + +package() { + # Installs the script to /usr/bin/ and makes it executable + install -Dm755 "$srcdir/ptodo.py" "$pkgdir/usr/bin/ptodo" +} diff --git a/README.md b/README.md new file mode 100644 index 000000000000..23b335bad043 --- /dev/null +++ b/README.md @@ -0,0 +1,63 @@ +# TODOAPP + +This is a todolist app. +If you run the install script you will be able to run it in the terminal with the command 'todo'. +(The install script works only in bash terminals) +We are happy about any feedback! Do not hesitate. + +--- + +Make sure you have installed the dependencies. + +# DEPENDENCIES + +You need rich for python. + +```bash +python3 -m pip install rich +``` + +If pip is missing: +```bash +sudo apt install python3-pip +``` +or: +```bash +sudo pacman -S python-pip +``` + +# INSTALL + +You first need to clone the repo into ~/TODOAPP: + +```bash +git clone https://github.com/NVitschDEV/TODOAPP.git +``` + +Make sure the installer is executable: + +```bash +sudo chmod +x ~/TODOAPP/install.sh +``` + +Then simply run the install script: +```bash +~/TODOAPP/install.sh +``` +You will be able to use the app with this command. +```bash +todo +``` +Please dont try the uninstall script. It is in the betaphase. :) + +You can use an AUR helper +```bash +paru -S ptodo +``` + +You can clone it manually +```bash +git clone https://github.com/NVitschDEV/ptodo.git +cd ptodo/ +makepkg -si +``` diff --git a/TODOLIST.spec b/TODOLIST.spec new file mode 100644 index 000000000000..cfe2d2dc4960 --- /dev/null +++ b/TODOLIST.spec @@ -0,0 +1,38 @@ +# -*- mode: python ; coding: utf-8 -*- + + +a = Analysis( + ['TODOLIST.py'], + pathex=[], + binaries=[], + datas=[], + hiddenimports=[], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + noarchive=False, + optimize=0, +) +pyz = PYZ(a.pure) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.datas, + [], + name='TODOLIST', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=True, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) diff --git a/install.sh b/install.sh new file mode 100644 index 000000000000..869add873022 --- /dev/null +++ b/install.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# Colors because why not +GREEN="\033[1;32m" +RED="\033[1;31m" +RESET="\033[0m" + +# Somebody used nonexistent stuff... so here it is made existent. +print_msg() { + echo -e "${GREEN}[INSTALL]${RESET} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${RESET} $1" +} +sudo pacman -S python-rich + + +BASH_RC="$HOME/.bashrc" +CONFIG_LINE="alias todo='python3 $HOME/TODOAPP/TODOLIST.py'" + +# Edit .bashrc safely +if [ -f "$BASH_RC" ]; then + # Check if the line already exists (Idempotency check) + if grep -Fxq "$CONFIG_LINE" "$BASH_RC"; then + print_msg "Configuration already exists in $BASH_RC. Skipping." + else + print_msg "Backing up $BASH_RC to $BASH_RC.bak..." + cp "$BASH_RC" "$BASH_RC.bak" + + print_msg "Adding configuration to $BASH_RC..." + # Add a newline just in case the file doesn't end with one + echo "" >> "$BASH_RC" + echo "# Added by install.sh script" >> "$BASH_RC" + echo "$CONFIG_LINE" >> "$BASH_RC" + fi +else + print_error "$BASH_RC does not exist. (Are you using zsh?)" +fi + +print_msg "Installation complete!" +print_msg "Please restart your terminal or run: source $BASH_RC" diff --git a/ptodo.py b/ptodo.py new file mode 100644 index 000000000000..ca208f52f2e4 --- /dev/null +++ b/ptodo.py @@ -0,0 +1,178 @@ +#!/usr/bin/env python + +import json +import os +import time + +from rich import print as rprint +from rich.align import Align +from rich.console import Console +from rich.panel import Panel +from rich.prompt import IntPrompt, Prompt +from rich.table import Table + +FILENAME = "TODOLIST.json" +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 + + +def print_header(): + os.system("cls" if os.name == "nt" else "clear") + logo = r""" + [bold red]___________________ ________ ________ .____ .___ ____________________[/bold red] + [bold red]\__ ___/\_____ \ \______ \ \_____ \ | | | |/ _____/\__ ___/[/bold red] + [bold blue1] | | / | \ | | \ / | \| | | |\_____ \ | |[/bold blue1] + [bold blue] | | / | \| ` \ / | \ |___| |/ \ | |[/bold blue] + [bold blue] |____| \_______ /_______ / \_______ /_______ \___/_______ / |____|[/bold blue] + [dim] \/ \/ \/ \/ \/[/dim] + """ + 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 colorscemes(): + pass + + +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]Reload[/bold white]") + console.print("[6] [bold white]Exit[/bold white]") + + choice = Prompt.ask("\nChoose", choices=["1", "2", "3", "4", "5", "6", "exit"]) + + 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]Reload[/bold yellow]") + todos = load_todos() + elif choice == "6": + console.print("[bold yellow]Goodbye![/bold yellow]") + break + elif choice == "exit": + console.print("[bold yellow]Goodbye![/bold yellow]") + break + + +app()