task | add ink support

This commit is contained in:
Don Harper 2026-05-02 22:25:35 -05:00
parent 9f9fd41851
commit bf3b1fc456
13 changed files with 595 additions and 37 deletions

View file

@ -3,7 +3,7 @@ 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
from .engine import PenTracker, Pen, InkTracker, Ink
# --- TUI SCREENS ---
class PenFormScreen(Screen):
@ -54,6 +54,50 @@ class PenFormScreen(Screen):
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."""
@ -89,7 +133,8 @@ class PenTrackerApp(App):
BINDINGS = [
Binding("d", "delete_selected", "Delete Selected"),
Binding("a", "add_new", "Add New Pen"),
Binding("a", "add_new", "Add New"),
Binding("i", "toggle_mode", "Toggle Pens/Inks"),
Binding("q", "quit", "Quit"),
]
@ -100,29 +145,46 @@ class PenTrackerApp(App):
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)
display_cols = ['Make', 'Model', 'Nib', 'Nib-Material', 'Body','Cap', 'Current-Ink', 'Inked-date', 'Notes']
table.add_columns(*display_cols)
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, pen in enumerate(self.tracker.pens):
row_values = [getattr(pen, c.replace('-','_')) for c in display_cols]
# We use the index as the row key to track items accurately
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:
form = PenFormScreen(self.tracker)
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)
existing_pen = self.tracker.pens[idx]
form = PenFormScreen(self.tracker, existing_pen=existing_pen)
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
@ -135,16 +197,26 @@ class PenTrackerApp(App):
def action_delete_selected(self) -> None:
table = self.query_one("#pen_table", DataTable)
try:
# Accessing via the table's current cursor
table = self.query_one("#pen_table", DataTable)
row_node = table.get_row_at_cursor()
idx = int(row_node.key.value)
removed = self.tracker.pens.pop(idx)
self.tracker.save_data()
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()
self.notify(f"Deleted {removed.Make}", title="Removed")
except Exception:
self.notify("No pen selected to delete", title="Error", severity="error")
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: