hamster-tools/hamstertools/app.py

209 lines
6.4 KiB
Python
Raw Normal View History

2023-10-27 00:13:08 +00:00
from textual.app import App, ComposeResult
2023-10-27 03:04:30 +00:00
from textual.binding import Binding
from textual.widgets import Header, Footer, DataTable, Input
from textual.containers import Horizontal, Vertical
from textual.coordinate import Coordinate
2023-10-27 01:26:15 +00:00
from textual.screen import Screen
2023-10-27 00:13:08 +00:00
2023-10-27 03:04:30 +00:00
from .db import DatabaseManager, Category, Activity
2023-10-27 00:13:08 +00:00
2023-10-27 15:40:25 +00:00
2023-10-27 15:39:58 +00:00
class ListScreen(Screen):
2023-10-27 03:04:30 +00:00
def __init__(self, db_manager):
self.db_manager = db_manager
2023-10-27 00:13:08 +00:00
super().__init__()
def compose(self) -> ComposeResult:
2023-10-27 01:26:15 +00:00
"""create child widgets for the app."""
yield Header()
2023-10-27 03:04:30 +00:00
with Vertical():
yield DataTable()
with Horizontal():
yield Input(id="filter")
yield Footer()
2023-10-27 00:13:08 +00:00
def action_refresh(self) -> None:
self._refresh()
def action_sort(self) -> None:
self.table.cursor_type = "column"
2023-10-27 15:28:46 +00:00
def on_data_table_column_selected(self, event):
self.sort = (event.column_key,)
event.data_table.sort(*self.sort)
event.data_table.cursor_type = "row"
2023-10-27 03:04:30 +00:00
def action_filter(self) -> None:
filter_input = self.query_one("#filter")
filter_input.display = True
2023-10-27 15:28:46 +00:00
self._refresh(filter_input.value)
2023-10-27 03:04:30 +00:00
filter_input.focus()
2023-10-27 15:28:46 +00:00
def on_input_submitted(self, event):
self.table.focus()
2023-10-27 03:04:30 +00:00
def action_cancelfilter(self) -> None:
filter_input = self.query_one("#filter")
filter_input.display = False
2023-10-27 15:28:46 +00:00
filter_input.clear()
self.table.focus()
2023-10-27 03:04:30 +00:00
self._refresh()
2023-10-27 15:39:58 +00:00
def on_input_changed(self, event):
self._refresh(event.value)
class ActivitiesScreen(ListScreen):
BINDINGS = [
("q", "quit", "Quit"),
("s", "sort", "Sort"),
("r", "refresh", "Refresh"),
("/", "filter", "Search"),
("d", "delete", "Delete activity"),
("f", "move_facts", "Move facts"),
Binding(key="escape", action="cancelfilter", show=False),
]
def _refresh(self, filter_query=None):
self.table.clear()
# List activities with the count of facts
2023-10-27 20:01:45 +00:00
activities = Activity.list(self.db_manager, filter_query)
2023-10-27 15:39:58 +00:00
2023-10-27 15:40:25 +00:00
self.table.add_rows(
[
[
activity.category_id,
activity.category_name,
activity.id,
activity.name,
activity.facts_count,
]
for activity in activities
]
)
2023-10-27 15:39:58 +00:00
self.table.sort(*self.sort)
def on_mount(self) -> None:
self.table = self.query_one(DataTable)
self.table.cursor_type = "row"
2023-10-27 15:40:25 +00:00
self.columns = self.table.add_columns(
"category id", "category", "activity id", "activity", "entries"
)
2023-10-27 15:39:58 +00:00
self.sort = (self.columns[1], self.columns[3])
self._refresh()
2023-10-27 01:26:15 +00:00
def action_delete(self) -> None:
2023-10-27 15:28:46 +00:00
# get the keys for the row and column under the cursor.
row_key, _ = self.table.coordinate_to_cell_key(self.table.cursor_coordinate)
activity_id = self.table.get_cell_at(
Coordinate(self.table.cursor_coordinate.row, 2),
)
2023-10-27 03:04:30 +00:00
activity = Activity.get_by_id(self.db_manager, activity_id)
activity.delete()
2023-10-27 01:26:15 +00:00
# supply the row key to `remove_row` to delete the row.
self.table.remove_row(row_key)
2023-10-27 15:28:46 +00:00
def action_move_facts(self) -> None:
row_idx: int = self.table.cursor_row
row_cells = self.table.get_row_at(row_idx)
self.move_from_activity = Activity.get_by_id(self.db_manager, row_cells[2])
for col_idx, cell_value in enumerate(row_cells):
cell_coordinate = Coordinate(row_idx, col_idx)
self.table.update_cell_at(
cell_coordinate,
f"[red]{cell_value}[/red]",
)
2023-10-27 15:40:25 +00:00
self.table.move_cursor(row=self.table.cursor_coordinate[0] + 1)
2023-10-27 15:28:46 +00:00
def on_data_table_row_selected(self, event):
if getattr(self, "move_from_activity", None) is not None:
2023-10-27 15:40:25 +00:00
move_to_activity = Activity.get_by_id(
self.db_manager, self.table.get_cell_at(Coordinate(event.cursor_row, 2))
)
2023-10-27 15:28:46 +00:00
self.move_from_activity.move_facts(move_to_activity)
2023-10-27 15:48:03 +00:00
filter_input = self.query_one("#filter")
self._refresh(filter_input.value)
2023-10-27 15:28:46 +00:00
del self.move_from_activity
2023-10-27 01:26:15 +00:00
2023-10-27 15:40:25 +00:00
2023-10-27 15:39:58 +00:00
class CategoriesScreen(ListScreen):
2023-10-27 01:26:15 +00:00
BINDINGS = [
2023-10-27 15:39:58 +00:00
("q", "quit", "Quit"),
2023-10-27 01:26:15 +00:00
("s", "sort", "Sort"),
("r", "refresh", "Refresh"),
2023-10-27 03:04:30 +00:00
("/", "filter", "Search"),
2023-10-27 15:39:58 +00:00
("d", "delete", "Delete category"),
2023-10-27 03:04:30 +00:00
Binding(key="escape", action="cancelfilter", show=False),
2023-10-27 01:26:15 +00:00
]
2023-10-27 03:04:30 +00:00
def _refresh(self, filter_query=None):
2023-10-27 01:26:15 +00:00
self.table.clear()
2023-10-27 20:01:45 +00:00
categories = Category.list(
2023-10-27 15:40:25 +00:00
self.db_manager, filter_query=filter_query
)
2023-10-27 03:04:30 +00:00
2023-10-27 15:40:25 +00:00
self.table.add_rows(
[
[
category.id,
category.name,
category.activity_count,
]
for category in categories
]
)
2023-10-27 03:04:30 +00:00
self.table.sort(self.sort)
2023-10-27 01:26:15 +00:00
def on_mount(self) -> None:
self.table = self.query_one(DataTable)
self.table.cursor_type = "row"
2023-10-27 15:40:25 +00:00
self.columns = self.table.add_columns("category id", "category", "activities")
2023-10-27 03:04:30 +00:00
self.sort = self.columns[1]
2023-10-27 01:26:15 +00:00
self._refresh()
def action_delete(self) -> None:
# get the keys for the row and column under the cursor.
row_key, _ = self.table.coordinate_to_cell_key(self.table.cursor_coordinate)
category_id = self.table.get_cell_at(
Coordinate(self.table.cursor_coordinate.row, 0),
)
2023-10-27 03:04:30 +00:00
category = Category.get_by_id(self.db_manager, category_id)
category.delete()
2023-10-27 01:26:15 +00:00
# supply the row key to `remove_row` to delete the row.
self.table.remove_row(row_key)
2023-10-27 15:40:25 +00:00
2023-10-27 01:26:15 +00:00
class HamsterToolsApp(App):
2023-10-27 15:40:25 +00:00
CSS_PATH = "app.tcss"
2023-10-27 01:26:15 +00:00
BINDINGS = [
("a", "switch_mode('activities')", "Activities"),
("c", "switch_mode('categories')", "Categories"),
("q", "quit", "Quit"),
]
2023-10-27 03:04:30 +00:00
def __init__(self):
2023-10-27 15:40:25 +00:00
self.db_manager = DatabaseManager("hamster-testing.db")
2023-10-27 01:26:15 +00:00
self.MODES = {
2023-10-27 03:04:30 +00:00
"categories": CategoriesScreen(self.db_manager),
"activities": ActivitiesScreen(self.db_manager)
2023-10-27 01:26:15 +00:00
}
super().__init__()
def on_mount(self) -> None:
self.switch_mode("activities")
def action_quit(self) -> None:
self.exit()
2023-10-27 03:04:30 +00:00
self.db_manager.close()