Added the diary select screen

This commit is contained in:
Gustavo Henrique Santos Souza de Miranda 2025-06-08 22:50:26 -03:00
parent 03fb3b23c2
commit 58c7bfd8e9
8 changed files with 197 additions and 8 deletions

View File

@ -18,7 +18,9 @@ classifiers = [
"Operating System :: OS Independent",
]
dependencies = [
"sqlalchemy"
"sqlalchemy",
"textual",
"textual-dev"
]
[template.plugins.default]
src-layout = true

View File

@ -2,3 +2,5 @@ greenlet==3.2.2
SQLAlchemy==2.0.41
typing_extensions==4.14.0
textual~=3.3.0

View File

@ -6,9 +6,10 @@ class TravelDiaryServiceMock(TravelDiaryService):
def __init__(self):
super().__init__(None)
self.mock_data = {
1:TravelDiary(id=1,name="Montreal")
1:TravelDiary(id=1,name="Montreal"),
2:TravelDiary(id=2,name="Rio de Janeiro"),
}
self._next_id = 2
self._next_id = 3
def create(self, name: str):
new_travel_diary = TravelDiary(id=self._next_id,name=name)

View File

@ -18,18 +18,18 @@ class TravelDiaryService:
def read_all(self):
return self.session.query(TravelDiary).all()
def update(self, travel_diary_src:TravelDiary,travel_diary_dst:TravelDiary):
original = self.read_by_id(travel_diary_src.id)
def update(self, travel_diary_id: TravelDiary, travel_diary_dst: TravelDiary):
original = self.read_by_id(travel_diary_id.id)
if original is not None:
original.name = travel_diary_dst.name
self.session.commit()
self.session.refresh(original)
return original
def delete(self, travel_diary_src:TravelDiary):
excluded = self.read_by_id(travel_diary_src.id)
def delete(self, travel_diary_id: TravelDiary):
excluded = self.read_by_id(travel_diary_id.id)
if excluded is not None:
self.session.delete(travel_diary_src)
self.session.delete(travel_diary_id)
self.session.commit()
return excluded
return None

View File

View File

