From 00776601aa0a0dd543e34e351d9a9716945a1ce3 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 21 Apr 2022 20:34:28 +0530 Subject: [PATCH] Fix #1967149 [[Enhancement] Give notice to user about Amazon cover bugs.](https://bugs.launchpad.net/calibre/+bug/1967149) --- src/calibre/devices/interface.py | 15 +++++++++++- src/calibre/devices/kindle/driver.py | 13 ++++++++++ src/calibre/gui2/device.py | 36 ++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/calibre/devices/interface.py b/src/calibre/devices/interface.py index f0c917d475..913c686f2e 100644 --- a/src/calibre/devices/interface.py +++ b/src/calibre/devices/interface.py @@ -8,6 +8,14 @@ from calibre.constants import iswindows from calibre.customize import Plugin +class OpenPopupMessage: + + def __init__(self, title='', message='', level='info'): + self.title = title + self.message = message + self.level = level + + class DevicePlugin(Plugin): """ Defines the interface that should be implemented by backends that @@ -69,7 +77,7 @@ class DevicePlugin(Plugin): # Encapsulates an annotation fetched from the device UserAnnotation = namedtuple('Annotation','type, value') - #: GUI displays this as a message if not None. Useful if opening can take a + #: GUI displays this as a message if not None in the status bar. Useful if opening can take a #: long time OPEN_FEEDBACK_MESSAGE = None @@ -126,6 +134,11 @@ class DevicePlugin(Plugin): return cls.__name__ return cls.name + @classmethod + def get_open_popup_message(self): + ' GUI displays this as a non-modal popup. Should be an instance of OpenPopupMessage ' + return None + # Device detection {{{ def test_bcd(self, bcdDevice, bcd): if bcd is None or len(bcd) == 0: diff --git a/src/calibre/devices/kindle/driver.py b/src/calibre/devices/kindle/driver.py index fe9e4f411f..65d69463e9 100644 --- a/src/calibre/devices/kindle/driver.py +++ b/src/calibre/devices/kindle/driver.py @@ -9,6 +9,7 @@ Device driver for Amazon's Kindle import datetime, os, re, json, hashlib, errno from calibre.constants import DEBUG, filesystem_encoding +from calibre.devices.interface import OpenPopupMessage from calibre.devices.kindle.bookmark import Bookmark from calibre.devices.usbms.driver import USBMS from calibre import strftime, fsync, prints @@ -95,6 +96,18 @@ class KINDLE(USBMS): ' Click "Show details" to see the list of books.' ) + @classmethod + def get_open_popup_message(cls): + from calibre.utils.localization import localize_website_link + return OpenPopupMessage(title=_('WARNING: E-book covers'), message=_( + 'Amazon has broken display of covers for books sent to the Kindle by USB cable. To workaround it,' + ' you have to:
  1. Send the books to the Kindle
  2. Disconnect the Kindle and wait for the covers to be deleted' + ' by Amazon
  3. Reconnect the Kindle and calibre will restore the covers.
After this the' + ' covers for those books should stay put. Click here for details.').format(localize_website_link( + 'https://manual.calibre-ebook.com/faq.html#covers-for-books-i' + '-send-to-my-e-ink-kindle-show-up-momentarily-and-then-are-replaced-by-a-generic-cover') + )) + def is_allowed_book_file(self, filename, path, prefix): lpath = os.path.join(path, filename).partition(self.normalize_path(prefix))[2].replace('\\', '/') return '.sdr/' not in lpath diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index b0f82747b6..ff9b92de0a 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -132,6 +132,37 @@ class BusyCursor: QApplication.restoreOverrideCursor() +def convert_open_popup(opm, skip_key): + class OPM(OpenFeedback): + + def __init__(self, opm): + super().__init__('placeholder') + self.opm = opm + self.skip_key = skip_key + + def custom_dialog(self, parent): + from calibre.gui2.dialogs.message_box import MessageBox + + class M(MessageBox): + def on_cd_finished(s): + gprefs.set(self.skip_key, not s.toggle_checkbox.isChecked()) + m = M({ + 'info': MessageBox.INFO, 'information': MessageBox.INFO, + 'warn': MessageBox.WARNING, 'warning': MessageBox.WARNING, + }[self.opm.level], self.opm.title, self.opm.message, + parent=parent + ) + tc = m.toggle_checkbox + tc.setVisible(True) + tc.setText(_('Show this message again')) + tc.setChecked(True) + m.resize_needed.emit() + m.finished.connect(m.on_cd_finished) + return m + + return OPM(opm) + + class DeviceManager(Thread): # {{{ def __init__(self, connected_slot, job_manager, open_feedback_slot, @@ -191,6 +222,11 @@ class DeviceManager(Thread): # {{{ for dev, detected_device in connected_devices: if dev.OPEN_FEEDBACK_MESSAGE is not None: self.open_feedback_slot(dev.OPEN_FEEDBACK_MESSAGE) + opm = dev.get_open_popup_message() + if opm is not None: + skip_key = f'do_not_show_device_open_popup_message_{dev.__class__.__name__}' + if not gprefs.get(skip_key, False): + self.open_feedback_msg(dev.get_gui_name(), convert_open_popup(opm, skip_key)) try: dev.reset(detected_device=detected_device, report_progress=self.report_progress)