Compare commits

...
10 changed files with 244 additions and 27 deletions
+22
View File
@@ -1,3 +1,4 @@
import re
from datetime import datetime from datetime import datetime
from typing import List from typing import List
@@ -54,3 +55,24 @@ class EntryService:
self.session.commit() self.session.commit()
return excluded return excluded
return None return None
def delete_references_for_specific_photo(self, entry: Entry, photo_hash: str) -> Entry:
regex = r"\[\[photo::" + re.escape(photo_hash) + r"\]\]"
entry.text = re.sub(regex, lambda match: ' ' * len(match.group(0)), entry.text)
self.session.commit()
self.session.refresh(entry)
return entry
def delete_all_photo_references(self, entry: Entry, commit=True) -> Entry:
if not entry.photos:
return entry
photo_hashes = {photo.photo_hash[:8] for photo in entry.photos}
regex = r"\[\[photo::(" + "|".join(re.escape(h) for h in photo_hashes) + r")\]\]"
entry.text = re.sub(regex, lambda match: ' ' * len(match.group(0)), entry.text)
if commit:
self.session.commit()
self.session.refresh(entry)
return entry
+3 -2
View File
@@ -141,7 +141,7 @@ class PhotoService:
return original return original
return None return None
def delete(self, photo_src: Photo) -> Photo | None: def delete(self, photo_src: Photo, commit=True) -> Photo | None:
excluded = self.read_by_id(photo_src.id) excluded = self.read_by_id(photo_src.id)
if excluded: if excluded:
# Store photo data before deletion # Store photo data before deletion
@@ -162,7 +162,8 @@ class PhotoService:
file_path.unlink() file_path.unlink()
self.session.delete(excluded) self.session.delete(excluded)
self.session.commit() if commit:
self.session.commit()
return deleted_photo return deleted_photo
return None return None
@@ -3,12 +3,16 @@ import re
import shutil import shutil
from pathlib import Path from pathlib import Path
from pilgrim.models.entry import Entry
from pilgrim.utils import DirectoryManager from pilgrim.utils import DirectoryManager
from sqlalchemy.exc import IntegrityError from sqlalchemy.exc import IntegrityError
from pilgrim.models.travel_diary import TravelDiary from pilgrim.models.travel_diary import TravelDiary
from unidecode import unidecode from unidecode import unidecode
from pilgrim.service.photo_service import PhotoService
from pilgrim.service.entry_service import EntryService
class TravelDiaryService: class TravelDiaryService:
def __init__(self, session): def __init__(self, session):
self.session = session self.session = session
@@ -147,3 +151,32 @@ class TravelDiaryService:
self.session.rollback() self.session.rollback()
raise ValueError(f"Could not delete diary: {str(e)}") raise ValueError(f"Could not delete diary: {str(e)}")
return None return None
def delete_all_entries(self,travel_diary: TravelDiary):
diary = self.read_by_id(travel_diary.id)
if diary is not None:
diary.entries = []
self.session.commit()
return True
return False
def delete_all_photos(self,travel_diary: TravelDiary):
diary = self.read_by_id(travel_diary.id)
photo_service = PhotoService(self.session)
entry_service = EntryService(self.session)
if diary is not None:
for entry in list(diary.entries):
entry_service.delete_all_photo_references(entry,commit=False)
for photo in list(diary.photos):
photo_service.delete(photo,commit=False)
self.session.commit()
return True
return False
@@ -9,6 +9,7 @@ from textual.containers import Vertical, Container, Horizontal
from pilgrim.models.travel_diary import TravelDiary from pilgrim.models.travel_diary import TravelDiary
from pilgrim.ui.screens.about_screen import AboutScreen from pilgrim.ui.screens.about_screen import AboutScreen
from pilgrim.ui.screens.diary_settings_screen import SettingsScreen
from pilgrim.ui.screens.edit_diary_modal import EditDiaryModal from pilgrim.ui.screens.edit_diary_modal import EditDiaryModal
from pilgrim.ui.screens.new_diary_modal import NewDiaryModal from pilgrim.ui.screens.new_diary_modal import NewDiaryModal
from pilgrim.ui.screens.edit_entry_screen import EditEntryScreen from pilgrim.ui.screens.edit_entry_screen import EditEntryScreen
@@ -23,6 +24,7 @@ class DiaryListScreen(Screen):
Binding("enter", "open_selected_diary", "Open diary"), Binding("enter", "open_selected_diary", "Open diary"),
Binding("e", "edit_selected_diary", "Edit diary"), Binding("e", "edit_selected_diary", "Edit diary"),
Binding("r", "force_refresh", "Force refresh"), Binding("r", "force_refresh", "Force refresh"),
Binding("s", "diary_settings", "Open The Selected Diary Settings"),
] ]
def __init__(self): def __init__(self):
@@ -286,3 +288,13 @@ class DiaryListScreen(Screen):
def action_quit(self): def action_quit(self):
"""Action to quit the application""" """Action to quit the application"""
self.app.exit() self.app.exit()
def action_diary_settings(self):
if self.selected_diary_index is not None:
diary_id = self.diary_id_map.get(self.selected_diary_index)
if diary_id:
self.app.push_screen(SettingsScreen(diary_id=diary_id))
else:
self.notify("Invalid diary ID")
else:
self.notify("Select a diary to open the settings")
+116 -18
View File
@@ -7,7 +7,7 @@ from textual.reactive import reactive
from textual.binding import Binding from textual.binding import Binding
from textual import on from textual import on
from pilgrim import TravelDiary from pilgrim.models.travel_diary import TravelDiary
from pilgrim.ui.screens.modals.delete_all_entries_from_diary_modal import DeleteAllEntriesModal from pilgrim.ui.screens.modals.delete_all_entries_from_diary_modal import DeleteAllEntriesModal
from pilgrim.ui.screens.modals.delete_all_photos_from_diary_modal import DeleteAllPhotosModal from pilgrim.ui.screens.modals.delete_all_photos_from_diary_modal import DeleteAllPhotosModal
from pilgrim.ui.screens.modals.delete_diary_modal import DeleteDiaryModal from pilgrim.ui.screens.modals.delete_diary_modal import DeleteDiaryModal
@@ -19,22 +19,23 @@ class SettingsScreen(Screen):
Binding("escape","cancel","Cancel"), Binding("escape","cancel","Cancel"),
] ]
def __init__(self,diary:TravelDiary): def __init__(self,diary_id:int):
super().__init__() super().__init__()
self.current_diary = diary self.current_diary = self.app.service_manager.get_travel_diary_service().read_by_id(diary_id)
self.header = Header() self.header = Header()
self.footer = Footer() self.footer = Footer()
self.title = "Settings" self.title = "Settings"
self.diary_name = Static(self.current_diary.name,id="DiarySettingsScreen-DiaryName") self.diary_name = Static(self.current_diary.name,id="DiarySettingsScreen-DiaryName")
self.is_the_diary_set_to_auto_open = False self.notify(str(self.app.config_manager))
self.diary_entry_count = Static("0") self.is_the_diary_set_to_auto_open = self.app.config_manager.get_auto_open_diary() == self.current_diary.name
self.diary_photo_count = Static("0") self.diary_entry_count = Static(str(len(self.current_diary.entries)))
self.save_button = Button("Save") self.diary_photo_count = Static(str(len(self.current_diary.photos)))
self.save_button = Button("Save",id="DiarySettingsScreen-SaveButton" )
self.cancel_button = Button("Cancel",id="DiarySettingsScreen-cancel_button") self.cancel_button = Button("Cancel",id="DiarySettingsScreen-cancel_button")
self.apply_button = Button("Apply") self.apply_button = Button("Apply",id="DiarySettingsScreen-ApplyButton")
self.backup_diary_button = Button("Backup Diary")
self.delete_diary_button = Button("Delete Diary",id="DiarySettingsScreen-DeleteDiaryButton") self.delete_diary_button = Button("Delete Diary",id="DiarySettingsScreen-DeleteDiaryButton")
self.delete_all_entries_button = Button("Delete All Entries",id="DiarySettingsScreen-DeleteAllEntriesButton") self.delete_all_entries_button = Button("Delete All Entries",id="DiarySettingsScreen-DeleteAllEntriesButton")
self.delete_all_photos_button = Button("Delete All Photos",id="DiarySettingsScreen-DeleteAllPhotosButton") self.delete_all_photos_button = Button("Delete All Photos",id="DiarySettingsScreen-DeleteAllPhotosButton")
@@ -46,12 +47,6 @@ class SettingsScreen(Screen):
id="DiarySettingsScreen-DeleteDiaryButtonContainer", id="DiarySettingsScreen-DeleteDiaryButtonContainer",
classes="DiarySettingsScreen-DeleteDiaryButtonContainer Button_Container" classes="DiarySettingsScreen-DeleteDiaryButtonContainer Button_Container"
) )
self.backup_diary_button_container = Container(
Label("Backup Diary:"),
self.backup_diary_button,
id="DiarySettingsScreen-BackupDiaryButtonContainer",
classes="DiarySettingsScreen-BackupDiaryButtonContainer Button_Container"
)
self.delete_all_entries_button_container = Container( self.delete_all_entries_button_container = Container(
Label("Delete All Entries:"), Label("Delete All Entries:"),
self.delete_all_entries_button, self.delete_all_entries_button,
@@ -132,7 +127,7 @@ class SettingsScreen(Screen):
@on(Checkbox.Changed, "#set_auto_open_to_this_diary") @on(Checkbox.Changed, "#set_auto_open_to_this_diary")
def on_checkbox_changed(self, event): def on_checkbox_changed(self, event):
self.is_changed = not self.is_changed self.is_changed = not self.is_changed
self.notify("Checkboxed")
@on(Button.Pressed, "#DiarySettingsScreen-cancel_button") @on(Button.Pressed, "#DiarySettingsScreen-cancel_button")
def on_cancel_button_pressed(self, event): def on_cancel_button_pressed(self, event):
@@ -154,7 +149,15 @@ class SettingsScreen(Screen):
if self.is_changed: if self.is_changed:
self.notify("Cancel button pressed, but changes are not saved",severity="error") self.notify("Cancel button pressed, but changes are not saved",severity="error")
return return
self.app.exit() self.dismiss()
@on(Button.Pressed, "#DiarySettingsScreen-SaveButton")
def on_save_button_pressed(self, event):
self.action_save()
@on(Button.Pressed, "#DiarySettingsScreen-ApplyButton")
def on_apply_button_pressed(self, event):
self.action_apply()
def watch_is_changed(self, value): def watch_is_changed(self, value):
@@ -170,7 +173,102 @@ class SettingsScreen(Screen):
yield Footer() yield Footer()
def on_mount(self): def on_mount(self):
pass if self.app.config_manager.get_auto_open_diary() == self.current_diary.name:
self.call_after_refresh(self.set_checkbox_state)
def set_checkbox_state(self): def set_checkbox_state(self):
self.set_auto_open_to_this_diary.value = True self.set_auto_open_to_this_diary.value = True
def _set_auto_open_diary(self,value):
self.app.config_manager.set_auto_open_diary(value)
self.app.config_manager.save_config()
self.is_changed = False
def _get_auto_open_diary(self):
return self.app.config_manager.get_auto_open_diary()
def _make_auto_open_diary_value(self):
value = None
if self.set_auto_open_to_this_diary.value:
value = self.current_diary.name
return value
def action_save(self):
if not self.is_changed:
self.dismiss()
return
value = self._make_auto_open_diary_value()
current_auto_open = self._get_auto_open_diary()
if current_auto_open is None:
self._set_auto_open_diary(value)
self.notify("Settings saved")
self.dismiss()
return
if current_auto_open == self.current_diary.name:
if value is None:
self._set_auto_open_diary(None)
self.notify("Auto-open disabled")
else:
self.is_changed = False
self.notify("No changes made")
self.dismiss()
return
if value is not None:
self._set_auto_open_diary(value)
self.notify(f"Auto-open changed from '{current_auto_open}' to '{self.current_diary.name}'")
self.dismiss()
else:
self.is_changed = False
self.notify("No changes made")
self.dismiss()
def action_apply(self):
if not self.is_changed:
return
value = self._make_auto_open_diary_value()
current_auto_open = self._get_auto_open_diary()
if current_auto_open is None:
self._set_auto_open_diary(value)
self.notify("Settings applied")
return
if current_auto_open == self.current_diary.name:
if value is None:
self._set_auto_open_diary(None)
self.notify("Auto-open disabled")
else:
self.is_changed = False
self.notify("No changes made")
return
if value is not None:
self._set_auto_open_diary(value)
self.notify(f"Auto-open changed from '{current_auto_open}' to '{self.current_diary.name}'")
else:
self.is_changed = False
self.notify("No changes made")
@@ -3,6 +3,7 @@ from textual.widgets import Button
from textual import on from textual import on
from pilgrim.ui.screens.modals.delete_yes_confirmation_modal import DeleteYesConfirmationModal from pilgrim.ui.screens.modals.delete_yes_confirmation_modal import DeleteYesConfirmationModal
@@ -10,11 +11,23 @@ class DeleteAllEntriesModal(DeleteYesConfirmationModal):
def __init__(self,diary_id:int): def __init__(self,diary_id:int):
super().__init__(diary_id) super().__init__(diary_id)
self.head_text.update("Are you sure you want to delete all entries from this diary?") self.head_text.update("Are you sure you want to delete all entries from this diary?")
self.delete_button.add_class("DeleteDiaryModal-DeleteButton")
@on(Button.Pressed, "#DeleteDiaryModal-DeleteButton") @on(Button.Pressed, ".DeleteDiaryModal-DeleteButton")
def on_delete_button_pressed(self, event): def on_delete_button_pressed(self, event):
self.result = True
self.dismiss()
from pilgrim.ui.screens.diary_list_screen import DiaryListScreen
self.result = True
self._delete_entries()
self.dismiss()
self.app.push_screen(DiaryListScreen())
def _delete_entries(self):
diary = self.app.service_manager.get_travel_diary_service().read_by_id(self.diary_id)
if self.app.service_manager.get_travel_diary_service().delete_all_entries(diary):
self.notify("All entries deleted successfully")
else:
self.notify("Failed to delete all entries")
@@ -10,11 +10,23 @@ class DeleteAllPhotosModal(DeleteYesConfirmationModal):
def __init__(self,diary_id:int): def __init__(self,diary_id:int):
super().__init__(diary_id) super().__init__(diary_id)
self.head_text.update("Are you sure you want to delete all photos from this diary?") self.head_text.update("Are you sure you want to delete all photos from this diary?")
self.delete_button.add_class("DeleteDiaryModal-DeleteButton")
@on(Button.Pressed, "#DeleteDiaryModal-DeleteButton") @on(Button.Pressed, ".DeleteDiaryModal-DeleteButton")
def on_delete_button_pressed(self, event): def on_delete_button_pressed(self, event):
self.result = True
self.dismiss()
from pilgrim.ui.screens.diary_list_screen import DiaryListScreen
self.result = True
self._delete_all_photo()
self.dismiss()
self.app.push_screen(DiaryListScreen())
def _delete_all_photo(self):
diary = self.app.service_manager.get_travel_diary_service().read_by_id(self.diary_id)
if self.app.service_manager.get_travel_diary_service().delete_all_photos(diary):
self.notify("All photos deleted successfully")
else:
self.notify("Failed to delete all photos")
@@ -5,6 +5,8 @@ from textual.binding import Binding
from textual import on from textual import on
class DeleteDiaryModal(Screen): class DeleteDiaryModal(Screen):
BINDINGS = [ BINDINGS = [
@@ -44,11 +46,19 @@ class DeleteDiaryModal(Screen):
else: else:
self.delete_button.disabled = True self.delete_button.disabled = True
@on(Button.Pressed,"#DeleteDiaryModal-DeleteButton") @on(Button.Pressed,"#DeleteDiaryModal-DeleteButton")
def on_delete_button_pressed(self, event): def on_delete_button_pressed(self, event):
self.result = True self.result = True
self._delete_diary()
self.dismiss() self.dismiss()
from pilgrim.ui.screens.diary_list_screen import DiaryListScreen
self.app.push_screen(DiaryListScreen())
@on(Button.Pressed,"#DeleteDiaryModal-CancelButton") @on(Button.Pressed,"#DeleteDiaryModal-CancelButton")
def on_cancel_button_pressed(self, event): def on_cancel_button_pressed(self, event):
@@ -57,3 +67,11 @@ class DeleteDiaryModal(Screen):
def action_cancel(self): def action_cancel(self):
self.dismiss() self.dismiss()
def _delete_diary(self):
diary = self.app.service_manager.get_travel_diary_service().read_by_id(self.diary_id)
self.app.service_manager.get_travel_diary_service().delete(diary)
if self.app.config_manager.get_auto_open_diary() == self.diary_name:
self.app.config_manager.set_auto_open_diary(None)
self.app.config_manager.save_config()
@@ -5,6 +5,8 @@ from textual.binding import Binding
from textual import on from textual import on
class DeleteYesConfirmationModal(Screen): class DeleteYesConfirmationModal(Screen):
BINDINGS = [ BINDINGS = [
Binding("escape", "cancel", "Cancel"), Binding("escape", "cancel", "Cancel"),
@@ -45,8 +47,9 @@ class DeleteYesConfirmationModal(Screen):
self.action_cancel() self.action_cancel()
def action_cancel(self): def action_cancel(self):
from pilgrim.ui.screens.diary_settings_screen import SettingsScreen
self.dismiss() self.dismiss()
self.app.push_screen(SettingsScreen(diary=travel_diary[0])) self.app.push_screen(SettingsScreen(self.diary_id))
def compose(self): def compose(self):
yield Header() yield Header()
+5
View File
@@ -46,6 +46,8 @@ class ConfigManager(metaclass=SingletonMeta):
if self.__data["settings"]["diary"]["auto_open_diary_on_startup"] == "": if self.__data["settings"]["diary"]["auto_open_diary_on_startup"] == "":
self.auto_open_diary = None self.auto_open_diary = None
else:
self.auto_open_diary = self.__data["settings"]["diary"]["auto_open_diary_on_startup"]
self.auto_open_new_diary = self.__data["settings"]["diary"]["auto_open_on_creation"] self.auto_open_new_diary = self.__data["settings"]["diary"]["auto_open_on_creation"]
else: else:
print("Error: config.toml not found.") print("Error: config.toml not found.")
@@ -103,5 +105,8 @@ class ConfigManager(metaclass=SingletonMeta):
def set_auto_open_diary(self, value: str): def set_auto_open_diary(self, value: str):
self.auto_open_diary = value self.auto_open_diary = value
def get_auto_open_diary(self):
return self.auto_open_diary
def set_auto_open_new_diary(self, value: bool): def set_auto_open_new_diary(self, value: bool):
self.auto_open_new_diary = value self.auto_open_new_diary = value