From 183d991e05100d7a58f4ee8d310fbd52fd3e32e3 Mon Sep 17 00:00:00 2001 From: Don Harper Date: Sat, 13 Jun 2026 23:53:34 -0500 Subject: [PATCH] remove tui display as it never really worked --- README.md | 7 - pyproject.toml | 7 +- src/pen_tracker.egg-info/PKG-INFO | 10 +- src/pen_tracker.egg-info/SOURCES.txt | 2 - src/pen_tracker.egg-info/entry_points.txt | 1 - src/pen_tracker.egg-info/requires.txt | 1 - src/pen_tracker/cli.py | 31 +-- src/pen_tracker/tui.py | 231 ---------------------- 8 files changed, 23 insertions(+), 267 deletions(-) delete mode 100644 src/pen_tracker.egg-info/requires.txt delete mode 100644 src/pen_tracker/tui.py diff --git a/README.md b/README.md index da2e4ae..ad359b5 100644 --- a/README.md +++ b/README.md @@ -30,17 +30,10 @@ pen-tracker list pen-tracker export --output my_pens.json ``` -### TUI - -```bash -pen-tui -``` - ## Features - Track fountain pens with details like make, model, nib, ink, etc. - CLI interface with interactive and command-line modes -- TUI interface using Textual - Data stored in CSV format - Export to JSON - Input validation for dates diff --git a/pyproject.toml b/pyproject.toml index c2786e5..b2763bb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,20 +4,17 @@ build-backend = "setuptools.build_meta" [project] name = "pen-tracker" -version = "0.4.2" +version = "0.5.0" authors = [ { name="Don Harper", email="don@donharper.org" }, ] description = "A fountain pen collection tracker." readme = "README.md" requires-python = ">=3.8" -dependencies = [ - "textual", -] +dependencies = [] [project.scripts] pen-tracker = "pen_tracker.cli:main" -pen-tui = "pen_tracker.tui:main" [tool.setuptools.packages.find] where = ["src"] diff --git a/src/pen_tracker.egg-info/PKG-INFO b/src/pen_tracker.egg-info/PKG-INFO index af55fcb..26d8654 100644 --- a/src/pen_tracker.egg-info/PKG-INFO +++ b/src/pen_tracker.egg-info/PKG-INFO @@ -1,12 +1,11 @@ Metadata-Version: 2.4 Name: pen-tracker -Version: 0.4.2 +Version: 0.5.0 Summary: A fountain pen collection tracker. Author-email: Don Harper Requires-Python: >=3.8 Description-Content-Type: text/markdown License-File: LICENSE -Requires-Dist: textual Dynamic: license-file # Pen Tracker @@ -41,17 +40,10 @@ pen-tracker list pen-tracker export --output my_pens.json ``` -### TUI - -```bash -pen-tui -``` - ## Features - Track fountain pens with details like make, model, nib, ink, etc. - CLI interface with interactive and command-line modes -- TUI interface using Textual - Data stored in CSV format - Export to JSON - Input validation for dates diff --git a/src/pen_tracker.egg-info/SOURCES.txt b/src/pen_tracker.egg-info/SOURCES.txt index 4c88beb..0e75d83 100644 --- a/src/pen_tracker.egg-info/SOURCES.txt +++ b/src/pen_tracker.egg-info/SOURCES.txt @@ -4,11 +4,9 @@ pyproject.toml src/pen_tracker/__init__.py src/pen_tracker/cli.py src/pen_tracker/engine.py -src/pen_tracker/tui.py src/pen_tracker.egg-info/PKG-INFO src/pen_tracker.egg-info/SOURCES.txt src/pen_tracker.egg-info/dependency_links.txt src/pen_tracker.egg-info/entry_points.txt -src/pen_tracker.egg-info/requires.txt src/pen_tracker.egg-info/top_level.txt tests/test_engine.py \ No newline at end of file diff --git a/src/pen_tracker.egg-info/entry_points.txt b/src/pen_tracker.egg-info/entry_points.txt index 5530550..95d4225 100644 --- a/src/pen_tracker.egg-info/entry_points.txt +++ b/src/pen_tracker.egg-info/entry_points.txt @@ -1,3 +1,2 @@ [console_scripts] pen-tracker = pen_tracker.cli:main -pen-tui = pen_tracker.tui:main diff --git a/src/pen_tracker.egg-info/requires.txt b/src/pen_tracker.egg-info/requires.txt deleted file mode 100644 index a75a51d..0000000 --- a/src/pen_tracker.egg-info/requires.txt +++ /dev/null @@ -1 +0,0 @@ -textual diff --git a/src/pen_tracker/cli.py b/src/pen_tracker/cli.py index 176cd6d..9233355 100644 --- a/src/pen_tracker/cli.py +++ b/src/pen_tracker/cli.py @@ -68,7 +68,9 @@ class CLITracker(PenTracker): try: idx = int(input("\nEnter the ID of the pen to edit: ")) - pen = self.pens[idx] + if idx < 1: + raise ValueError + pen = self.pens[idx - 1] except (ValueError, IndexError): print("[!] Invalid ID.") return @@ -110,7 +112,7 @@ class CLITracker(PenTracker): """Helper to print a list without the interactive menu logic.""" print(f"{'ID':<4} | {'MAKE':<12} | {'MODEL':<12} | {'BODY':<12} | {'CAP':<12} | {'NIB':<3} | {'INK':<15} | {'INKED DATE':<12}") print("-" * 102) - for idx, pen in enumerate(self.pens): + for idx, pen in enumerate(self.pens, start=1): make = pen.Make[:12] model = pen.Model[:12] body = pen.Body[:12] @@ -131,7 +133,10 @@ class CLITracker(PenTracker): choice = input("\nEnter ID to see full details (or 'b' to go back): ") if choice.lower() != 'b': try: - self.view_pen_details(int(choice)) + idx = int(choice) + if idx < 1: + raise ValueError + self.view_pen_details(idx - 1) except (ValueError, IndexError): print("[!] Invalid ID.") @@ -153,7 +158,9 @@ class CLITracker(PenTracker): self.show_summary_list() try: idx = int(input("\nEnter the ID of the pen to delete: ")) - removed = self.pens.pop(idx) + if idx < 1: + raise ValueError + removed = self.pens.pop(idx - 1) self.save_data() print(f"\n[!] Removed: {removed.Make} {removed.Model}") except (ValueError, IndexError): @@ -192,18 +199,18 @@ class CLITracker(PenTracker): print("\n[!] Your ink collection is currently empty.") return - print("\n" + "="*80) + print("\n" + "="*100) print(f"{'ID':<4} | {'VENDOR':<12} | {'NAME':<20} | {'COLOR':<15} | {'SIZE':<30}") - print("-" * 80) + print("-" * 100) - for idx, ink in enumerate(self.ink_tracker.inks): + for idx, ink in enumerate(self.ink_tracker.inks, start=1): vendor = ink.Vendor[:12] name = ink.Name[:20] color = ink.Color[:15] size = ink.Size[:30] print(f"{idx:<4} | {vendor:<12} | {name:<20} | {color:<15} | {size:<30}") - print("="*80) + print("="*100) def select_ink(self): """Helper method to select an ink from the list.""" @@ -213,10 +220,12 @@ class CLITracker(PenTracker): self.view_all_inks() try: - idx = int(input("\nEnter the ID of the ink to select (or -1 for N/A): ")) - if idx == -1: + idx = int(input("\nEnter the ID of the ink to select (or 0 for N/A): ")) + if idx == 0: return "N/A" - ink = self.ink_tracker.inks[idx] + if idx < 0: + raise ValueError + ink = self.ink_tracker.inks[idx - 1] return ink.Name except (ValueError, IndexError): print("[!] Invalid ID.") diff --git a/src/pen_tracker/tui.py b/src/pen_tracker/tui.py deleted file mode 100644 index ed32fb1..0000000 --- a/src/pen_tracker/tui.py +++ /dev/null @@ -1,231 +0,0 @@ -from textual.app import App, ComposeResult -from textual.screen import Screen -from textual.widgets import Label, Input, Button, Header, Footer, DataTable -from textual.containers import Vertical, Horizontal -from textual.binding import Binding -from .engine import PenTracker, Pen, InkTracker, Ink -# --- TUI SCREENS --- - -class PenFormScreen(Screen): - """A screen for adding or editing a pen.""" - - def __init__(self, tracker, existing_pen=None): - super().__init__() - self.tracker = tracker - self.existing_pen = existing_pen - - def compose(self) -> ComposeResult: - with Vertical(id="form-container"): - yield Label("📝 NEW PEN" if not self.existing_pen else "✏️ EDIT PEN") - - for header in self.tracker.headers: - field = self.tracker.key_map.get(header, header) - val = getattr(self.existing_pen, field) if self.existing_pen else "" - yield Input(value=val, placeholder=header, id=header) - - with Horizontal(): - yield Button("Save", variant="success", id="save_cmd") - yield Button("Cancel", variant="error", id="cancel_cmd") - - def on_button_pressed(self, event: Button.Pressed) -> None: - if event.button.id == "cancel_cmd": - self.dismiss() - return - - new_data = {} - for header in self.tracker.headers: - try: - input_widget = self.query_one(f"#{header}", Input) - new_data[header] = input_widget.value if input_widget.value.strip() else "N/A" - except Exception: - new_data[header] = "N/A" - - # Map to Pen fields - mapped_data = {self.tracker.key_map.get(k, k): v for k, v in new_data.items()} - new_pen = Pen(**mapped_data) - - if self.existing_pen is not None and self.existing_pen in self.tracker.pens: - idx = self.tracker.pens.index(self.existing_pen) - self.tracker.pens[idx] = new_pen - else: - self.tracker.pens.append(new_pen) - - # save_data() handles the sorting internally - self.tracker.save_data() - self.dismiss(new_pen) - -class InkFormScreen(Screen): - """A screen for adding or editing an ink.""" - - def __init__(self, ink_tracker, existing_ink=None): - super().__init__() - self.ink_tracker = ink_tracker - self.existing_ink = existing_ink - - def compose(self) -> ComposeResult: - with Vertical(id="form-container"): - yield Label("🖋️ NEW INK" if not self.existing_ink else "✏️ EDIT INK") - - for header in self.ink_tracker.headers: - val = getattr(self.existing_ink, header) if self.existing_ink else "" - yield Input(value=val, placeholder=header, id=header) - - with Horizontal(): - yield Button("Save", variant="success", id="save_cmd") - yield Button("Cancel", variant="error", id="cancel_cmd") - - def on_button_pressed(self, event: Button.Pressed) -> None: - if event.button.id == "cancel_cmd": - self.dismiss() - return - - new_data = {} - for header in self.ink_tracker.headers: - try: - input_widget = self.query_one(f"#{header}", Input) - new_data[header] = input_widget.value if input_widget.value.strip() else "N/A" - except Exception: - new_data[header] = "N/A" - - new_ink = Ink(**new_data) - - if self.existing_ink is not None and self.existing_ink in self.ink_tracker.inks: - idx = self.ink_tracker.inks.index(self.existing_ink) - self.ink_tracker.inks[idx] = new_ink - else: - self.ink_tracker.inks.append(new_ink) - - self.ink_tracker.save_data() - self.dismiss(new_ink) - -class PenTrackerApp(App): - """The Main TUI Application.""" - - CSS = """ - #form-container { - width: 60%; - height: auto; - border: heavy white; - padding: 1 2; - margin: 5 10; - background: $panel; - } - Label { - width: 100%; - text-align: center; - text-style: bold; - margin-bottom: 1; - } - Input { - margin-bottom: 1; - } - Horizontal { - align: center middle; - height: auto; - } - Button { - margin: 0 1; - } - DataTable { - height: 1fr; - } - """ - - BINDINGS = [ - Binding("d", "delete_selected", "Delete Selected"), - Binding("a", "add_new", "Add New"), - Binding("i", "toggle_mode", "Toggle Pens/Inks"), - Binding("q", "quit", "Quit"), - ] - - def compose(self) -> ComposeResult: - yield Header() - yield DataTable(id="pen_table") - yield Footer() - - def on_mount(self) -> None: - self.tracker = PenTracker() - self.ink_tracker = InkTracker() - self.mode = "pens" # "pens" or "inks" - self._refresh_table() - - def _refresh_table(self): - table = self.query_one("#pen_table", DataTable) - table.clear(columns=True) - - if self.mode == "pens": - display_cols = ['Make', 'Model', 'Nib', 'Nib-Material', 'Body','Cap', 'Current-Ink', 'Inked-date', 'Notes'] - table.add_columns(*display_cols) - items = self.tracker.pens - else: # inks - display_cols = ['Vendor', 'Name', 'Color', 'Purchased', 'Size', 'Notes'] - table.add_columns(*display_cols) - items = self.ink_tracker.inks - - for idx, item in enumerate(items): - if self.mode == "pens": - row_values = [getattr(item, c.replace('-','_')) for c in display_cols] - else: - row_values = [getattr(item, c) for c in display_cols] - table.add_row(*row_values, key=str(idx)) - - def action_add_new(self) -> None: - if self.mode == "pens": - form = PenFormScreen(self.tracker) - else: - form = InkFormScreen(self.ink_tracker) - self.push_screen(form, self.handle_form_result) - - def action_edit_selected(self, index_str: str): - try: - idx = int(index_str) - if self.mode == "pens": - existing_item = self.tracker.pens[idx] - form = PenFormScreen(self.tracker, existing_item) - else: - existing_item = self.ink_tracker.inks[idx] - form = InkFormScreen(self.ink_tracker, existing_item) - self.push_screen(form, self.handle_form_result) - except (ValueError, IndexError): - pass - - def handle_form_result(self, updated_pen_data) -> None: - if updated_pen_data: - self._refresh_table() - self.notify("Collection Updated & Sorted!", title="Success") - - def action_delete_selected(self) -> None: - table = self.query_one("#pen_table", DataTable) - try: - table = self.query_one("#pen_table", DataTable) - row_node = table.get_row_at_cursor() - idx = int(row_node.key.value) - if self.mode == "pens": - removed = self.tracker.pens.pop(idx) - self.tracker.save_data() - self.notify(f"Deleted {removed.Make}", title="Removed") - else: - removed = self.ink_tracker.inks.pop(idx) - self.ink_tracker.save_data() - self.notify(f"Deleted {removed.Name}", title="Removed") - self._refresh_table() - except Exception: - self.notify("No item selected to delete", title="Error", severity="error") - - def action_toggle_mode(self) -> None: - self.mode = "inks" if self.mode == "pens" else "pens" - self._refresh_table() - mode_name = "Pens" if self.mode == "pens" else "Inks" - self.notify(f"Switched to {mode_name} mode", title="Mode Changed") - - def on_data_table_cell_selected(self, event: DataTable.CellSelected) -> None: - try: - idx = int(event.cell_key.row_key.value) - self.action_edit_selected(str(idx)) - except (AttributeError, ValueError): - self.notify("Error selecting row", title="Error", severity="error") - -def main(): - # This is the entry point defined in pyproject.toml - app = PenTrackerApp() - app.run()