diff options
Diffstat (limited to 'src/book_flow.py')
| -rw-r--r-- | src/book_flow.py | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/src/book_flow.py b/src/book_flow.py new file mode 100644 index 0000000..59b0218 --- /dev/null +++ b/src/book_flow.py @@ -0,0 +1,141 @@ +import gi +gi.require_version("Gtk", "4.0") +from gi.repository import Gtk, Gio +import glob +import shutil +import functools +import os +import subprocess + +import src.utils as utils +import src.db as db +from src.book_detail import BookDetail +from src.book_delete import BookDelete +from src.book_form import BookForm +from src.book_transfer import BookTransfer +from src.picture_cache import PictureCache +import src.book_files as book_files + +class BookFlow(Gtk.FlowBox): + + def __init__(self, window, resources, library, ereader, conn, progress, update_filter_progress): + Gtk.FlowBox.__init__(self) + + self._window = window + self._resources = resources + self._library = library + self._ereader = ereader + self._conn = conn + self._progress = progress + self._update_filter_progress = update_filter_progress + self._picture_cache = PictureCache() + + self._load_books() + + def add_book(self, book_id, data): + self._books[book_id] = data + self.update_progress(data['progress']) + + def update_progress(self, progress): + self._progress = progress + self._reset_view() + + # Private + + def _load_books(self): + """Get books from DB, but most importantly load covers to memory.""" + self._books = db.get_books(self._conn) + for book_id in self._books.keys(): + _ = self._picture_cache.get(f'{self._library}/{book_id}/cover-min.png') + self._reset_view() + + def _reset_view(self): + self.remove_all() + self._flow_box_children = {} + for book_id, data in sorted(self._books.items(), key=book_sort): + if data['progress'] == self._progress: + picture = self._picture_cache.get(f'{self._library}/{book_id}/cover-min.png') + picture.set_can_shrink(False) + + gesture_lclick = Gtk.GestureClick() + gesture_lclick.connect('released', self._on_left_click, book_id, data) + picture.add_controller(gesture_lclick) + + gesture_rclick = Gtk.GestureClick() + gesture_rclick.set_button(3) + gesture_rclick.connect('released', self._on_right_click, picture, book_id, data) + picture.add_controller(gesture_rclick) + + flow_box_child = Gtk.FlowBoxChild() + flow_box_child.set_child(picture) + self._flow_box_children[book_id] = flow_box_child + self.append(flow_box_child) + + def _on_left_click(self, gesture, n_press, x, y, book_id, data): + if n_press == 2: + self._see_book(book_id, data) + + def _on_right_click(self, gesture, n_press, x, y, picture, book_id, data): + if n_press == 1: + popover = Gtk.Popover() + popover.set_parent(picture) + box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5) + popover.set_child(box) + + see_button = Gtk.Button(label='Voir') + see_button.connect('clicked', lambda _: self._see_book(book_id, data)) + box.append(see_button) + + update_button = Gtk.Button(label='Modifier') + update_button.connect('clicked', lambda _: self._update_book(book_id, data)) + box.append(update_button) + + delete_button = Gtk.Button(label='Supprimer') + delete_button.connect('clicked', lambda _: self._confirm_delete_book(book_id, data)) + box.append(delete_button) + + if self._ereader and os.path.exists(self._ereader): + paths = book_files.get(self._library, book_id) + if paths: + transfer_button = Gtk.Button(label='Transférer') + transfer_button.connect('clicked', lambda _: self._transfer_book(book_id, data, paths)) + box.append(transfer_button) + + popover.popup() + + def _see_book(self, book_id, data): + BookDetail(self._window, self._library, book_id, data).present() + + def _update_book(self, book_id, data): + book = {'id': book_id, 'data': data } + BookForm(self._window, self._resources, self._library, self._conn, data['progress'], self._on_book_updated, book).present() + + def _on_book_updated(self, book_id, data): + self._picture_cache.invalidate(f'{self._library}/{book_id}/cover-min.png') + self._books[book_id] = data + self.update_progress(data['progress']) # Note: this redraws everything, this is overkill in some cases + self._update_filter_progress(data['progress']) + self.select_child(self._flow_box_children[book_id]) + + def _confirm_delete_book(self, book_id, data): + BookDelete(self._window, self._library, book_id, data, lambda: self._delete_book(book_id, data)).present() + + def _delete_book(self, book_id, data): + del self._books[book_id] + db.delete_book(self._conn, book_id) + self._reset_view() + + def _transfer_book(self, book_id, data, paths): + BookTransfer(self._window, self._ereader, book_id, data, paths).present() + +def book_sort(b): + key, data = b + author = author_key(data) + date = data['date'] if 'date' in data else '' + return f'{author}{date}' + +def author_key(data): + match data['authors']: + case [author, *_]: + return author.split()[-1] + return '' |
