2025-12-04 13:21:49 +01:00
|
|
|
"""
|
|
|
|
|
This is where the application is implemented.
|
|
|
|
|
"""
|
|
|
|
|
|
2025-12-04 19:25:18 +01:00
|
|
|
from typing import Literal, final, override
|
2025-12-04 13:21:49 +01:00
|
|
|
|
|
|
|
|
from textual.app import App, ComposeResult
|
2025-12-04 19:25:18 +01:00
|
|
|
from textual.containers import HorizontalGroup
|
2025-12-04 13:21:49 +01:00
|
|
|
from textual.screen import Screen
|
|
|
|
|
from textual.widget import Widget
|
|
|
|
|
from textual.widgets import (
|
|
|
|
|
Button,
|
2025-12-04 19:25:18 +01:00
|
|
|
DataTable,
|
2025-12-04 13:21:49 +01:00
|
|
|
Footer,
|
|
|
|
|
Header,
|
|
|
|
|
Input,
|
2025-12-04 19:28:14 +01:00
|
|
|
Static,
|
2025-12-04 13:21:49 +01:00
|
|
|
)
|
2025-12-08 17:38:39 +01:00
|
|
|
from tortoise import Tortoise
|
2025-12-04 13:21:49 +01:00
|
|
|
|
2025-12-09 21:22:49 +01:00
|
|
|
from teilchensammler_cli import settings
|
|
|
|
|
|
2025-12-04 13:21:49 +01:00
|
|
|
|
|
|
|
|
@final
|
2025-12-04 19:28:14 +01:00
|
|
|
class SearchBar(Static):
|
2025-12-04 13:21:49 +01:00
|
|
|
DEFAULT_CSS = """
|
|
|
|
|
#teilchen-input {
|
|
|
|
|
width: 4fr;
|
|
|
|
|
}
|
|
|
|
|
#button-search, #button-add {
|
|
|
|
|
width: 1fr;
|
|
|
|
|
}
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
def compose(self) -> ComposeResult:
|
2025-12-04 19:28:14 +01:00
|
|
|
with HorizontalGroup(id="search-bar-widget"):
|
2025-12-04 13:21:49 +01:00
|
|
|
yield Input(
|
|
|
|
|
placeholder="Enter Teilchen information: name, description, #tags",
|
|
|
|
|
tooltip=(
|
|
|
|
|
"This is a free-form field: Enter a name and "
|
|
|
|
|
"description any way you like. You should use #hashtags for any "
|
|
|
|
|
"meta information."
|
|
|
|
|
),
|
|
|
|
|
id="teilchen-input",
|
|
|
|
|
type="text",
|
|
|
|
|
)
|
2025-12-09 21:22:49 +01:00
|
|
|
yield Button("Add", variant="success", classes="search-bar-buttons", id="button-add")
|
2025-12-04 19:28:14 +01:00
|
|
|
yield Button(
|
|
|
|
|
"Search",
|
|
|
|
|
variant="default",
|
|
|
|
|
classes="search-bar-buttons",
|
|
|
|
|
id="button-search",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
2025-12-04 19:25:18 +01:00
|
|
|
TeilchenDatum = tuple[int, str, str, str, str]
|
|
|
|
|
TeilchenHeader = tuple[
|
|
|
|
|
Literal["pk"],
|
|
|
|
|
Literal["Name"],
|
|
|
|
|
Literal["Description"],
|
|
|
|
|
Literal["Number"],
|
|
|
|
|
Literal["Tags"],
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FAKE_DATA: list[TeilchenHeader | TeilchenDatum] = [
|
|
|
|
|
("pk", "Name", "Description", "Number", "Tags"),
|
|
|
|
|
(0, "Name0", "Description0", "9000", "#tag0 #tag00 #tag000"),
|
|
|
|
|
(1, "Name1", "Description1", "9001", "#tag1 #tag11 #tag111"),
|
|
|
|
|
(2, "Name2", "Description2", "9002", "#tag2 #tag22 #tag222"),
|
|
|
|
|
(3, "Name3", "Description3", "9003", "#tag3 #tag33 #tag333"),
|
|
|
|
|
(4, "Name4", "Description4", "9004", "#tag4 #tag44 #tag444"),
|
|
|
|
|
(5, "Name5", "Description5", "9005", "#tag5 #tag55 #tag555"),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@final
|
|
|
|
|
class SearchResults(Widget):
|
|
|
|
|
@override
|
|
|
|
|
def compose(self) -> ComposeResult:
|
|
|
|
|
yield DataTable(id="table-search-result", cursor_type="row", zebra_stripes=True)
|
|
|
|
|
|
2025-12-04 23:11:41 +01:00
|
|
|
async def on_mount(self) -> None:
|
2025-12-04 19:25:18 +01:00
|
|
|
table: DataTable[None] = self.query_one(DataTable[None])
|
|
|
|
|
_ = table.add_columns(*FAKE_DATA[0]) # pyright: ignore[reportArgumentType]
|
|
|
|
|
_ = table.add_rows(FAKE_DATA[1:]) # pyright: ignore[reportArgumentType]
|
2025-12-04 13:21:49 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class AddInventoryScreen(Screen[None]):
|
|
|
|
|
@override
|
|
|
|
|
def compose(self) -> ComposeResult:
|
|
|
|
|
yield Header()
|
|
|
|
|
yield SearchBar()
|
2025-12-04 19:25:18 +01:00
|
|
|
yield SearchResults()
|
2025-12-04 13:21:49 +01:00
|
|
|
yield Footer()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@final
|
|
|
|
|
class SammlerApp(App[None]):
|
2025-12-04 23:11:41 +01:00
|
|
|
async def on_mount(self) -> None:
|
2025-12-09 21:22:49 +01:00
|
|
|
await Tortoise.init(config=settings.TORTOISE_ORM_CONFIG)
|
|
|
|
|
await Tortoise.generate_schemas(safe=True)
|
2025-12-04 13:21:49 +01:00
|
|
|
_ = self.push_screen(AddInventoryScreen())
|
|
|
|
|
|
2025-12-09 21:22:49 +01:00
|
|
|
async def on_unmount(self) -> None:
|
|
|
|
|
# https://tortoise.github.io/setup.html#the-importance-of-cleaning-up
|
|
|
|
|
await Tortoise.close_connections()
|
|
|
|
|
|
2025-12-04 13:21:49 +01:00
|
|
|
|
|
|
|
|
def main() -> None:
|
|
|
|
|
app = SammlerApp()
|
|
|
|
|
app.run()
|