diff --git a/src/pyj/book_list/home.pyj b/src/pyj/book_list/home.pyj index 91c3e79b00..d42003364d 100644 --- a/src/pyj/book_list/home.pyj +++ b/src/pyj/book_list/home.pyj @@ -5,9 +5,9 @@ from __python__ import bound_methods, hash_literals from elementmaker import E from gettext import gettext as _ -from ajax import ajax from book_list.cover_grid import BORDER_RADIUS from book_list.globals import get_db +from book_list.library_data import sync_library_books from book_list.router import open_book, update_window_title from book_list.top_bar import create_top_bar from book_list.ui import set_default_panel_handler, show_panel @@ -76,19 +76,6 @@ def sync_data_received(library_id, lrmap, load_type, xhr, ev): db.update_last_read_data_from_key(library_id, int(book_id), fmt, last_read, cfi) -def sync_library_books(library_id, to_sync): - url = f'book-get-last-read-position/{library_id}/' - which = v'[]' - lrmap = {} - for key, last_read in to_sync: - library_id, book_id, fmt = key - fmt = fmt.upper() - which.push(f'{book_id}-{fmt}') - lrmap[f'{book_id}:{fmt}'] = last_read - url += which.join('_') - ajax(url, sync_data_received.bind(None, library_id, lrmap)).send() - - def start_sync(to_sync): libraries = {} for key, last_read in to_sync: @@ -97,7 +84,7 @@ def start_sync(to_sync): libraries[library_id] = v'[]' libraries[library_id].push(v'[key, last_read]') for lid in libraries: - sync_library_books(lid, libraries[lid]) + sync_library_books(lid, libraries[lid], sync_data_received) def show_recent_stage2(books): diff --git a/src/pyj/book_list/library_data.pyj b/src/pyj/book_list/library_data.pyj index 3f20f4f22f..8b20d1734d 100644 --- a/src/pyj/book_list/library_data.pyj +++ b/src/pyj/book_list/library_data.pyj @@ -155,3 +155,16 @@ class ThumbnailCache: callback(img, load_type) thumbnail_cache = ThumbnailCache() + + +def sync_library_books(library_id, to_sync, callback): + url = f'book-get-last-read-position/{library_id}/' + which = v'[]' + lrmap = {} + for key, last_read in to_sync: + library_id, book_id, fmt = key + fmt = fmt.upper() + which.push(f'{book_id}-{fmt}') + lrmap[f'{book_id}:{fmt}'] = last_read + url += which.join('_') + ajax(url, callback.bind(None, library_id, lrmap)).send() diff --git a/src/pyj/read_book/overlay.pyj b/src/pyj/read_book/overlay.pyj index 032f6c16bd..c912cf50b1 100644 --- a/src/pyj/read_book/overlay.pyj +++ b/src/pyj/read_book/overlay.pyj @@ -1,18 +1,23 @@ # vim:fileencoding=utf-8 # License: GPL v3 Copyright: 2016, Kovid Goyal -from __python__ import hash_literals, bound_methods +from __python__ import bound_methods, hash_literals -from dom import clear, set_css, unique_id, svgicon, build_rule, add_extra_css from elementmaker import E -from book_list.theme import get_color -from book_list.globals import get_read_ui -from book_list.router import home -from widgets import create_spinner, create_button from gettext import gettext as _ -from read_book.toc import create_toc_panel + +from book_list.globals import get_read_ui +from book_list.library_data import sync_library_books +from book_list.router import home +from book_list.theme import get_color +from dom import add_extra_css, build_rule, clear, set_css, svgicon, unique_id +from modals import error_dialog from read_book.goto import create_goto_panel -from read_book.prefs.main import create_prefs_panel from read_book.prefs.font_size import create_font_size_panel +from read_book.prefs.main import create_prefs_panel +from read_book.toc import create_toc_panel +from session import get_device_uuid +from widgets import create_button, create_spinner + class LoadingMessage: # {{{ @@ -96,6 +101,63 @@ class DeleteBook: # {{{ self.overlay.hide_current_panel() # }}} +class SyncBook: # {{{ + + def __init__(self, overlay): + self.overlay = overlay + self.canceled = False + + def show(self, container): + self.container_id = container.getAttribute('id') + set_css(container, display='flex', justify_content='center', flex_direction='column', background_color=get_color('window-background')) + book = self.overlay.view.book + to_sync = v'[[book.key, new Date(0)]]' + sync_library_books(book.key[0], to_sync, self.sync_data_received) + container.appendChild( + E.div(style='margin:1ex 1em', + E.h2(_('Syncing to last read position')), + E.p(_('Downloading last read data from server, please wait...')), + E.div(style='display:flex; justify-content:flex-end', + create_button(_('Cancel'), action=self.cancel), + ) + ) + ) + + def on_container_click(self, evt): + pass # Dont allow panel to be closed by a click + + def cancel(self): + self.canceled = True + self.overlay.hide_current_panel() + + def sync_data_received(self, library_id, lrmap, load_type, xhr, ev): + if self.canceled: + return + self.overlay.hide() + if load_type is not 'load': + error_dialog(_('Failed to fetch sync data'), _('Failed to download last read data from server, click "Show details" for more information.'), xhr.error_html) + return + data = JSON.parse(xhr.responseText) + book = self.overlay.view.book + dev = get_device_uuid() + epoch = 0 + ans = None + for key in data: + book_id, fmt = key.partition(':')[::2] + if book_id is str(book.key[1]) and fmt.upper() is book.key[2].upper(): + last_read_positions = data[key] + for d in last_read_positions: + if d.device is not dev and d.epoch > epoch: + epoch = d.epoch + ans = d + if ans is not None: + cfi = ans.cfi + if cfi: + self.overlay.view.goto_bookpos(cfi) + + +# }}} + # MainOverlay {{{ MAIN_OVERLAY_TS_CLASS = 'read-book-main-overlay-top-section' @@ -161,7 +223,7 @@ class MainOverlay: ), E.ul( - ac(_('Sync'), _('Get last read position and annotations from the server'), None, 'cloud-download'), + ac(_('Sync'), _('Get last read position and annotations from the server'), self.overlay.sync_book, 'cloud-download'), ac(_('Delete'), _('Delete this book from the device'), self.overlay.delete_book, 'trash'), ac(_('Reload'), _('Reload this book from the server'), self.overlay.reload_book, 'refresh') ), @@ -337,6 +399,11 @@ class Overlay: self.panels = [DeleteBook(self, _('Are you sure you want to reload this book?'), 'refresh', _('Reload book'), True)] self.show_current_panel() + def sync_book(self): + self.hide_current_panel() + self.panels = [SyncBook(self)] + self.show_current_panel() + def show_toc(self): self.panels.push(TOCOverlay(self)) self.show_current_panel()