From a999a0a43717ff90eb9c8bf1b2ddde147242dc5c Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Wed, 25 Jun 2025 00:27:49 -0300 Subject: [PATCH 1/3] Changed the modal size and also modified the edit_entry_screen.py to conform with the wireframe, also changed all the texts to be english --- .../service/mocks/entry_service_mock.py | 48 +++++------ .../mocks/travel_diary_service_mock.py | 34 ++++---- src/pilgrim/ui/screens/about_screen.py | 10 +-- src/pilgrim/ui/screens/diary_list_screen.py | 84 +++++++++---------- src/pilgrim/ui/screens/edit_diary_modal.py | 21 +++-- src/pilgrim/ui/screens/edit_entry_screen.py | 39 ++++++--- src/pilgrim/ui/screens/new_diary_modal.py | 6 +- src/pilgrim/ui/ui.py | 2 +- 8 files changed, 128 insertions(+), 116 deletions(-) diff --git a/src/pilgrim/service/mocks/entry_service_mock.py b/src/pilgrim/service/mocks/entry_service_mock.py index 5b93f51..b78f59e 100644 --- a/src/pilgrim/service/mocks/entry_service_mock.py +++ b/src/pilgrim/service/mocks/entry_service_mock.py @@ -33,30 +33,30 @@ class EntryServiceMock(EntryService): } self._next_id = 11 - # Métodos síncronos (mantidos para compatibilidade) + # Synchronous methods (kept for compatibility) def create(self, travel_diary_id: int, title: str, text: str, date: str) -> Entry: - """Versão síncrona""" + """Synchronous version""" new_entry = Entry(title, text, date, travel_diary_id, id=self._next_id) self.mock_data[self._next_id] = new_entry self._next_id += 1 return new_entry def read_by_id(self, entry_id: int) -> Entry | None: - """Versão síncrona""" + """Synchronous version""" return self.mock_data.get(entry_id) def read_all(self) -> List[Entry]: - """Versão síncrona""" + """Synchronous version""" return list(self.mock_data.values()) def read_by_travel_diary_id(self, travel_diary_id: int) -> List[Entry]: - """Versão síncrona - lê entradas por diário""" + """Synchronous version - reads entries by diary""" return [entry for entry in self.mock_data.values() if entry.fk_travel_diary_id == travel_diary_id] def read_paginated(self, travel_diary_id: int, page: int = 1, page_size: int = 5) -> Tuple[List[Entry], int, int]: - """Versão síncrona - lê entradas paginadas por diário""" + """Synchronous version - reads paginated entries by diary""" entries = self.read_by_travel_diary_id(travel_diary_id) - entries.sort(key=lambda x: x.id, reverse=True) # Mais recentes primeiro + entries.sort(key=lambda x: x.id, reverse=True) # Most recent first total_entries = len(entries) total_pages = (total_entries + page_size - 1) // page_size @@ -69,7 +69,7 @@ class EntryServiceMock(EntryService): return page_entries, total_pages, total_entries def update(self, entry_src: Entry, entry_dst: Entry) -> Entry | None: - """Versão síncrona""" + """Synchronous version""" item_to_update = self.mock_data.get(entry_src.id) if item_to_update: item_to_update.title = entry_dst.title if entry_dst.title is not None else item_to_update.title @@ -83,41 +83,41 @@ class EntryServiceMock(EntryService): return None def delete(self, entry_src: Entry) -> Entry | None: - """Versão síncrona""" + """Synchronous version""" return self.mock_data.pop(entry_src.id, None) - # Métodos assíncronos (principais) + # Async methods (main) async def async_create(self, travel_diary_id: int, title: str, text: str, date: str) -> Entry: - """Versão assíncrona""" - await asyncio.sleep(0.01) # Simula I/O + """Async version""" + await asyncio.sleep(0.01) # Simulates I/O return self.create(travel_diary_id, title, text, date) async def async_read_by_id(self, entry_id: int) -> Entry | None: - """Versão assíncrona""" - await asyncio.sleep(0.01) # Simula I/O + """Async version""" + await asyncio.sleep(0.01) # Simulates I/O return self.read_by_id(entry_id) async def async_read_all(self) -> List[Entry]: - """Versão assíncrona""" - await asyncio.sleep(0.01) # Simula I/O + """Async version""" + await asyncio.sleep(0.01) # Simulates I/O return self.read_all() async def async_read_by_travel_diary_id(self, travel_diary_id: int) -> List[Entry]: - """Versão assíncrona - lê entradas por diário""" - await asyncio.sleep(0.01) # Simula I/O + """Async version - reads entries by diary""" + await asyncio.sleep(0.01) # Simulates I/O return self.read_by_travel_diary_id(travel_diary_id) async def async_read_paginated(self, travel_diary_id: int, page: int = 1, page_size: int = 5) -> Tuple[List[Entry], int, int]: - """Versão assíncrona - lê entradas paginadas por diário""" - await asyncio.sleep(0.01) # Simula I/O + """Async version - reads paginated entries by diary""" + await asyncio.sleep(0.01) # Simulates I/O return self.read_paginated(travel_diary_id, page, page_size) async def async_update(self, entry_src: Entry, entry_dst: Entry) -> Entry | None: - """Versão assíncrona""" - await asyncio.sleep(0.01) # Simula I/O + """Async version""" + await asyncio.sleep(0.01) # Simulates I/O return self.update(entry_src, entry_dst) async def async_delete(self, entry_src: Entry) -> Entry | None: - """Versão assíncrona""" - await asyncio.sleep(0.01) # Simula I/O + """Async version""" + await asyncio.sleep(0.01) # Simulates I/O return self.delete(entry_src) \ No newline at end of file diff --git a/src/pilgrim/service/mocks/travel_diary_service_mock.py b/src/pilgrim/service/mocks/travel_diary_service_mock.py index 5db4475..c5b4c6e 100644 --- a/src/pilgrim/service/mocks/travel_diary_service_mock.py +++ b/src/pilgrim/service/mocks/travel_diary_service_mock.py @@ -12,24 +12,24 @@ class TravelDiaryServiceMock(TravelDiaryService): } self._next_id = 3 - # Métodos síncronos (originais) + # Synchronous methods (original) def create(self, name: str): - """Versão síncrona""" + """Synchronous version""" new_travel_diary = TravelDiary(id=self._next_id, name=name) self.mock_data[self._next_id] = new_travel_diary self._next_id += 1 return new_travel_diary def read_by_id(self, travel_id: int): - """Versão síncrona""" + """Synchronous version""" return self.mock_data.get(travel_id) def read_all(self): - """Versão síncrona""" + """Synchronous version""" return list(self.mock_data.values()) def update(self, travel_diary_id: int, name: str): - """Versão síncrona""" + """Synchronous version""" item_to_update = self.mock_data.get(travel_diary_id) if item_to_update: item_to_update.name = name @@ -37,31 +37,31 @@ class TravelDiaryServiceMock(TravelDiaryService): return None def delete(self, travel_diary_id: int): - """Versão síncrona""" + """Synchronous version""" return self.mock_data.pop(travel_diary_id, None) - # Métodos assíncronos (novos) + # Async methods (new) async def async_create(self, name: str): - """Versão assíncrona""" - await asyncio.sleep(0.01) # Simula I/O + """Async version""" + await asyncio.sleep(0.01) # Simulates I/O return self.create(name) async def async_read_by_id(self, travel_id: int): - """Versão assíncrona""" - await asyncio.sleep(0.01) # Simula I/O + """Async version""" + await asyncio.sleep(0.01) # Simulates I/O return self.read_by_id(travel_id) async def async_read_all(self): - """Versão assíncrona""" - await asyncio.sleep(0.01) # Simula I/O + """Async version""" + await asyncio.sleep(0.01) # Simulates I/O return self.read_all() async def async_update(self, travel_diary_id: int, name: str): - """Versão assíncrona""" - await asyncio.sleep(0.01) # Simula I/O + """Async version""" + await asyncio.sleep(0.01) # Simulates I/O return self.update(travel_diary_id, name) async def async_delete(self, travel_diary_id: int): - """Versão assíncrona""" - await asyncio.sleep(0.01) # Simula I/O + """Async version""" + await asyncio.sleep(0.01) # Simulates I/O return self.delete(travel_diary_id) \ No newline at end of file diff --git a/src/pilgrim/ui/screens/about_screen.py b/src/pilgrim/ui/screens/about_screen.py index ebf7d48..bedb479 100644 --- a/src/pilgrim/ui/screens/about_screen.py +++ b/src/pilgrim/ui/screens/about_screen.py @@ -5,7 +5,7 @@ from textual.widgets import Header, Footer, Button, Label, TextArea from textual.containers import Container class AboutScreen(Screen[bool]): - """Tela para exibir informações sobre a aplicação.""" + """Screen to display application information.""" TITLE = "Pilgrim - About" @@ -51,20 +51,20 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND yield self.footer def on_button_pressed(self, event: Button.Pressed) -> None: - """Lida com os cliques dos botões.""" + """Handles button clicks.""" if "about-close-button" in event.button.classes: self.dismiss(False) elif "about-info-button" in event.button.classes: - self.notify("Mais informações seriam exibidas aqui!", title="Info") + self.notify("More information would be displayed here!", title="Info") def action_dismiss(self, **kwargs) -> None: - """Fecha o about box usando dismiss. + """Closes the about box using dismiss. :param **kwargs: """ self.dismiss(False) def on_key(self, event) -> None: - """Intercepta teclas específicas.""" + """Intercepts specific keys.""" if event.key == "escape": self.dismiss(False) event.prevent_default() diff --git a/src/pilgrim/ui/screens/diary_list_screen.py b/src/pilgrim/ui/screens/diary_list_screen.py index 0240ba5..0b0c042 100644 --- a/src/pilgrim/ui/screens/diary_list_screen.py +++ b/src/pilgrim/ui/screens/diary_list_screen.py @@ -58,31 +58,31 @@ class DiaryListScreen(Screen): yield self.footer def on_mount(self) -> None: - # Usa versão síncrona para o mount inicial + # Uses synchronous version for initial mount self.refresh_diaries() self.update_buttons_state() def refresh_diaries(self): - """Versão síncrona do refresh""" + """Synchronous version of refresh""" try: service_manager = self.app.service_manager travel_diary_service = service_manager.get_travel_diary_service() - # Usa método síncrono + # Uses synchronous method diaries = travel_diary_service.read_all() - # Salva o estado atual + # Saves current state current_diary_id = None if (self.selected_diary_index is not None and self.selected_diary_index in self.diary_id_map): current_diary_id = self.diary_id_map[self.selected_diary_index] - # Limpa e reconstrói + # Clears and rebuilds self.diary_list.clear_options() self.diary_id_map = {} if not diaries: - self.diary_list.add_option("[dim]Nenhum diário encontrado. Pressione 'N' para criar um novo![/dim]") + self.diary_list.add_option("[dim]No diaries found. Press 'N' to create a new one![/dim]") self.selected_diary_index = None else: new_selected_index = 0 @@ -91,33 +91,33 @@ class DiaryListScreen(Screen): self.diary_id_map[index] = diary.id self.diary_list.add_option(f"[b]{diary.name}[/b]\n[dim]ID: {diary.id}[/dim]") - # Mantém a seleção se possível + # Maintains selection if possible if current_diary_id and diary.id == current_diary_id: new_selected_index = index self.selected_diary_index = new_selected_index - # Atualiza o highlight + # Updates highlight self.set_timer(0.05, lambda: self._update_highlight(new_selected_index)) - # Força refresh visual + # Forces visual refresh self.diary_list.refresh() self.update_buttons_state() except Exception as e: - self.notify(f"Erro ao carregar diários: {str(e)}") + self.notify(f"Error loading diaries: {str(e)}") def _update_highlight(self, index: int): - """Atualiza o highlight do OptionList""" + """Updates the OptionList highlight""" try: if index < len(self.diary_list.options): self.diary_list.highlighted = index self.diary_list.refresh() except Exception as e: - self.notify(f"Erro ao atualizar highlight: {str(e)}") + self.notify(f"Error updating highlight: {str(e)}") async def async_refresh_diaries(self): - """Versão assíncrona do refresh""" + """Async version of refresh""" if self.is_refreshing: return @@ -127,21 +127,21 @@ class DiaryListScreen(Screen): service_manager = self.app.service_manager travel_diary_service = service_manager.get_travel_diary_service() - # Usa método assíncrono + # Uses async method diaries = await travel_diary_service.async_read_all() - # Salva o estado atual + # Saves current state current_diary_id = None if (self.selected_diary_index is not None and self.selected_diary_index in self.diary_id_map): current_diary_id = self.diary_id_map[self.selected_diary_index] - # Limpa e reconstrói + # Clears and rebuilds self.diary_list.clear_options() self.diary_id_map = {} if not diaries: - self.diary_list.add_option("[dim]Nenhum diário encontrado. Pressione 'N' para criar um novo![/dim]") + self.diary_list.add_option("[dim]No diaries found. Press 'N' to create a new one![/dim]") self.selected_diary_index = None else: new_selected_index = 0 @@ -160,12 +160,12 @@ class DiaryListScreen(Screen): self.update_buttons_state() except Exception as e: - self.notify(f"Erro ao carregar diários: {str(e)}") + self.notify(f"Error loading diaries: {str(e)}") finally: self.is_refreshing = False def on_option_list_option_highlighted(self, event: OptionList.OptionHighlighted) -> None: - """Handle quando uma opção é destacada""" + """Handle when an option is highlighted""" if self.diary_id_map and event.option_index in self.diary_id_map: self.selected_diary_index = event.option_index else: @@ -174,7 +174,7 @@ class DiaryListScreen(Screen): self.update_buttons_state() def on_option_list_option_selected(self, event: OptionList.OptionSelected) -> None: - """Handle quando uma opção é selecionada""" + """Handle when an option is selected""" if self.diary_id_map and event.option_index in self.diary_id_map: self.selected_diary_index = event.option_index self.action_open_diary() @@ -184,7 +184,7 @@ class DiaryListScreen(Screen): self.update_buttons_state() def update_buttons_state(self): - """Atualiza o estado dos botões""" + """Updates button states""" has_selection = (self.selected_diary_index is not None and self.selected_diary_index in self.diary_id_map) @@ -192,7 +192,7 @@ class DiaryListScreen(Screen): self.open_diary.disabled = not has_selection def on_button_pressed(self, event: Button.Pressed) -> None: - """Handle cliques nos botões""" + """Handle button clicks""" button_id = event.button.id if button_id == "new_diary": @@ -203,7 +203,7 @@ class DiaryListScreen(Screen): self.action_open_diary() def action_new_diary(self): - """Ação para criar novo diário""" + """Action to create new diary""" self.app.push_screen(NewDiaryModal(),self._on_new_diary_submitted) def _on_new_diary_submitted(self,result): @@ -231,7 +231,7 @@ class DiaryListScreen(Screen): def action_edit_selected_diary(self): - """Ação para editar diário selecionado""" + """Action to edit selected diary""" if self.selected_diary_index is not None: diary_id = self.diary_id_map.get(self.selected_diary_index) if diary_id: @@ -240,10 +240,10 @@ class DiaryListScreen(Screen): self._on_edited_diary_name_submitted ) else: - self.notify("Selecione um diário para editar") + self.notify("Select a diary to edit") def action_open_diary(self): - """Ação para abrir diário selecionado""" + """Action to open selected diary""" if self.selected_diary_index is not None: diary_id = self.diary_id_map.get(self.selected_diary_index) if diary_id: @@ -252,43 +252,43 @@ class DiaryListScreen(Screen): else: self.notify("Invalid diary ID") else: - self.notify("Selecione um diário para abrir") + self.notify("Select a diary to open") def _on_edited_diary_name_submitted(self, result: Optional[Tuple[int, str]]) -> None: - """Callback após edição do diário""" + """Callback after diary editing""" if result: diary_id, name = result - self.notify(f"Atualizando diário ID {diary_id} para '{name}'...") - # Agenda a atualização assíncrona + self.notify(f"Updating diary ID {diary_id} to '{name}'...") + # Schedules async update self.call_later(self._async_update_diary, diary_id, name) else: - self.notify("Edição cancelada") + self.notify("Edit canceled") async def _async_update_diary(self, diary_id: int, name: str): - """Atualiza o diário de forma assíncrona""" + """Updates the diary asynchronously""" try: service = self.app.service_manager.get_travel_diary_service() updated_diary = await service.async_update(diary_id, name) if updated_diary: - self.notify(f"Diário '{name}' atualizado!") - # Força refresh após a atualização + self.notify(f"Diary '{name}' updated!") + # Forces refresh after update await self.async_refresh_diaries() else: - self.notify("Erro: Diário não encontrado") + self.notify("Error: Diary not found") except Exception as e: - self.notify(f"Erro ao atualizar: {str(e)}") + self.notify(f"Error updating: {str(e)}") def action_force_refresh(self): - """Força refresh manual""" - self.notify("Forçando refresh...") - # Tenta ambas as versões - self.refresh_diaries() # Síncrona - self.call_later(self.async_refresh_diaries) # Assíncrona + """Forces manual refresh""" + self.notify("Forcing refresh...") + # Tries both versions + self.refresh_diaries() # Synchronous + self.call_later(self.async_refresh_diaries) # Asynchronous def action_open_selected_diary(self): - """Ação do binding ENTER""" + """Action for ENTER binding""" self.action_open_diary() def action_about_cmd(self): diff --git a/src/pilgrim/ui/screens/edit_diary_modal.py b/src/pilgrim/ui/screens/edit_diary_modal.py index 1c346cd..6834a64 100644 --- a/src/pilgrim/ui/screens/edit_diary_modal.py +++ b/src/pilgrim/ui/screens/edit_diary_modal.py @@ -6,29 +6,28 @@ from textual.widgets import Label, Input, Button class EditDiaryModal(ModalScreen[tuple[int,str]]): BINDINGS = [ - ("escape", "cancel", "Cancelar"), + ("escape", "cancel", "Cancel"), ] def __init__(self, diary_id: int): super().__init__() self.diary_id = diary_id self.current_diary_name = self.app.service_manager.get_travel_diary_service().read_by_id(self.diary_id).name - self.name_input = Input(value=self.current_diary_name, id="edit_diary_name_input",classes="EditDiaryModal-NameInput") + self.name_input = Input(value=self.current_diary_name, id="edit_diary_name_input", classes="EditDiaryModal-NameInput") def compose(self) -> ComposeResult: with Vertical(id="edit_diary_dialog", classes="EditDiaryModal-Dialog"): - yield Label(f"Editar Diário: {self.current_diary_name}", classes="EditDiaryModal-Title") - yield Label("Novo Nome do Diário:") + yield Label("Edit Diary", classes="EditDiaryModal-Title") + yield Label("New Diary Name:") yield self.name_input - with Horizontal(classes="dialog-buttons"): - yield Button("Salvar", variant="primary", id="save_diary_button") - yield Button("Cancelar", variant="default", id="cancel_button") + with Horizontal(classes="EditDiaryModal-ButtonsContainer"): + yield Button("Save", variant="primary", id="save_diary_button", classes="EditDiaryModal-SaveButton") + yield Button("Cancel", variant="default", id="cancel_button", classes="EditDiaryModal-CancelButton") def on_mount(self) -> None: - """Foca no campo de entrada e move o cursor para o final do texto.""" + """Focuses on the input field and moves cursor to the end of text.""" self.name_input.focus() self.name_input.cursor_position = len(self.name_input.value) - # REMOVIDA A LINHA QUE CAUSA O ERRO: self.name_input.select_text() def on_button_pressed(self, event: Button.Pressed) -> None: if event.button.id == "save_diary_button": @@ -36,10 +35,10 @@ class EditDiaryModal(ModalScreen[tuple[int,str]]): if new_diary_name and new_diary_name != self.current_diary_name: self.dismiss((self.diary_id, new_diary_name)) elif new_diary_name == self.current_diary_name: - self.notify("Nenhuma alteração feita.", severity="warning") + self.notify("No changes made.", severity="warning") self.dismiss(None) else: - self.notify("O nome do diário não pode estar vazio.", severity="warning") + self.notify("Diary name cannot be empty.", severity="warning") self.name_input.focus() elif event.button.id == "cancel_button": self.dismiss(None) diff --git a/src/pilgrim/ui/screens/edit_entry_screen.py b/src/pilgrim/ui/screens/edit_entry_screen.py index 0fd4aa1..5ab7fa9 100644 --- a/src/pilgrim/ui/screens/edit_entry_screen.py +++ b/src/pilgrim/ui/screens/edit_entry_screen.py @@ -14,21 +14,20 @@ from pilgrim.ui.screens.rename_entry_modal import RenameEntryModal class EditEntryScreen(Screen): - TITLE = "Pilgrim - Edit Entry" + TITLE = "Pilgrim - Edit" BINDINGS = [ Binding("ctrl+s", "save", "Save"), Binding("ctrl+n", "next_entry", "Next/New Entry"), Binding("ctrl+b", "prev_entry", "Previous Entry"), Binding("ctrl+r", "rename_entry", "Rename Entry"), - Binding("escape", "back_to_list", "Back to List"), - Binding("r", "force_refresh", "Force refresh"), + Binding("escape", "back_to_list", "Back to List") ] def __init__(self, diary_id: int = 1): super().__init__() self.diary_id = diary_id - self.diary_name = "Unknown Diary" + self.diary_name = f"Diary {diary_id}" # Use a better default name self.current_entry_index = 0 self.entries: List[Entry] = [] self.is_new_entry = False @@ -81,8 +80,7 @@ class EditEntryScreen(Screen): """Called when the screen is mounted""" # First update diary info, then refresh entries self.update_diary_info() - # Use a small delay to ensure diary info is loaded before refreshing entries - self.set_timer(0.1, self.refresh_entries) + self.refresh_entries() def update_diary_info(self): """Updates diary information""" @@ -94,11 +92,27 @@ class EditEntryScreen(Screen): if diary: self.diary_name = diary.name self.diary_info.update(f"Diary: {self.diary_name}") - self.notify(f"Loaded diary: {self.diary_name}") else: - self.notify(f"Diary with ID {self.diary_id} not found") + # If diary not found, try to get a default name + self.diary_name = f"Diary {self.diary_id}" + self.diary_info.update(f"Diary: {self.diary_name}") + self.notify(f"Diary {self.diary_id} not found, using default name") except Exception as e: + # If there's an error, use a default name but don't break the app + self.diary_name = f"Diary {self.diary_id}" + self.diary_info.update(f"Diary: {self.diary_name}") self.notify(f"Error loading diary info: {str(e)}") + + # Always ensure the diary info is updated + self._ensure_diary_info_updated() + + def _ensure_diary_info_updated(self): + """Ensures the diary info widget is always updated with current diary name""" + try: + self.diary_info.update(f"Diary: {self.diary_name}") + except Exception as e: + # If even this fails, at least try to show something + self.diary_info.update(f"Diary: {self.diary_id}") def refresh_entries(self): """Synchronous version of refresh""" @@ -124,6 +138,9 @@ class EditEntryScreen(Screen): except Exception as e: self.notify(f"Error loading entries: {str(e)}") + + # Ensure diary info is updated even if entries fail to load + self._ensure_diary_info_updated() async def async_refresh_entries(self): """Asynchronous version of refresh""" @@ -178,7 +195,7 @@ class EditEntryScreen(Screen): self._update_status_indicator("New", "new") else: current_entry = self.entries[self.current_entry_index] - entry_text = f"Entry: ({self.current_entry_index + 1}/{len(self.entries)}) {current_entry.title}" + entry_text = f"Entry: \\[{self.current_entry_index + 1}/{len(self.entries)}] {current_entry.title}" self.entry_info.update(entry_text) self._update_status_indicator("Saved", "saved") @@ -198,10 +215,6 @@ class EditEntryScreen(Screen): def _update_entry_display(self): """Updates the display of the current entry""" if not self.entries and not self.is_new_entry: - # Ensure diary name is loaded - if self.diary_name == "Unknown Diary": - self.update_diary_info() - self.text_entry.text = f"No entries found for diary '{self.diary_name}'\n\nPress Ctrl+N to create a new entry." self.text_entry.read_only = True self._original_content = self.text_entry.text diff --git a/src/pilgrim/ui/screens/new_diary_modal.py b/src/pilgrim/ui/screens/new_diary_modal.py index 26323ba..ecc84f5 100644 --- a/src/pilgrim/ui/screens/new_diary_modal.py +++ b/src/pilgrim/ui/screens/new_diary_modal.py @@ -27,17 +27,17 @@ class NewDiaryModal(ModalScreen[str]): self.name_input.focus() def on_button_pressed(self, event: Button.Pressed) -> None: - """Lida com os cliques dos botões.""" + """Handles button clicks.""" if event.button.id == "create_diary_button": diary_name = self.name_input.value.strip() if diary_name: self.dismiss(diary_name) else: - self.notify("O nome do diário não pode estar vazio.", severity="warning") + self.notify("Diary name cannot be empty.", severity="warning") self.name_input.focus() elif event.button.id == "cancel_button": self.dismiss("") def action_cancel(self) -> None: - """Ação para cancelar a modal.""" + """Action to cancel the modal.""" self.dismiss("") \ No newline at end of file diff --git a/src/pilgrim/ui/ui.py b/src/pilgrim/ui/ui.py index ecbdeb2..2443f74 100644 --- a/src/pilgrim/ui/ui.py +++ b/src/pilgrim/ui/ui.py @@ -22,7 +22,7 @@ class UIApp(App): def on_mount(self) -> None: - """Chamado quando a app inicia. Carrega a tela principal.""" + """Called when the app starts. Loads the main screen.""" self.push_screen(DiaryListScreen()) def get_system_commands(self, screen: Screen) -> Iterable[SystemCommand]: From 697ce03638dbb4a1ff65e90b0cbfc3eab40a0f24 Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Wed, 25 Jun 2025 01:20:34 -0300 Subject: [PATCH 2/3] Fixed the action to quit the application on the diary_list_screen.py --- src/pilgrim/ui/screens/diary_list_screen.py | 6 +- src/pilgrim/ui/styles/pilgrim.css | 464 ++++++++++++-------- 2 files changed, 294 insertions(+), 176 deletions(-) diff --git a/src/pilgrim/ui/screens/diary_list_screen.py b/src/pilgrim/ui/screens/diary_list_screen.py index 0b0c042..8166ffa 100644 --- a/src/pilgrim/ui/screens/diary_list_screen.py +++ b/src/pilgrim/ui/screens/diary_list_screen.py @@ -292,4 +292,8 @@ class DiaryListScreen(Screen): self.action_open_diary() def action_about_cmd(self): - self.app.push_screen(AboutScreen()) \ No newline at end of file + self.app.push_screen(AboutScreen()) + + def action_quit(self): + """Action to quit the application""" + self.app.exit() \ No newline at end of file diff --git a/src/pilgrim/ui/styles/pilgrim.css b/src/pilgrim/ui/styles/pilgrim.css index 673bbe5..76828bb 100644 --- a/src/pilgrim/ui/styles/pilgrim.css +++ b/src/pilgrim/ui/styles/pilgrim.css @@ -3,175 +3,7 @@ Screen { background: $surface-darken-1; align: center middle; } -.DiaryListScreen-DiaryListContainer { - height: 1fr; - width: 100%; - layout: vertical; - align: center top; /* Alinha no topo para seguir o wireframe */ - padding: 2 4; /* Mais espaço nas laterais */ - background: $surface; /* Removendo aquamarine para ficar mais limpo */ -} -/* A lista de diários - área principal como no wireframe */ -.DiaryListScreen-DiaryListOptions { - border: round $primary-lighten-2; - background: $surface; - width: 75%; /* Largura generosa como no wireframe */ - height: 72%; /* Ocupa o espaço disponível */ - margin: 2 0; /* Margem vertical para separar dos outros elementos */ -} - -.DiaryListScreen-DiaryListOptions:focus { - border: round $primary; -} - -/* O contêiner dos botões - logo abaixo da lista */ -.DiaryListScreen-ButtonsGrid { - layout: horizontal; - align: center middle; - width: 79%; /* Mesma largura da lista */ - height: 20%; /* Aumentando altura para caber o texto dos botões */ -} - -/* Botões individuais - garantindo espaço para o texto */ -.DiaryListScreen-NewDiaryButton, -.DiaryListScreen-EditDiaryButton, -.DiaryListScreen-OpenDiaryButton { - margin: 0 1 1 0; /* Espaço entre os botões */ - height: 1fr; - width: 1fr; - border: round grey; -} - -/* As dicas - usando a classe correta */ -.DiaryListScreen-DiaryListTips { - width: 100%; /* Largura total quando usando dock */ - height: auto; - text-style: italic; - text-align: center; /* Centraliza o texto dentro do elemento */ - color: $text-muted; - dock: bottom; /* Gruda no fundo da tela */ - margin: 0 1; -} - -/* Estilos genéricos que não mudaram */ -.option-list--option-highlighted { - background: $primary-darken-2; -} - -.option-list--option-selected { - text-style: bold; - background: $primary; -} - -Header { - background: $primary; - color: $text; -} - -Footer { - background: $primary; - color: $text; -} - -AboutScreen { - align: center middle; -} - -.AboutScreen_AboutContainer { - align: center middle; - width: 85%; - height: 95%; - border: thick $primary; - background: $surface; - margin: 1; -} - -.AboutScreen_AboutContainer TextArea { - align: center middle; - width: 100%; - height: 55%; - margin: 2; - padding: 1; -} - -.AboutScreen_SubContainer { - align: center middle; - height: 45%; - padding: 1 1; - margin: 1 1; -} - -.AboutScreen_AboutTitle { - color: $accent; - text-style: bold; - text-align: center; - margin-bottom: 1; -} - -.AboutScreen_AboutVersion { - color: $warning; - text-style: italic; - text-align: center; - margin-bottom: 1; -} - -.AboutScreen_AboutContent { - text-align: center; - margin-bottom: 1; -} - -.AboutScreen_AboutContact, -.AboutScreen_AboutAuthor { - color: $text-muted; - text-align: center; - margin-bottom: 1; -} - -.AboutScreen_AboutLicense { - height: 60%; -} - -Screen.-modal { - background: rgba(0, 0, 0, 0.7); /* Escurece o fundo da tela por baixo */ - align: center middle; /* Centraliza o conteúdo (sua modal) que está nesta tela modal */ -} - -.NewDiaryModal-Dialog { - width: 60%; /* Largura do diálogo */ - height: auto; /* Altura automática */ - background: $surface; /* Fundo do diálogo */ - border: thick $accent; /* Borda chamativa */ - padding: 2 4; /* Espaçamento interno */ - align: center middle; /* Centraliza conteúdo dentro do diálogo */ - layout: vertical; -} - -.NewDiaryModal-Dialog .NewDiaryModal-Title{ - text-align: center; - text-style: bold; - color: $primary; - margin-bottom: 1; -} - -.NewDiaryModal-NameInput{ - width: 1fr; /* Ocupa a largura disponível */ - margin-bottom: 2; -} - -.NewDiaryModal-ButtonsContainer{ - width: 1fr; - height: auto; - align: center middle; - padding-top: 1; -} - -.NewDiaryModal-ButtonsContainer Button{ - margin: 0 1; - width: 1fr; -} - -/* EditEntryScreen Styles */ .EditEntryScreen-sub-header { layout: horizontal; background: $primary-darken-1; @@ -234,7 +66,292 @@ Screen.-modal { border: none; } -/* RenameEntryModal Styles */ +AboutScreen { + align: center middle; +} + +#AboutScreen_AboutContainer { + align: center middle; + width: 85%; + height: 95%; + border: thick $primary; + background: $surface; + margin: 1; +} + +#AboutScreen_AboutContainer TextArea { + align: center middle; + width: 100%; + height: 55%; + margin: 2; + padding: 1; +} + +#AboutScreen_SubContainer { + align: center middle; + height: 45%; + padding: 1 1; + margin: 1 1; +} + +#AboutScreen_AboutTitle { + color: $accent; + text-style: bold; + text-align: center; + margin-bottom: 1; +} + +#AboutScreen_AboutVersion { + color: $warning; + text-style: italic; + text-align: center; + margin-bottom: 1; +} + +#AboutScreen_AboutContent { + text-align: center; + margin-bottom: 1; +} + +#AboutScreen_AboutContact, +#AboutScreen_AboutAuthor { + color: $text-muted; + text-align: center; + margin-bottom: 1; +} + +#AboutScreen_AboutLicense { + height: 60%; +} + +/* Main container - distributing vertical space */ +.DiaryListScreen-DiaryListContainer { + height: 1fr; + width: 100%; + layout: vertical; + align: center top; /* Aligns at the top to follow the wireframe */ + padding: 2 4; /* More space on the sides */ + background: $surface; /* Removing aquamarine to keep it cleaner */ +} + +/* Diary list - main area as in the wireframe */ +.DiaryListScreen-DiaryListOptions { + border: round $primary-lighten-2; + background: $surface; + width: 75%; /* Generous width as in the wireframe */ + height: 60%; /* Occupies available space */ + margin: 2 0; /* Vertical margin to separate from other elements */ +} + +.DiaryListScreen-DiaryListOptions:focus { + border: round $primary; +} + +/* Button container - right below the list */ +.DiaryListScreen-ButtonsGrid { + layout: horizontal; + align: center middle; + width: 79%; /* Same width as the list */ + height: 20%; /* Increasing height to fit button text */ +} + +/* Individual buttons - ensuring space for text */ +.DiaryListScreen-NewDiaryButton, +.DiaryListScreen-EditDiaryButton, +.DiaryListScreen-OpenDiaryButton { + margin: 0 1 1 0; /* Space between buttons */ + height: 1fr; + width: 1fr; + border: round grey; +} + +/* Tips - using the correct class */ +.DiaryListScreen-DiaryListTips { + width: 100%; /* Full width when using dock */ + height: auto; + text-style: italic; + text-align: center; /* Centers text within the element */ + color: $text-muted; + dock: bottom; /* Sticks to the bottom of the screen */ + margin: 0 1; +} + +/* Generic styles that haven't changed */ +.option-list--option-highlighted { + background: $primary-darken-2; +} + +.option-list--option-selected { + text-style: bold; + background: $primary; +} + +Header { + background: $primary; + color: $text; +} + +Footer { + background: $primary; + color: $text; +} + +Screen.-modal { + background: rgba(0, 0, 0, 0.7); /* Darkens the background screen underneath */ + align: center middle; /* Centers the content (your modal) that is in this modal screen */ +} + +/* Style for the new diary modal dialog */ +.NewDiaryModal-dialog { + layout: vertical; + width: 60%; + height: auto; + background: $surface; + border: thick $accent; + padding: 2 4; + align: center middle; +} + +.NewDiaryModal-title { + text-align: center; + text-style: bold; + color: $primary; + margin-bottom: 1; +} + +.NewDiaryModal-label { + margin-bottom: 1; +} + +.NewDiaryModal-name-input { + width: 1fr; + margin-bottom: 2; +} + +.NewDiaryModal-buttons { + width: 1fr; + height: auto; + align: center middle; + padding-top: 1; +} + +.NewDiaryModal-buttons Button { + margin: 0 1; + width: 1fr; +} + +/* Additional classes for NewDiaryModal */ +.NewDiaryModal-Dialog { + layout: vertical; + width: 60%; + height: auto; + background: $surface; + border: thick $accent; + padding: 2 4; + align: center middle; +} + +.NewDiaryModal-Title { + text-align: center; + text-style: bold; + color: $primary; + margin-bottom: 1; +} + +.NewDiaryModal-NameInput { + width: 1fr; + margin-bottom: 2; +} + +.NewDiaryModal-ButtonsContainer { + width: 1fr; + height: auto; + align: center middle; + padding-top: 1; +} + +.NewDiaryModal-CreateDiaryButton, +.NewDiaryModal-CancelButton { + margin: 0 1; + width: 1fr; +} + +/* Style for the edit diary modal dialog */ +.EditDiaryModal-dialog { + layout: vertical; + width: 60%; + height: auto; + background: $surface; + border: thick $warning; + padding: 2 4; + align: center middle; +} + +.EditDiaryModal-title { + text-align: center; + text-style: bold; + color: $warning; + margin-bottom: 1; +} + +.EditDiaryModal-label { + margin-bottom: 1; +} + +.EditDiaryModal-name-input { + width: 1fr; + margin-bottom: 2; +} + +.EditDiaryModal-buttons { + width: 1fr; + height: auto; + align: center middle; + padding-top: 1; +} + +.EditDiaryModal-buttons Button { + margin: 0 1; + width: 1fr; +} + +/* Additional classes for EditDiaryModal */ +.EditDiaryModal-Dialog { + layout: vertical; + width: 60%; + height: auto; + background: $surface; + border: thick $warning; + padding: 2 4; + align: center middle; +} + +.EditDiaryModal-Title { + text-align: center; + text-style: bold; + color: $warning; + margin-bottom: 1; +} + +.EditDiaryModal-NameInput { + width: 1fr; + margin-bottom: 2; +} + +.EditDiaryModal-ButtonsContainer { + width: 1fr; + height: auto; + align: center middle; + padding-top: 1; +} + +.EditDiaryModal-SaveButton, +.EditDiaryModal-CancelButton { + margin: 0 1; + width: 1fr; +} + +/* Style for the rename entry modal dialog */ .RenameEntryModal-dialog { layout: vertical; width: 60%; @@ -252,10 +369,6 @@ Screen.-modal { margin-bottom: 1; } -.RenameEntryModal-label { - margin-bottom: 1; -} - .RenameEntryModal-name-input { width: 1fr; margin-bottom: 2; @@ -268,7 +381,8 @@ Screen.-modal { padding-top: 1; } -.RenameEntryModal-buttons Button { +.RenameEntryModal-save-button, +.RenameEntryModal-cancel-button { margin: 0 1; width: 1fr; -} \ No newline at end of file +} \ No newline at end of file From 869c183e73ed369791d3d1bfa54d941c4cbda9d3 Mon Sep 17 00:00:00 2001 From: Gustavo Henrique Santos Souza de Miranda Date: Wed, 25 Jun 2025 01:31:20 -0300 Subject: [PATCH 3/3] Changed the size of grid of buttons to be the same lenght of the list of diaries --- src/pilgrim/ui/styles/pilgrim.css | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pilgrim/ui/styles/pilgrim.css b/src/pilgrim/ui/styles/pilgrim.css index 76828bb..fef0786 100644 --- a/src/pilgrim/ui/styles/pilgrim.css +++ b/src/pilgrim/ui/styles/pilgrim.css @@ -151,7 +151,7 @@ AboutScreen { .DiaryListScreen-ButtonsGrid { layout: horizontal; align: center middle; - width: 79%; /* Same width as the list */ + width: 75%; /* Same width as the diary list */ height: 20%; /* Increasing height to fit button text */ } @@ -163,6 +163,8 @@ AboutScreen { height: 1fr; width: 1fr; border: round grey; + text-align: center; + content-align: center middle; } /* Tips - using the correct class */