teilchensammler-cli/src/teilchensammler_cli/main.py

105 lines
2.8 KiB
Python
Raw Normal View History

"""
This is where the application is implemented.
"""
import logging
2025-12-04 19:25:18 +01:00
from textual import on
from textual.app import App, ComposeResult
from textual.containers import HorizontalGroup
2025-12-28 21:56:57 +01:00
from textual.logging import TextualHandler
from textual.screen import Screen
from textual.widget import Widget
from textual.widgets import Button, DataTable, Footer, Header, Input, Static
from .database import create_db_and_tables
from .models import add_to_database, load_initial_data, make_teilchen_input
2025-12-28 21:56:57 +01:00
logging.basicConfig(
level="NOTSET",
handlers=[TextualHandler()],
)
logger = logging.getLogger(__name__)
TEILCHEN_DATA_HEADER = "pk Name Description Number Tags".split()
2026-02-18 20:40:58 +01:00
class SammlerApp(App):
async def on_mount(self) -> None:
create_db_and_tables()
self.push_screen(AddInventoryScreen())
class SearchBar(Static):
DEFAULT_CSS = """
#teilchen-input {
width: 4fr;
}
#button-search, #button-add {
width: 1fr;
}
"""
def compose(self) -> ComposeResult:
with HorizontalGroup(id="search-bar-widget"):
yield Input(
placeholder='This is a name. "This is the description" #these #are #tags',
tooltip=(
"Enter a name followed by a period, then a description "
'enclosed in double quotes ("). You should use #hashtags for any meta information. '
"Hashtags can be placed anywhere."
),
id="teilchen-input",
type="text",
)
yield Button("Add", variant="success", classes="search-bar-buttons", id="button-add")
yield Button(
"Search",
variant="default",
classes="search-bar-buttons",
id="button-search",
)
@on(Input.Submitted)
async def parse_input(self, event: Input.Submitted) -> None:
if not (tc := await make_teilchen_input(event.value)):
return
event.input.value = ""
teilchen = await add_to_database(tc)
self.screen.query_one(DataTable).add_row(
teilchen.id, teilchen.name, teilchen.description, teilchen.number, teilchen.tags
)
class SearchResults(Widget):
def compose(self) -> ComposeResult:
yield DataTable(id="table-search-result", cursor_type="row", zebra_stripes=True)
async def on_mount(self) -> None:
table: DataTable = self.query_one(DataTable)
table.add_columns(*TEILCHEN_DATA_HEADER)
table.add_rows(await load_initial_data())
class AddInventoryScreen(Screen):
def compose(self) -> ComposeResult:
yield Header()
yield SearchBar()
yield SearchResults()
yield Footer()
# so we can import it without running it
app = SammlerApp()
def main() -> None:
app.run()
if __name__ == "__main__":
main()