@ -0,0 +1,147 @@
from click import prompt
from textual.app import ComposeResult
from textual.screen import Screen
from textual.widgets import Header, Footer, Label, Static, OptionList, Button
from textual.binding import Binding
from textual.containers import Vertical, Container, Horizontal
class DiaryListScreen(Screen):
TITLE = "Pilgrim - Main"
BINDINGS = [
Binding("n", "new_diary", "Novo Diário"),
Binding("^q", "quit", "Sair"),
]
def __init__(self):
super().__init__()
self.selected_diary_index = None # Armazena o índice do diário selecionado
def compose(self) -> ComposeResult:
yield Header()
yield Container(
Static("Pilgrim", classes="app-title"),
Label("Select a diary"),
OptionList(id="option-list", classes="diary-options"),
Horizontal(
Button("New diary", id="new-diary"),
Button("Edit diary", id="edit-diary"),
Button("🔄 Refresh", id="refresh-btn"),
classes="actions-buttons",
),
classes="dialog-container"
)
yield Static(
"Tip: use ↑↓ to navigate • ENTER to Select • "
"TAB to alternate the fields • SHIFT + TAB to alternate back ",
classes="tips"
)
yield Footer()
def on_mount(self) -> None:
self.refresh_diaries()
self.update_buttons_state() # Atualiza estado inicial dos botões
def refresh_diaries(self):
try:
service_manager = self.app.service_manager
option_list = self.query_one(".diary-options")
option_list.clear_options()
travel_diary_service = service_manager.get_travel_diary_service()
diaries = travel_diary_service.read_all()
if not diaries:
# Para OptionList vazio, você pode adicionar uma string simples
option_list.add_option("[dim]Nenhum diário encontrado. Pressione 'N' para criar um novo![/dim]")
else:
for diary in diaries:
# Adiciona cada opção como string com markup rich
option_list.add_option(f"[b]{diary.name}[/b]\n[dim]ID: {diary.id}[/dim]")
except Exception as e:
self.notify("Error: " + str(e))
def on_option_list_option_selected(self, event: OptionList.OptionSelected) -> None:
"""Handle quando uma opção é selecionada"""
diaries = self.app.service_manager.get_travel_diary_service().read_all()
if diaries and event.option_index < len(diaries):
self.selected_diary_index = event.option_index
selected_diary = diaries[event.option_index]
self.notify(f"Diário selecionado: {selected_diary.name}")
else:
# Caso seja a opção "nenhum diário encontrado"
self.selected_diary_index = None
self.update_buttons_state()
def update_buttons_state(self):
"""Atualiza o estado dos botões baseado na seleção"""
edit_button = self.query_one("#edit-diary")
# Só habilita os botões se há um diário selecionado
has_selection = self.selected_diary_index is not None
edit_button.disabled = not has_selection
def on_button_pressed(self, event: Button.Pressed) -> None:
"""Handle cliques nos botões"""
button_id = event.button.id
if button_id == "new-diary":
self.action_new_diary()
elif button_id == "edit-diary":
self.action_edit_diary()
elif button_id == "refresh-btn":
self.refresh_diaries()
self.notify("Lista atualizada manualmente!")
def action_new_diary(self):
"""Ação para criar novo diário"""
self.notify("Criando novo diário...")
# Aqui você pode navegar para uma tela de criação de diário
def action_edit_diary(self):
"""Ação para editar diário selecionado"""
if self.selected_diary_index is not None:
diaries = self.app.service_manager.get_travel_diary_service().read_all()
if self.selected_diary_index < len(diaries):
selected_diary = diaries[self.selected_diary_index]
self.notify(f"Editando diário: {selected_diary.name}")
# Aqui você pode navegar para uma tela de edição
# self.app.push_screen(EditDiaryScreen(diary=selected_diary))
def refresh_diaries(self):
"""Atualiza a lista de diários no OptionList"""
try:
service_manager = self.app.service_manager
option_list = self.query_one("#option-list") # Usando ID em vez de classe
# Debug
current_count = len(option_list.options) if hasattr(option_list, 'options') else 0
self.notify(f"OptionList atual tem {current_count} opções")
option_list.clear_options()
travel_diary_service = service_manager.get_travel_diary_service()
diaries = travel_diary_service.read_all()
self.notify(f"Carregando {len(diaries)} diários do serviço")
if not diaries:
option_list.add_option("[dim]Nenhum diário encontrado. Pressione 'N' para criar um novo![/dim]")
self.selected_diary_index = None
else:
for diary in diaries:
option_list.add_option(f"[b]{diary.name}[/b]\n[dim]ID: {diary.id}[/dim]")
# Valida se a seleção ainda é válida
if (self.selected_diary_index is not None and
self.selected_diary_index >= len(diaries)):
self.selected_diary_index = None
except Exception as e:
self.notify("Error no refresh_diaries: " + str(e))

View File

@ -0,0 +1,25 @@
.dialog-container{
content-align: center top;
}
.app-title{
dock: top;
height: 3;
content-align: center middle;
text-style: bold;
color: $accent;
}
.actions-buttons{
height: auto;
margin: 1 0;
align: center middle;
}
.tips{
dock: bottom;
height: 4;
content-align: center middle;
color: $text-muted;
}

View File

@ -1,9 +1,21 @@
from pathlib import Path
from textual.app import App
from pilgrim.service.servicemanager import ServiceManager
from pilgrim.ui.screens.diary_list_screen import DiaryListScreen
CSS_FILE_PATH = Path(__file__).parent / "styles" / "pilgrim.css"
class UIApp(App):
CSS_PATH = CSS_FILE_PATH
def __init__(self,service_manager: ServiceManager):
super().__init__()
self.service_manager = service_manager
def on_mount(self) -> None:
"""Chamado quando a app inicia. Carrega a tela principal."""
self.push_screen(DiaryListScreen())