diff --git a/CHANGELOG.md b/CHANGELOG.md index c29dedace..1d1cb2254 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,34 @@ Version counting is based on semantic versioning (Major.Feature.Patch) +## 9.14.1 + +### YACReader +* Add setting to disable scroll animations and scroll smoothing, recommended if you are using a touch pad or if you find the mouse wheel behaviour laggy. +* Fix missing translation when opening YACReader from YACReaderLibrary. + +### YACReaderLibrary +* Fix "Set type" context menu the grid view for folders. +* Add a different versioning strategy for databases. DBs version will change only when the structure changes and not when YACReader version changes. +* Add support for updating libraries automatically with various settings to chose from. During automatic library updates most actions are disabled, you can stop an update by clicking on the busy indicator next to the Libraries title. +* Improve content reloading. Navigation and selection state is no longer reseted after content changes (e.g. library updates, tags edits, etc.) +* The app will try to move comics and folders to the trash bin when deletions are requested, if the file system used doesn't support trash bin the files will be removed permanetly. +* Add menu to choose what columns are displayed in the table comics view (do a right click on the header to show it). The view has new 3 new headers to choose from (Series, Volume and Story arc). +* Migrate `number` and `arcNumber` data types to `TEXT`. This only affects databases created before 9.13 and fixes problems with some formats of numbers (e.g. 1.10). +* Propage update date to all the parent folders. +* Fix crash when resorting comics in reading lists in table view view and the comic flow is hidden. +* Fix cover loading in QML views due to malformed URLs. +* Improve style of the webui status page. +* Fix type not being propagated to new files in a folder. +* Mark the current type in the context menu so the user can know the current type. + +### YACReaderLibraryServer +* Add `rescan-xml-info` command. +* Improved API to provide better integration with the clients (Android 1.4.0 and iOS 3.29.0). + +### All Apps +* New universal builds for macos. + ## 9.13.1 ### YACReaderLibrary diff --git a/README.md b/README.md index 9c561df05..2b43d64ba 100644 --- a/README.md +++ b/README.md @@ -52,9 +52,9 @@ If you are interested in contributing to the project the first step should be to Contributions are not restricted to coding; you can help the project by bringing new UI/UX ideas, designing new assets, writing manuals or tutorials, translating the apps, etc. If you are interested in DevOps, YACReader uses Azure Pipelines for CI/CD, any improvements in that area are welcome. Testing pre-releases is also really appreciated. #### Dev Setup -YACReader is developed in *c++/Qt*, so the first thing you need to do is to install a *C++* compiler or environment that supports at least *C++17* and *Qt*. In *Windows* I use *Visual Studio Community Edition 2019* as build system and in *macos* I use Xcode, but I do all the coding using *QtCreator*. The project is adding support to *Qt6* and it already compiles under it but it is not ready to ship, so you need to make sure that everything works in both *Qt5* and *Qt6*, you only need to install *Qt5* for now and *CI* will check that everything builds with *Qt6*. +YACReader is developed in *c++/Qt*, so the first thing you need to do is to install a *C++* compiler or environment that supports at least *C++17* and *Qt*. In *Windows* I use *Visual Studio Community Edition 2019* as build system and in *macos* I use Xcode, but I do all the coding using *QtCreator*. The project support *Qt5* and *Qt6* at the moment so you need to make sure that everything works in both *Qt5* and *Qt6*, you only need to install one flavor of *Qt* and *CI* will check that everything builds with both, I recommend using *Qt6*. -The repo includes binaries for the dependencies needed for *Windows* (MSVC compiler) and *macos* (clang) but you need to configure *7zip/p7zip* dependency manually, please take a look at *compressed_archive/README_7zip.txt*. +The repo includes binaries for the dependencies needed for *Windows* (MSVC compiler) and *macos* (clang) but you need to configure *7zip* dependency manually, please take a look at *compressed_archive/README_7zip.txt*. ##### Running and debugging YACReader needs to find its dependencies at runtime, make sure that *Qt* binaries are in your *PATH* and the third-party binaries are next to the executable. The best way to make sure you have all the third-party binaries in place is to check YACReader installation and copy the binaries in your output folder. diff --git a/YACReader/configuration.h b/YACReader/configuration.h index 3c4649ea1..03d9de46a 100644 --- a/YACReader/configuration.h +++ b/YACReader/configuration.h @@ -81,6 +81,8 @@ class Configuration : public QObject bool getDisableShowOnMouseOver() { return settings->value(DISABLE_MOUSE_OVER_GOTO_FLOW).toBool(); } bool getDoNotTurnPageOnScroll() { return settings->value(DO_NOT_TURN_PAGE_ON_SCROLL, false).toBool(); } bool getUseSingleScrollStepToTurnPage() { return settings->value(USE_SINGLE_SCROLL_STEP_TO_TURN_PAGE, false).toBool(); } + void setDisableScrollAnimation(bool b) { settings->setValue(DISABLE_SCROLL_ANIMATION, b); } + bool getDisableScrollAnimation() { return settings->value(DISABLE_SCROLL_ANIMATION, false).toBool(); } }; #endif diff --git a/YACReader/options_dialog.cpp b/YACReader/options_dialog.cpp index 1acb1a68a..5d006a6a9 100644 --- a/YACReader/options_dialog.cpp +++ b/YACReader/options_dialog.cpp @@ -71,9 +71,11 @@ OptionsDialog::OptionsDialog(QWidget *parent) auto scrollBox = new QGroupBox(tr("Scroll behaviour")); auto scrollLayout = new QVBoxLayout; + disableScrollAnimations = new QCheckBox(tr("Disable scroll animations and smooth scrolling")); doNotTurnPageOnScroll = new QCheckBox(tr("Do not turn page using scroll")); useSingleScrollStepToTurnPage = new QCheckBox(tr("Use single scroll step to turn page")); + scrollLayout->addWidget(disableScrollAnimations); scrollLayout->addWidget(doNotTurnPageOnScroll); scrollLayout->addWidget(useSingleScrollStepToTurnPage); @@ -242,6 +244,7 @@ void OptionsDialog::saveOptions() settings->setValue(DO_NOT_TURN_PAGE_ON_SCROLL, doNotTurnPageOnScroll->isChecked()); settings->setValue(USE_SINGLE_SCROLL_STEP_TO_TURN_PAGE, useSingleScrollStepToTurnPage->isChecked()); + settings->setValue(DISABLE_SCROLL_ANIMATION, disableScrollAnimations->isChecked()); YACReaderOptionsDialog::saveOptions(); } @@ -283,6 +286,7 @@ void OptionsDialog::restoreOptions(QSettings *settings) doNotTurnPageOnScroll->setChecked(settings->value(DO_NOT_TURN_PAGE_ON_SCROLL, false).toBool()); useSingleScrollStepToTurnPage->setChecked(settings->value(USE_SINGLE_SCROLL_STEP_TO_TURN_PAGE, false).toBool()); + disableScrollAnimations->setChecked(settings->value(DISABLE_SCROLL_ANIMATION, false).toBool()); } void OptionsDialog::updateColor(const QColor &color) diff --git a/YACReader/options_dialog.h b/YACReader/options_dialog.h index c59066306..db1e858c4 100644 --- a/YACReader/options_dialog.h +++ b/YACReader/options_dialog.h @@ -42,6 +42,7 @@ class OptionsDialog : public YACReaderOptionsDialog QCheckBox *doNotTurnPageOnScroll; QCheckBox *useSingleScrollStepToTurnPage; + QCheckBox *disableScrollAnimations; YACReaderSpinSliderWidget *brightnessS; diff --git a/YACReader/viewer.cpp b/YACReader/viewer.cpp index d8d56582b..58973bcf3 100644 --- a/YACReader/viewer.cpp +++ b/YACReader/viewer.cpp @@ -445,7 +445,7 @@ void Viewer::scrollDown() next(); } else { int currentPos = verticalScrollBar()->sliderPosition(); - verticalScroller->setDuration(250); + verticalScroller->setDuration(animationDuration()); verticalScroller->setStartValue(currentPos); verticalScroller->setEndValue(nextPos); @@ -461,7 +461,7 @@ void Viewer::scrollUp() prev(); } else { int currentPos = verticalScrollBar()->sliderPosition(); - verticalScroller->setDuration(250); + verticalScroller->setDuration(animationDuration()); verticalScroller->setStartValue(currentPos); verticalScroller->setEndValue(nextPos); @@ -604,16 +604,25 @@ void Viewer::scrollTo(int x, int y) { if (groupScroller->state() == QAbstractAnimation::Running) return; - horizontalScroller->setDuration(250); + horizontalScroller->setDuration(animationDuration()); horizontalScroller->setStartValue(horizontalScrollBar()->sliderPosition()); horizontalScroller->setEndValue(x); - verticalScroller->setDuration(250); + verticalScroller->setDuration(animationDuration()); verticalScroller->setStartValue(verticalScrollBar()->sliderPosition()); verticalScroller->setEndValue(y); groupScroller->start(); emit backgroundChanges(); } +int Viewer::animationDuration() const +{ + if (Configuration::getConfiguration().getDisableScrollAnimation()) { + return 0; + } else { + return 250; + } +} + void Viewer::moveView(Qt::Key directionKey) { QKeyEvent event(QEvent::KeyPress, directionKey, Qt::NoModifier); @@ -621,7 +630,7 @@ void Viewer::moveView(Qt::Key directionKey) emit backgroundChanges(); } -static void animateScroll(QPropertyAnimation &scroller, const QScrollBar &scrollBar, int delta) +void Viewer::animateScroll(QPropertyAnimation &scroller, const QScrollBar &scrollBar, int delta) { int deltaNotFinished = 0; if (scroller.state() == QAbstractAnimation::Running) { @@ -630,7 +639,7 @@ static void animateScroll(QPropertyAnimation &scroller, const QScrollBar &scroll } const int currentPos = scrollBar.sliderPosition(); - scroller.setDuration(250); + scroller.setDuration(animationDuration()); scroller.setStartValue(currentPos); scroller.setEndValue(currentPos - delta - deltaNotFinished); @@ -639,9 +648,9 @@ static void animateScroll(QPropertyAnimation &scroller, const QScrollBar &scroll void Viewer::wheelEvent(QWheelEvent *event) { - auto delta = event->angleDelta(); - if (render->hasLoadedComic()) { + auto delta = event->angleDelta(); + if (delta.x() != 0) { animateScroll(*horizontalScroller, *horizontalScrollBar(), delta.x()); return; diff --git a/YACReader/viewer.h b/YACReader/viewer.h index b6134d785..b17c266a1 100644 --- a/YACReader/viewer.h +++ b/YACReader/viewer.h @@ -162,7 +162,7 @@ public slots: bool restoreMagnifyingGlass; void setMagnifyingGlassShown(bool shown); - //! Manejadores de evento: + //! Event handlers: void resizeEvent(QResizeEvent *event) override; void wheelEvent(QWheelEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; @@ -179,6 +179,10 @@ public slots: void scrollZigzag(scrollDirection d1, scrollDirection d2, bool forward); void scrollTo(int x, int y); + // Zero when animations are disabled + int animationDuration() const; + void animateScroll(QPropertyAnimation &scroller, const QScrollBar &scrollBar, int delta); + public: Viewer(QWidget *parent = nullptr); ~Viewer(); diff --git a/YACReader/yacreader_de.ts b/YACReader/yacreader_de.ts index 05b174942..eb1981cf3 100644 --- a/YACReader/yacreader_de.ts +++ b/YACReader/yacreader_de.ts @@ -36,27 +36,27 @@ EditShortcutsDialog - + Restore defaults Standardwerte wiederherstellen - + To change a shortcut, double click in the key combination and type the new keys. Um ein Kürzel zu ändern, klicke doppelt auf die Tastenkombination und füge die neuen Tasten ein. - + Shortcuts settings Kürzel-Einstellungen - + Shortcut in use Genutzte Kürzel - + The shortcut "%1" is already assigned to other function Das Kürzel "%1" ist bereits für eine andere Funktion in Verwendung @@ -559,12 +559,12 @@ OptionsDialog - + Gamma Gamma - + Reset Zurücksetzen @@ -574,7 +574,7 @@ Meine Comics-Pfad - + Image adjustment Bildanpassung @@ -589,22 +589,22 @@ Auswählen - + Image options Bilderoptionen - + Contrast Kontrast - + Options Optionen - + Comics directory Comics-Verzeichnis @@ -614,27 +614,27 @@ Hintergrundfarbe - + Page Flow Page Flow - + General Allgemein - + Brightness Helligkeit - + Restart is needed Neustart erforderlich - + Quick Navigation Mode Schnellnavigations-Modus @@ -645,36 +645,41 @@ - Do not turn page using scroll + Disable scroll animations and smooth scrolling + Do not turn page using scroll + + + + Use single scroll step to turn page - + Disable mouse over activation Aktivierung durch Maus deaktivieren - + Fit options Anpassungsoptionen - + Enlarge images to fit width/height Bilder vergrößern, um sie Breite/Höhe anzupassen - + Double Page options Doppelseiten-Einstellungen - + Show covers as single page Cover als eine Seite darstellen @@ -766,31 +771,28 @@ ShortcutsDialog - Close - Schliessen + Schliessen - YACReader keyboard shortcuts - YACReader Tastaturkürzel + YACReader Tastaturkürzel - Keyboard Shortcuts - Tastaturkürzel + Tastaturkürzel Viewer - + Page not available! Seite nicht verfügbar! - + Press 'O' to open comic. 'O' drücken, um Comic zu öffnen. @@ -800,7 +802,7 @@ Fehler beim Öffnen des Comics - + Cover! Titelseite! @@ -820,12 +822,12 @@ Nicht gefunden - + Last page! Letzte Seite! - + Loading...please wait! Ladevorgang... Bitte warten! @@ -833,480 +835,490 @@ YACReader::MainWindowViewer - + &Open &Öffnen - + Open a comic Comic öffnen - + New instance Neuer Fall - + Open Folder Ordner öffnen - + Open image folder Bilder-Ordner öffnen - + Open latest comic Neuesten Comic öffnen - + Open the latest comic opened in the previous reading session Öffne den neuesten Comic deiner letzten Sitzung - + Clear Löschen - + Clear open recent list Lösche Liste zuletzt geöffneter Elemente - + Save Speichern - - + + Save current page Aktuelle Seite speichern - + Previous Comic Voheriger Comic - - - + + + Open previous comic Vorherigen Comic öffnen - + Next Comic Nächster Comic - - - + + + Open next comic Nächsten Comic öffnen - + &Previous &Vorherige - - - + + + Go to previous page Zur vorherigen Seite gehen - + &Next &Nächstes - - - + + + Go to next page Zur nächsten Seite gehen - + Fit Height Höhe anpassen - + Fit image to height Bild an Höhe anpassen - + Fit Width Breite anpassen - + Fit image to width Bildbreite anpassen - + Show full size Vollansicht anzeigen - + Fit to page An Seite anpassen - + Reset zoom Zoom zurücksetzen - + Show zoom slider Zoomleiste anzeigen - + Zoom+ Zoom+ - + Zoom- Zoom- - + Rotate image to the left Bild nach links drehen - + Rotate image to the right Bild nach rechts drehen - + Double page mode Doppelseiten-Modus - + Switch to double page mode Zum Doppelseiten-Modus wechseln - + Double page manga mode Doppelseiten-Manga-Modus - + Reverse reading order in double page mode Umgekehrte Lesereihenfolge im Doppelseiten-Modus - + Go To Gehe zu - + Go to page ... Gehe zu Seite ... - + Options Optionen - + YACReader options YACReader Optionen - - + + Help Hilfe - + Help, About YACReader Hilfe, über YACReader - + Magnifying glass Vergößerungsglas - + Switch Magnifying glass Vergrößerungsglas wechseln - + Set bookmark Lesezeichen setzen - + Set a bookmark on the current page Lesezeichen auf dieser Seite setzen - + Show bookmarks Lesezeichen anzeigen - + Show the bookmarks of the current comic Lesezeichen für diesen Comic anzeigen - + Show keyboard shortcuts Tastenkürzel anzeigen - + Show Info Info anzeigen - + Close - + Show Dictionary Wörterbuch anzeigen - + Show go to flow "Go to Flow" anzeigen - + Edit shortcuts - + &File &Datei - - + + Open recent Kürzlich geöffnet - + File Datei - + Edit Ändern - + View Anzeigen - + Go Los - + Window Fenster - - + + Open Comic Comic öffnen - - + + Comic files Comic-Dateien - + Open folder Ordner öffnen - + page_%1.jpg Seite_%1.jpg - + Image files (*.jpg) Bildateien (*.jpg) - + Comics Comics - + Toggle fullscreen mode Vollbild-Modus umschalten - + Hide/show toolbar Symbolleiste anzeigen/verstecken - + General Allgemein - + Size up magnifying glass Vergrößerungsglas vergrößern - + Size down magnifying glass Vergrößerungsglas verkleinern - + Zoom in magnifying glass Vergrößerungsglas reinzoomen - + Zoom out magnifying glass Vergrößerungsglas rauszoomen - + Magnifiying glass Vergrößerungsglas - + Toggle between fit to width and fit to height Zwischen Anpassung an Seite und Höhe wechseln - + Page adjustement Seitenanpassung - + Autoscroll down Automatisches Runterscrollen - + Autoscroll up Automatisches Raufscrollen - + Autoscroll forward, horizontal first Automatisches Vorwärtsscrollen, horizontal zuerst - + Autoscroll backward, horizontal first Automatisches Zurückscrollen, horizontal zuerst - + Autoscroll forward, vertical first Automatisches Vorwärtsscrollen, vertikal zuerst - + Autoscroll backward, vertical first Automatisches Zurückscrollen, vertikal zuerst - + Move down Nach unten - + Move up Nach oben - + Move left Nach links - + Move right Nach rechts - + Go to the first page Zur ersten Seite gehen - + Go to the last page Zur letzten Seite gehen - + + Offset double page to the left + + + + + Offset double page to the right + + + + Reading Lesend - + There is a new version available Neue Version verfügbar - + Do you want to download the new version? Möchten Sie die neue Version herunterladen? - + Remind me in 14 days In 14 Tagen erneut erinnern - + Not now Nicht jetzt @@ -1314,7 +1326,7 @@ YACReader::WhatsNewDialog - + Close Schließen diff --git a/YACReader/yacreader_en.ts b/YACReader/yacreader_en.ts index bac4cb38f..e63a36180 100644 --- a/YACReader/yacreader_en.ts +++ b/YACReader/yacreader_en.ts @@ -36,27 +36,27 @@ EditShortcutsDialog - + Restore defaults - + To change a shortcut, double click in the key combination and type the new keys. - + Shortcuts settings - + Shortcut in use - + The shortcut "%1" is already assigned to other function @@ -200,22 +200,22 @@ - + Quick Navigation Mode - + Disable mouse over activation - + Restart is needed - + Brightness @@ -226,76 +226,81 @@ - Do not turn page using scroll + Disable scroll animations and smooth scrolling + Do not turn page using scroll + + + + Use single scroll step to turn page - + Contrast - + Gamma - + Reset - + Image options - + Fit options - + Enlarge images to fit width/height - + Double Page options - + Show covers as single page - + General - + Page Flow - + Image adjustment - + Options - + Comics directory @@ -384,29 +389,11 @@ - - ShortcutsDialog - - - YACReader keyboard shortcuts - - - - - Close - - - - - Keyboard Shortcuts - - - Viewer - + Press 'O' to open comic. @@ -431,22 +418,22 @@ - + Loading...please wait! - + Page not available! - + Cover! - + Last page! @@ -454,480 +441,490 @@ YACReader::MainWindowViewer - + &Open - + Open a comic - + New instance - + Open Folder - + Open image folder - + Open latest comic - + Open the latest comic opened in the previous reading session - + Clear - + Clear open recent list - + Save - - + + Save current page - + Previous Comic - - - + + + Open previous comic - + Next Comic - - - + + + Open next comic - + &Previous - - - + + + Go to previous page - + &Next - - - + + + Go to next page - + Fit Height - + Fit image to height - + Fit Width - + Fit image to width - + Show full size - + Fit to page - + Reset zoom - + Show zoom slider - + Zoom+ - + Zoom- - + Rotate image to the left - + Rotate image to the right - + Double page mode - + Switch to double page mode - + Double page manga mode - + Reverse reading order in double page mode - + Go To - + Go to page ... - + Options - + YACReader options - - + + Help - + Help, About YACReader - + Magnifying glass - + Switch Magnifying glass - + Set bookmark - + Set a bookmark on the current page - + Show bookmarks - + Show the bookmarks of the current comic - + Show keyboard shortcuts - + Show Info - + Close - + Show Dictionary - + Show go to flow - + Edit shortcuts - + &File - - + + Open recent - + File - + Edit - + View - + Go - + Window - - + + Open Comic - - + + Comic files - + Open folder - + page_%1.jpg - + Image files (*.jpg) - + Comics - + Toggle fullscreen mode - + Hide/show toolbar - + General - + Size up magnifying glass - + Size down magnifying glass - + Zoom in magnifying glass - + Zoom out magnifying glass - + Magnifiying glass - + Toggle between fit to width and fit to height - + Page adjustement - + Autoscroll down - + Autoscroll up - + Autoscroll forward, horizontal first - + Autoscroll backward, horizontal first - + Autoscroll forward, vertical first - + Autoscroll backward, vertical first - + Move down - + Move up - + Move left - + Move right - + Go to the first page - + Go to the last page - + + Offset double page to the left + + + + + Offset double page to the right + + + + Reading - + There is a new version available - + Do you want to download the new version? - + Remind me in 14 days - + Not now @@ -935,7 +932,7 @@ YACReader::WhatsNewDialog - + Close diff --git a/YACReader/yacreader_es.ts b/YACReader/yacreader_es.ts index 070bc5bf7..8182aae39 100644 --- a/YACReader/yacreader_es.ts +++ b/YACReader/yacreader_es.ts @@ -6,7 +6,7 @@ None - + Ninguno @@ -36,29 +36,29 @@ EditShortcutsDialog - + Restore defaults - + Restaurar los valores predeterminados - + To change a shortcut, double click in the key combination and type the new keys. - + Para cambiar un atajo, haz doble clic en la combinación de teclas y escribe las nuevas teclas. - + Shortcuts settings - + Configuración de accesos directos - + Shortcut in use - + Accesos directos en uso - + The shortcut "%1" is already assigned to other function - + El acceso directo "%1" ya está asignado a otra función @@ -131,7 +131,7 @@ System info - + Información de sistema @@ -395,12 +395,12 @@ OptionsDialog - + Gamma Gamma - + Reset Reset @@ -410,7 +410,7 @@ Ruta a mis cómics - + Image adjustment Ajustes de imagen @@ -425,22 +425,22 @@ Elegir - + Image options Opciones de imagen - + Contrast Contraste - + Options Opciones - + Comics directory Directorio de cómics @@ -450,69 +450,74 @@ Color de fondo - + Page Flow Page Flow - + General General - + Brightness Brillo - + Restart is needed Es necesario reiniciar - + Quick Navigation Mode - + Modo de navegación rápida Scroll behaviour - + Comportamiento del scroll - Do not turn page using scroll - + Disable scroll animations and smooth scrolling + Desactivar animaciones de desplazamiento y desplazamiento suave + Do not turn page using scroll + No cambiar de página usando el scroll + + + Use single scroll step to turn page - + Usar un solo paso de desplazamiento para cambiar de página - + Disable mouse over activation - + Desactivar activación al pasar el ratón - + Fit options - + Opciones de ajuste - + Enlarge images to fit width/height - + Ampliar imágenes para ajustarse al ancho/alto - + Double Page options - + Opciones de doble página - + Show covers as single page - + Mostrar portadas como página única @@ -602,31 +607,28 @@ ShortcutsDialog - Close - Cerrar + Cerrar - YACReader keyboard shortcuts - Atajos de teclado de YACReader + Atajos de teclado de YACReader - Keyboard Shortcuts - Atajos de teclado + Atajos de teclado Viewer - + Page not available! ¡Página no disponible! - + Press 'O' to open comic. Pulsa 'O' para abrir un fichero. @@ -636,7 +638,7 @@ Error abriendo cómic - + Cover! ¡Portada! @@ -656,12 +658,12 @@ No encontrado - + Last page! ¡Última página! - + Loading...please wait! Cargando...espere, por favor! @@ -669,490 +671,500 @@ YACReader::MainWindowViewer - + &Open - &Abrir + &Abrir - + Open a comic - Abrir cómic + Abrir cómic - + New instance - + Nueva instancia - + Open Folder - Abrir carpeta + Abrir carpeta - + Open image folder - Abrir carpeta de imágenes + Abrir carpeta de imágenes - + Open latest comic - + Abrir el cómic más reciente - + Open the latest comic opened in the previous reading session - + Abrir el cómic más reciente abierto en la sesión de lectura anterior - + Clear - + Limpiar - + Clear open recent list - + Limpiar lista de abiertos recientemente - + Save - Guardar + Guardar - - + + Save current page - Guardar la página actual + Guardar la página actual - + Previous Comic - Cómic anterior + Cómic anterior - - - + + + Open previous comic - Abrir cómic anterior + Abrir cómic anterior - + Next Comic - Siguiente Cómic + Siguiente Cómic - - - + + + Open next comic - Abrir siguiente cómic + Abrir siguiente cómic - + &Previous - A&nterior + A&nterior - - - + + + Go to previous page - Ir a la página anterior + Ir a la página anterior - + &Next - Siguie&nte + Siguie&nte - - - + + + Go to next page - Ir a la página siguiente + Ir a la página siguiente - + Fit Height - Ajustar altura + Ajustar altura - + Fit image to height - Ajustar página a lo alto + Ajustar página a lo alto - + Fit Width - Ajustar anchura + Ajustar anchura - + Fit image to width - Ajustar página a lo ancho + Ajustar página a lo ancho - + Show full size - Mostrar a tamaño original + Mostrar a tamaño original - + Fit to page - + Ajustar a página - + Reset zoom - + Restablecer zoom - + Show zoom slider - + Mostrar control deslizante de zoom - + Zoom+ - + Zoom+ - + Zoom- - + Zoom- - + Rotate image to the left - Rotar imagen a la izquierda + Rotar imagen a la izquierda - + Rotate image to the right - Rotar imagen a la derecha + Rotar imagen a la derecha - + Double page mode - Modo a doble página + Modo a doble página - + Switch to double page mode - Cambiar a modo de doble página + Cambiar a modo de doble página - + Double page manga mode - + Modo de manga de página doble - + Reverse reading order in double page mode - + Invertir el orden de lectura en modo de página doble - + Go To - Ir a + Ir a - + Go to page ... - Ir a página... + Ir a página... - + Options - Opciones + Opciones - + YACReader options - Opciones de YACReader + Opciones de YACReader - - + + Help - Ayuda + Ayuda - + Help, About YACReader - Ayuda, Sobre YACReader + Ayuda, Sobre YACReader - + Magnifying glass - Lupa + Lupa - + Switch Magnifying glass - Lupa On/Off + Lupa On/Off - + Set bookmark - Añadir marcador + Añadir marcador - + Set a bookmark on the current page - Añadir un marcador en la página actual + Añadir un marcador en la página actual - + Show bookmarks - Mostrar marcadores + Mostrar marcadores - + Show the bookmarks of the current comic - Mostrar los marcadores del cómic actual + Mostrar los marcadores del cómic actual - + Show keyboard shortcuts - Mostrar atajos de teclado + Mostrar atajos de teclado - + Show Info - Mostrar información + Mostrar información - + Close - Cerrar + Cerrar - + Show Dictionary - Mostrar diccionario + Mostrar diccionario - + Show go to flow - Mostrar flow ir a + Mostrar flow ir a - + Edit shortcuts - + Editar accesos directos - + &File - &Archivo + &Archivo - - + + Open recent - + Abrir reciente - + File - Archivo + Archivo - + Edit - + Editar - + View - + Ver - + Go - + Ir - + Window - + Ventana - - + + Open Comic - Abrir cómic + Abrir cómic - - + + Comic files - Archivos de cómic + Archivos de cómic - + Open folder - Abrir carpeta + Abrir carpeta - + page_%1.jpg - página_%1.jpg + página_%1.jpg - + Image files (*.jpg) - Archivos de imagen (*.jpg) + Archivos de imagen (*.jpg) - + Comics - + Cómics - + Toggle fullscreen mode - + Alternar modo de pantalla completa - + Hide/show toolbar - + Ocultar/mostrar barra de herramientas - + General - General + General - + Size up magnifying glass - + Aumentar tamaño de la lupa - + Size down magnifying glass - + Disminuir tamaño de lupa - + Zoom in magnifying glass - + Incrementar el aumento de la lupa - + Zoom out magnifying glass - + Reducir el aumento de la lupa - + Magnifiying glass - + Lupa - + Toggle between fit to width and fit to height - + Alternar entre ajuste al ancho y ajuste al alto - + Page adjustement - + Ajuste de página - + Autoscroll down - + Desplazamiento automático hacia abajo - + Autoscroll up - + Desplazamiento automático hacia arriba - + Autoscroll forward, horizontal first - + Desplazamiento automático hacia adelante, primero horizontal - + Autoscroll backward, horizontal first - + Desplazamiento automático hacia atrás, primero horizontal - + Autoscroll forward, vertical first - + Desplazamiento automático hacia adelante, primero vertical - + Autoscroll backward, vertical first - + Desplazamiento automático hacia atrás, primero vertical - + Move down - + Mover abajo - + Move up - + Mover arriba - + Move left - + Mover a la izquierda - + Move right - + Mover a la derecha - + Go to the first page - + Ir a la primera página - + Go to the last page - + Ir a la última página + + + + Offset double page to the left + Mover una página a la izquierda + + + + Offset double page to the right + Mover una página a la derecha - + Reading - + Leyendo - + There is a new version available - Hay una nueva versión disponible + Hay una nueva versión disponible - + Do you want to download the new version? - ¿Desea descargar la nueva versión? + ¿Desea descargar la nueva versión? - + Remind me in 14 days - Recordar en 14 días + Recordar en 14 días - + Not now - Ahora no + Ahora no YACReader::WhatsNewDialog - + Close - Cerrar + Cerrar @@ -1248,7 +1260,7 @@ Z offset - Desplazamiento en Z + Desplazamiento en Z @@ -1346,12 +1358,12 @@ Edit shortcuts - + Editar accesos directos Shortcuts - + Accesos directos diff --git a/YACReader/yacreader_fr.ts b/YACReader/yacreader_fr.ts index 076497970..5a3c04cf3 100644 --- a/YACReader/yacreader_fr.ts +++ b/YACReader/yacreader_fr.ts @@ -36,27 +36,27 @@ EditShortcutsDialog - + Shortcut in use Raccourci en cours d'utilisation - + Restore defaults Réinitialiser - + Shortcuts settings Paramètres de raccourcis - + The shortcut "%1" is already assigned to other function Le raccourci "%1" est déjà affecté à une autre fonction - + To change a shortcut, double click in the key combination and type the new keys. Pour modifier un raccourci, double-cliquez sur la combinaison de touches et tapez les nouvelles clés. @@ -551,12 +551,12 @@ OptionsDialog - + Gamma Gamma - + Reset Remise à zéro @@ -566,7 +566,7 @@ Chemin de mes bandes dessinées - + Image adjustment Ajustement de l'image @@ -581,27 +581,27 @@ Choisir - + Image options Option de l'image - + Contrast Contraste - + Options Options - + Comics directory Répertoire des bandes dessinées - + Quick Navigation Mode Mode navigation rapide @@ -617,56 +617,61 @@ - Do not turn page using scroll + Disable scroll animations and smooth scrolling + Do not turn page using scroll + + + + Use single scroll step to turn page - + Disable mouse over activation Désactiver la souris sur l'activation - + Page Flow Flux des pages - + General Général - + Brightness Luminosité - + Restart is needed Redémarrage nécessaire - + Fit options - + Enlarge images to fit width/height - + Double Page options - + Show covers as single page @@ -758,31 +763,28 @@ ShortcutsDialog - Close - Fermer + Fermer - YACReader keyboard shortcuts - Raccourcis clavier de YACReader + Raccourcis clavier de YACReader - Keyboard Shortcuts - Raccourcis clavier + Raccourcis clavier Viewer - + Page not available! Page non disponible ! - + Press 'O' to open comic. Appuyez sur "O" pour ouvrir une bande dessinée. @@ -792,7 +794,7 @@ Erreur d'ouverture de la bande dessinée - + Cover! Couverture! @@ -812,12 +814,12 @@ Introuvable - + Last page! Dernière page! - + Loading...please wait! Chargement... Patientez @@ -825,480 +827,490 @@ YACReader::MainWindowViewer - + &Open &Ouvrir - + Open a comic Ouvrir une bande dessinée - + New instance - + Open Folder Ouvrir un dossier - + Open image folder Ouvrir un dossier d'images - + Open latest comic Ouvrir la dernière bande dessinée - + Open the latest comic opened in the previous reading session Ouvrir la dernière bande dessinée ouverte lors de la session de lecture précédente - + Clear - + Clear open recent list Vider la liste d'ouverture récente - + Save Sauvegarder - - + + Save current page Sauvegarder la page actuelle - + Previous Comic Bande dessinée précédente - - - + + + Open previous comic Ouvrir la bande dessiné précédente - + Next Comic Bande dessinée suivante - - - + + + Open next comic Ouvrir la bande dessinée suivante - + &Previous &Précédent - - - + + + Go to previous page Aller à la page précédente - + &Next &Suivant - - - + + + Go to next page Aller à la page suivante - + Fit Height Ajuster la hauteur - + Fit image to height Ajuster l'image à la hauteur - + Fit Width Ajuster la largeur - + Fit image to width Ajuster l'image à la largeur - + Show full size Plein écran - + Fit to page Ajuster à la page - + Reset zoom Réinitialiser le zoom - + Show zoom slider Afficher le curseur de zoom - + Zoom+ Zoom+ - + Zoom- Zoom- - + Rotate image to the left Rotation à gauche - + Rotate image to the right Rotation à droite - + Double page mode Mode double page - + Switch to double page mode Passer en mode double page - + Double page manga mode Mode manga en double page - + Reverse reading order in double page mode Ordre de lecture inversée en mode double page - + Go To Aller à - + Go to page ... Aller à la page ... - + Options Options - + YACReader options Options de YACReader - - + + Help Aide - + Help, About YACReader Aide, à propos de YACReader - + Magnifying glass Loupe - + Switch Magnifying glass Utiliser la loupe - + Set bookmark Placer un marque-page - + Set a bookmark on the current page Placer un marque-page sur la page actuelle - + Show bookmarks Voir les marque-pages - + Show the bookmarks of the current comic Voir les marque-pages de cette bande dessinée - + Show keyboard shortcuts Voir les raccourcis - + Show Info Voir les infos - + Close Fermer - + Show Dictionary Dictionnaire - + Show go to flow Afficher le flux - + Edit shortcuts Modifier les raccourcis - + &File &Fichier - - + + Open recent Ouvrir récent - + File Fichier - + Edit Editer - + View Vue - + Go Aller - + Window Fenêtre - - + + Open Comic Ouvrir la bande dessinée - - + + Comic files Bande dessinée - + Open folder Ouvirir le dossier - + page_%1.jpg page_%1.jpg - + Image files (*.jpg) Image(*.jpg) - + Comics Bandes dessinées - + Toggle fullscreen mode Basculer en mode plein écran - + Hide/show toolbar Masquer / afficher la barre d'outils - + General Général - + Size up magnifying glass Augmenter la taille de la loupe - + Size down magnifying glass Réduire la taille de la loupe - + Zoom in magnifying glass Zoomer - + Zoom out magnifying glass Dézoomer - + Magnifiying glass Loupe - + Toggle between fit to width and fit to height Basculer entre adapter à la largeur et adapter à la hauteur - + Page adjustement Ajustement de la page - + Autoscroll down Défilement automatique vers le bas - + Autoscroll up Défilement automatique vers le haut - + Autoscroll forward, horizontal first Défilement automatique en avant, horizontal - + Autoscroll backward, horizontal first Défilement automatique en arrière horizontal - + Autoscroll forward, vertical first Défilement automatique en avant, vertical - + Autoscroll backward, vertical first Défilement automatique en arrière, verticak - + Move down Descendre - + Move up Monter - + Move left Déplacer à gauche - + Move right Déplacer à droite - + Go to the first page Aller à la première page - + Go to the last page Aller à la dernière page - + + Offset double page to the left + + + + + Offset double page to the right + + + + Reading Lecture - + There is a new version available Une nouvelle version est disponible - + Do you want to download the new version? Voulez-vous télécharger la nouvelle version? - + Remind me in 14 days Rappelez-moi dans 14 jours - + Not now Pas maintenant @@ -1306,7 +1318,7 @@ YACReader::WhatsNewDialog - + Close Fermer diff --git a/YACReader/yacreader_it.ts b/YACReader/yacreader_it.ts index e5f023e8b..35f39c043 100644 --- a/YACReader/yacreader_it.ts +++ b/YACReader/yacreader_it.ts @@ -36,27 +36,27 @@ EditShortcutsDialog - + Shortcut in use Scorciatoia in uso - + Restore defaults Resetta al default - + Shortcuts settings impostazione scorciatoie - + The shortcut "%1" is already assigned to other function La scorciatoia "%1" è già assegnata ad un'altra funzione - + To change a shortcut, double click in the key combination and type the new keys. Per cambiare una scorciatoia doppio click sulla combinazione tasti e digita la nuova combinazione. @@ -555,12 +555,12 @@ OptionsDialog - + Gamma Gamma - + Reset Reset @@ -570,7 +570,7 @@ Percorso dei miei fumetti - + Image adjustment Correzioni immagine @@ -585,27 +585,27 @@ Scegli - + Image options Opzione immagine - + Contrast Contrasto - + Options Opzioni - + Comics directory Cartella Fumetti - + Quick Navigation Mode Modo navigazione rapida @@ -621,56 +621,61 @@ - Do not turn page using scroll + Disable scroll animations and smooth scrolling + Do not turn page using scroll + + + + Use single scroll step to turn page - + Disable mouse over activation Disabilita il mouse all'attivazione - + Page Flow Flusso pagine - + General Generale - + Brightness Luminosità - + Restart is needed Riavvio Necessario - + Fit options - + Enlarge images to fit width/height - + Double Page options - + Show covers as single page @@ -762,31 +767,28 @@ ShortcutsDialog - Close - Chiudi + Chiudi - YACReader keyboard shortcuts - Scorciatoie da tastiera di YACReader + Scorciatoie da tastiera di YACReader - Keyboard Shortcuts - Scorciatoia da tastiera + Scorciatoia da tastiera Viewer - + Page not available! Pagina non disponibile! - + Press 'O' to open comic. Premi "O" per aprire il fumettto. @@ -796,7 +798,7 @@ Errore nell'apertura - + Cover! Copertina! @@ -816,12 +818,12 @@ Non trovato - + Last page! Ultima pagina! - + Loading...please wait! In caricamento...Attendi! @@ -829,480 +831,490 @@ YACReader::MainWindowViewer - + &Open &Apri - + Open a comic Apri un Fumetto - + New instance - + Open Folder Apri una cartella - + Open image folder Apri la crettal immagini - + Open latest comic Apri l'ultimo fumetto - + Open the latest comic opened in the previous reading session Apri l'ultimo fumetto aperto nella sessione precedente - + Clear Cancella - + Clear open recent list Svuota la lista degli aperti - + Save Salva - - + + Save current page Salva la pagina corrente - + Previous Comic Fumetto precendente - - - + + + Open previous comic Apri il fumetto precendente - + Next Comic Prossimo fumetto - - - + + + Open next comic Apri il prossimo fumetto - + &Previous &Precedente - - - + + + Go to previous page Vai alla pagina precedente - + &Next &Prossimo - - - + + + Go to next page Vai alla prossima Pagina - + Fit Height Adatta altezza - + Fit image to height Adatta immagine all'altezza - + Fit Width Adatta Larghezza - + Fit image to width Adatta immagine in larghezza - + Show full size Mostra dimesioni reali - + Fit to page Adatta alla pagina - + Reset zoom Resetta Zoom - + Show zoom slider Mostra cursore di zoom - + Zoom+ Zoom+ - + Zoom- Zoom- - + Rotate image to the left Ruota immagine a sinistra - + Rotate image to the right Ruota immagine a destra - + Double page mode Modalita doppia pagina - + Switch to double page mode Passa alla modalità doppia pagina - + Double page manga mode Modalità doppia pagina Manga - + Reverse reading order in double page mode Ordine lettura inverso in modo doppia pagina - + Go To Vai a - + Go to page ... Vai a Pagina ... - + Options Opzioni - + YACReader options Opzioni YACReader - - + + Help Aiuto - + Help, About YACReader Aiuto, crediti YACReader - + Magnifying glass Lente ingrandimento - + Switch Magnifying glass Passa a lente ingrandimento - + Set bookmark Imposta Segnalibro - + Set a bookmark on the current page Imposta segnalibro a pagina corrente - + Show bookmarks Mostra segnalibro - + Show the bookmarks of the current comic Mostra il segnalibro del fumetto corrente - + Show keyboard shortcuts Mostra scorciatoie da tastiera - + Show Info Mostra info - + Close Chiudi - + Show Dictionary Mostra dizionario - + Show go to flow Mostra vai all'elenco - + Edit shortcuts - + &File &File - - + + Open recent Apri i recenti - + File File - + Edit Edit - + View Mostra - + Go Vai - + Window Finestra - - + + Open Comic Apri Fumetto - - + + Comic files File Fumetto - + Open folder Apri cartella - + page_%1.jpg Pagina_%1.jpg - + Image files (*.jpg) File immagine (*.jpg) - + Comics Fumetto - + Toggle fullscreen mode Attiva/Disattiva schermo intero - + Hide/show toolbar Mostra/Nascondi Barra strumenti - + General Generale - + Size up magnifying glass Ingrandisci lente ingrandimento - + Size down magnifying glass Riduci lente ingrandimento - + Zoom in magnifying glass Ingrandisci in lente di ingrandimento - + Zoom out magnifying glass Riduci in lente di ingrandimento - + Magnifiying glass Lente ingrandimento - + Toggle between fit to width and fit to height Passa tra adatta in larghezza ad altezza - + Page adjustement Correzioni di pagna - + Autoscroll down Autoscorri Giù - + Autoscroll up Autoscorri Sù - + Autoscroll forward, horizontal first Autoscorri avanti, priorità Orizzontale - + Autoscroll backward, horizontal first Autoscorri indietro, priorità Orizzontale - + Autoscroll forward, vertical first Autoscorri avanti, priorità Verticale - + Autoscroll backward, vertical first Autoscorri indietro, priorità Verticale - + Move down Muovi Giù - + Move up Muovi Sù - + Move left Muovi Sinistra - + Move right Muovi Destra - + Go to the first page Vai alla pagina iniziale - + Go to the last page Vai all'ultima pagina - + + Offset double page to the left + + + + + Offset double page to the right + + + + Reading Leggi - + There is a new version available Nuova versione disponibile - + Do you want to download the new version? Vuoi scaricare la nuova versione? - + Remind me in 14 days Ricordamelo in 14 giorni - + Not now Non ora @@ -1310,7 +1322,7 @@ YACReader::WhatsNewDialog - + Close Chiudi diff --git a/YACReader/yacreader_nl.ts b/YACReader/yacreader_nl.ts index eac581b03..20dfb999e 100644 --- a/YACReader/yacreader_nl.ts +++ b/YACReader/yacreader_nl.ts @@ -36,27 +36,27 @@ EditShortcutsDialog - + Restore defaults - + To change a shortcut, double click in the key combination and type the new keys. - + Shortcuts settings - + Shortcut in use - + The shortcut "%1" is already assigned to other function @@ -379,12 +379,12 @@ OptionsDialog - + Gamma Gamma - + Reset Standaardwaarden terugzetten @@ -394,7 +394,7 @@ Pad naar mijn strips - + Image adjustment Beeldaanpassing @@ -409,22 +409,22 @@ Kies - + Image options Afbeelding opties - + Contrast Contrast - + Options Opties - + Comics directory Strips map @@ -434,27 +434,27 @@ Achtergrondkleur - + Page Flow Omslagbrowser - + General Algemeen - + Brightness Helderheid - + Restart is needed Herstart is nodig - + Quick Navigation Mode @@ -465,36 +465,41 @@ - Do not turn page using scroll + Disable scroll animations and smooth scrolling + Do not turn page using scroll + + + + Use single scroll step to turn page - + Disable mouse over activation - + Fit options - + Enlarge images to fit width/height - + Double Page options - + Show covers as single page @@ -586,31 +591,28 @@ ShortcutsDialog - Close - Sluiten + Sluiten - YACReader keyboard shortcuts - YACReader sneltoetsen + YACReader sneltoetsen - Keyboard Shortcuts - Sneltoetsen + Sneltoetsen Viewer - + Press 'O' to open comic. Druk 'O' om een strip te openen. - + Cover! Omslag! @@ -625,12 +627,12 @@ Niet gevonden - + Last page! Laatste pagina! - + Loading...please wait! Inladen...even wachten! @@ -645,7 +647,7 @@ - + Page not available! @@ -653,480 +655,490 @@ YACReader::MainWindowViewer - + &Open &Open - + Open a comic Open een strip - + New instance - + Open Folder Map Openen - + Open image folder Open afbeeldings map - + Open latest comic - + Open the latest comic opened in the previous reading session - + Clear - + Clear open recent list - + Save Bewaar - - + + Save current page Bewaren huidige pagina - + Previous Comic Vorige Strip - - - + + + Open previous comic Open de vorige strip - + Next Comic Volgende Strip - - - + + + Open next comic Open volgende strip - + &Previous &Vorige - - - + + + Go to previous page Ga naar de vorige pagina - + &Next &Volgende - - - + + + Go to next page Ga naar de volgende pagina - + Fit Height - + Fit image to height Afbeelding aanpassen aan hoogte - + Fit Width Vensterbreedte aanpassen - + Fit image to width Afbeelding aanpassen aan breedte - + Show full size Volledig Scherm - + Fit to page - + Reset zoom - + Show zoom slider - + Zoom+ - + Zoom- - + Rotate image to the left Links omdraaien - + Rotate image to the right Rechts omdraaien - + Double page mode Dubbele bladzijde modus - + Switch to double page mode Naar dubbele bladzijde modus - + Double page manga mode - + Reverse reading order in double page mode - + Go To Ga Naar - + Go to page ... Ga naar bladzijde ... - + Options Opties - + YACReader options YACReader opties - - + + Help Help - + Help, About YACReader Help, Over YACReader - + Magnifying glass Vergrootglas - + Switch Magnifying glass Overschakelen naar Vergrootglas - + Set bookmark Bladwijzer instellen - + Set a bookmark on the current page Een bladwijzer toevoegen aan de huidige pagina - + Show bookmarks Bladwijzers weergeven - + Show the bookmarks of the current comic Toon de bladwijzers van de huidige strip - + Show keyboard shortcuts Toon de sneltoetsen - + Show Info Info tonen - + Close Sluiten - + Show Dictionary Woordenlijst weergeven - + Show go to flow Toon ga naar de Omslagbrowser - + Edit shortcuts - + &File &Bestand - - + + Open recent - + File - + Edit - + View - + Go - + Window - - + + Open Comic Open een Strip - - + + Comic files Strip bestanden - + Open folder Open een Map - + page_%1.jpg pagina_%1.jpg - + Image files (*.jpg) Afbeelding bestanden (*.jpg) - + Comics - + Toggle fullscreen mode - + Hide/show toolbar - + General Algemeen - + Size up magnifying glass - + Size down magnifying glass - + Zoom in magnifying glass - + Zoom out magnifying glass - + Magnifiying glass - + Toggle between fit to width and fit to height - + Page adjustement - + Autoscroll down - + Autoscroll up - + Autoscroll forward, horizontal first - + Autoscroll backward, horizontal first - + Autoscroll forward, vertical first - + Autoscroll backward, vertical first - + Move down - + Move up - + Move left - + Move right - + Go to the first page - + Go to the last page - + + Offset double page to the left + + + + + Offset double page to the right + + + + Reading - + There is a new version available Er is een nieuwe versie beschikbaar - + Do you want to download the new version? Wilt u de nieuwe versie downloaden? - + Remind me in 14 days - + Not now @@ -1134,7 +1146,7 @@ YACReader::WhatsNewDialog - + Close Sluiten diff --git a/YACReader/yacreader_pt.ts b/YACReader/yacreader_pt.ts index 922feae31..f225a5204 100644 --- a/YACReader/yacreader_pt.ts +++ b/YACReader/yacreader_pt.ts @@ -36,27 +36,27 @@ EditShortcutsDialog - + Restore defaults - + To change a shortcut, double click in the key combination and type the new keys. - + Shortcuts settings - + Shortcut in use - + The shortcut "%1" is already assigned to other function @@ -349,17 +349,17 @@ Tamanho do "Ir para cheia" - + Options Opções - + Comics directory Diretório de quadrinhos - + Restart is needed Reiniciar é necessário @@ -380,81 +380,86 @@ - Do not turn page using scroll + Disable scroll animations and smooth scrolling + Do not turn page using scroll + + + + Use single scroll step to turn page - + Quick Navigation Mode - + Disable mouse over activation - + Brightness - + Contrast - + Gamma - + Reset - + Image options - + Fit options - + Enlarge images to fit width/height - + Double Page options - + Show covers as single page - + General - + Page Flow - + Image adjustment @@ -546,31 +551,24 @@ ShortcutsDialog - Close - Fechar + Fechar - YACReader keyboard shortcuts - Teclas de atalhos do YACReader - - - - Keyboard Shortcuts - + Teclas de atalhos do YACReader Viewer - + Press 'O' to open comic. Pressione 'O' para abrir um quadrinho. - + Loading...please wait! Carregando... por favor, aguarde! @@ -595,17 +593,17 @@ - + Page not available! - + Cover! - + Last page! @@ -613,480 +611,490 @@ YACReader::MainWindowViewer - + &Open &Abrir - + Open a comic Abrir um quadrinho - + New instance - + Open Folder Abrir Pasta - + Open image folder - + Open latest comic - + Open the latest comic opened in the previous reading session - + Clear - + Clear open recent list - + Save Salvar - - + + Save current page Salvar página atual - + Previous Comic Quadrinho Anterior - - - + + + Open previous comic Abrir quadrinho anterior - + Next Comic Próximo Quadrinho - - - + + + Open next comic Abrir próximo quadrinho - + &Previous A&nterior - - - + + + Go to previous page Ir para a página anterior - + &Next &Próxima - - - + + + Go to next page Ir para a próxima página - + Fit Height - + Fit image to height - + Fit Width Ajustar à Largura - + Fit image to width - + Show full size - + Fit to page - + Reset zoom - + Show zoom slider - + Zoom+ - + Zoom- - + Rotate image to the left Girar imagem à esquerda - + Rotate image to the right Girar imagem à direita - + Double page mode Modo dupla página - + Switch to double page mode Alternar para o modo dupla página - + Double page manga mode - + Reverse reading order in double page mode - + Go To Ir Para - + Go to page ... Ir para a página... - + Options Opções - + YACReader options Opções do YACReader - - + + Help Ajuda - + Help, About YACReader Ajuda, Sobre o YACReader - + Magnifying glass Lupa - + Switch Magnifying glass Alternar Lupa - + Set bookmark Definir marcador - + Set a bookmark on the current page Definir um marcador na página atual - + Show bookmarks Mostrar marcadores - + Show the bookmarks of the current comic Mostrar os marcadores do quadrinho atual - + Show keyboard shortcuts Mostrar teclas de atalhos - + Show Info Mostrar Informações - + Close Fechar - + Show Dictionary - + Show go to flow - + Edit shortcuts - + &File &Arquivo - - + + Open recent - + File - + Edit - + View - + Go - + Window - - + + Open Comic Abrir Quadrinho - - + + Comic files - + Open folder Abrir pasta - + page_%1.jpg - + Image files (*.jpg) Arquivos de imagem (*.jpg) - + Comics - + Toggle fullscreen mode - + Hide/show toolbar - + General - + Size up magnifying glass - + Size down magnifying glass - + Zoom in magnifying glass - + Zoom out magnifying glass - + Magnifiying glass - + Toggle between fit to width and fit to height - + Page adjustement - + Autoscroll down - + Autoscroll up - + Autoscroll forward, horizontal first - + Autoscroll backward, horizontal first - + Autoscroll forward, vertical first - + Autoscroll backward, vertical first - + Move down - + Move up - + Move left - + Move right - + Go to the first page - + Go to the last page - + + Offset double page to the left + + + + + Offset double page to the right + + + + Reading - + There is a new version available Há uma nova versão disponível - + Do you want to download the new version? Você deseja baixar a nova versão? - + Remind me in 14 days - + Not now @@ -1094,7 +1102,7 @@ YACReader::WhatsNewDialog - + Close Fechar diff --git a/YACReader/yacreader_ru.ts b/YACReader/yacreader_ru.ts index 999125471..6577af0bc 100644 --- a/YACReader/yacreader_ru.ts +++ b/YACReader/yacreader_ru.ts @@ -36,27 +36,27 @@ EditShortcutsDialog - + Shortcut in use Горячая клавиша уже занята - + Restore defaults Восстановить значения по умолчанию - + Shortcuts settings Горячие клавиши - + The shortcut "%1" is already assigned to other function Сочетание клавиш "%1" уже назначено для другой функции - + To change a shortcut, double click in the key combination and type the new keys. Чтобы изменить горячую клавишу дважды щелкните по выбранной комбинации клавиш и введите новые сочетания клавиш. @@ -555,12 +555,12 @@ OptionsDialog - + Gamma Гамма - + Reset Вернуть к первоначальным значениям @@ -570,7 +570,7 @@ Папка комиксов - + Image adjustment Настройка изображения @@ -585,27 +585,27 @@ Выбрать - + Image options Настройки изображения - + Contrast Контраст - + Options Настройки - + Comics directory Папка комиксов - + Quick Navigation Mode Ползунок для быстрой навигации по страницам @@ -621,56 +621,61 @@ - Do not turn page using scroll + Disable scroll animations and smooth scrolling + Do not turn page using scroll + + + + Use single scroll step to turn page - + Disable mouse over activation Отключить активацию потока при наведении мыши - + Page Flow Поток Страниц - + General Общие - + Brightness Яркость - + Restart is needed - + Fit options - + Enlarge images to fit width/height - + Double Page options - + Show covers as single page @@ -762,31 +767,28 @@ ShortcutsDialog - Close - Закрыть + Закрыть - YACReader keyboard shortcuts - Клавиатурные комбинации YACReader + Клавиатурные комбинации YACReader - Keyboard Shortcuts - Клавиатурные комбинации + Клавиатурные комбинации Viewer - + Page not available! Страница недоступна! - + Press 'O' to open comic. Нажмите "O" чтобы открыть комикс. @@ -796,7 +798,7 @@ Ошибка открытия комикса - + Cover! Начало! @@ -816,12 +818,12 @@ Не найдено - + Last page! Конец! - + Loading...please wait! Загрузка... Пожалуйста подождите! @@ -829,480 +831,490 @@ YACReader::MainWindowViewer - + &Open &Открыть - + Open a comic Открыть комикс - + New instance - + Open Folder Открыть папку - + Open image folder Открыть папку с изображениями - + Open latest comic Открыть последний комикс - + Open the latest comic opened in the previous reading session Открыть комикс открытый в предыдущем сеансе чтения - + Clear Очистить - + Clear open recent list Очистить список недавно открытых файлов - + Save Сохранить - - + + Save current page Сохранить текущию страницу - + Previous Comic Предыдущий комикс - - - + + + Open previous comic Открыть предыдуший комикс - + Next Comic Следующий комикс - - - + + + Open next comic Открыть следующий комикс - + &Previous &Предыдущий - - - + + + Go to previous page Перейти к предыдущей странице - + &Next &Следующий - - - + + + Go to next page Перейти к следующей странице - + Fit Height Подогнать по высоте - + Fit image to height Подогнать по высоте - + Fit Width Подогнать по ширине - + Fit image to width Подогнать по ширине - + Show full size Показать в полном размере - + Fit to page Подогнать под размер страницы - + Reset zoom Сбросить масштаб - + Show zoom slider Показать ползунок масштабирования - + Zoom+ Увеличить масштаб - + Zoom- Уменьшить масштаб - + Rotate image to the left Повернуть изображение против часовой стрелки - + Rotate image to the right Повернуть изображение по часовой стрелке - + Double page mode Двухстраничный режим - + Switch to double page mode Двухстраничный режим - + Double page manga mode Двухстраничный режим манги - + Reverse reading order in double page mode Двухстраничный режим манги - + Go To Перейти к странице... - + Go to page ... Перейти к странице... - + Options Настройки - + YACReader options Настройки - - + + Help Справка - + Help, About YACReader Справка - + Magnifying glass Увеличительное стекло - + Switch Magnifying glass Увеличительное стекло - + Set bookmark Установить закладку - + Set a bookmark on the current page Установить закладку на текущей странице - + Show bookmarks Показать закладки - + Show the bookmarks of the current comic Показать закладки в текущем комиксе - + Show keyboard shortcuts Показать горячие клавиши - + Show Info Показать/скрыть номер страницы и текущее время - + Close Закрыть - + Show Dictionary Переводчик YACreader - + Show go to flow Показать поток страниц - + Edit shortcuts Редактировать горячие клавиши - + &File &Отображать панель инструментов - - + + Open recent Открыть недавние - + File Файл - + Edit Редактировать - + View Посмотреть - + Go Перейти - + Window Окно - - + + Open Comic Открыть комикс - - + + Comic files Файлы комикса - + Open folder Открыть папку - + page_%1.jpg страница_%1.jpg - + Image files (*.jpg) Файлы изображений (*.jpg) - + Comics Комикс - + Toggle fullscreen mode Полноэкранный режим включить/выключить - + Hide/show toolbar Показать/скрыть панель инструментов - + General Общие - + Size up magnifying glass Увеличение размера окошка увеличительного стекла - + Size down magnifying glass Уменьшение размера окошка увеличительного стекла - + Zoom in magnifying glass Увеличить - + Zoom out magnifying glass Уменьшить - + Magnifiying glass Увеличительное стекло - + Toggle between fit to width and fit to height Переключение режима подгонки страницы по ширине/высоте - + Page adjustement Настройка страницы - + Autoscroll down Автопрокрутка вниз - + Autoscroll up Автопрокрутка вверх - + Autoscroll forward, horizontal first Автопрокрутка вперед, горизонтальная - + Autoscroll backward, horizontal first Автопрокрутка назад, горизонтальная - + Autoscroll forward, vertical first Автопрокрутка вперед, вертикальная - + Autoscroll backward, vertical first Автопрокрутка назад, вертикальная - + Move down Переместить вниз - + Move up Переместить вверх - + Move left Переместить влево - + Move right Переместить вправо - + Go to the first page Перейти к первой странице - + Go to the last page Перейти к последней странице - + + Offset double page to the left + + + + + Offset double page to the right + + + + Reading Чтение - + There is a new version available Доступна новая версия - + Do you want to download the new version? Хотите загрузить новую версию ? - + Remind me in 14 days Напомнить через 14 дней - + Not now Не сейчас @@ -1310,7 +1322,7 @@ YACReader::WhatsNewDialog - + Close Закрыть diff --git a/YACReader/yacreader_tr.ts b/YACReader/yacreader_tr.ts index eaa98fea7..d35cd6238 100644 --- a/YACReader/yacreader_tr.ts +++ b/YACReader/yacreader_tr.ts @@ -36,27 +36,27 @@ EditShortcutsDialog - + Restore defaults Varsayılarları geri yükle - + To change a shortcut, double click in the key combination and type the new keys. Bir kısayolu değiştirmek için tuş kombinasyonuna çift tıklayın ve yeni tuşları girin. - + Shortcuts settings Kısayol oyarları - + Shortcut in use Kısayol kullanımda - + The shortcut "%1" is already assigned to other function "%1" kısayolu bir başka işleve zaten atanmış @@ -559,12 +559,12 @@ OptionsDialog - + Gamma Gama - + Reset Yeniden başlat @@ -574,7 +574,7 @@ Çizgi Romanlarım - + Image adjustment Resim ayarları @@ -589,22 +589,22 @@ Seç - + Image options Sayfa ayarları - + Contrast Kontrast - + Options Ayarlar - + Comics directory Çizgi roman konumu @@ -614,27 +614,27 @@ Arka plan rengi - + Page Flow Sayfa akışı - + General Genel - + Brightness Parlaklık - + Restart is needed Yeniden başlatılmalı - + Quick Navigation Mode Hızlı Gezinti Kipi @@ -645,36 +645,41 @@ - Do not turn page using scroll + Disable scroll animations and smooth scrolling + Do not turn page using scroll + + + + Use single scroll step to turn page - + Disable mouse over activation Etkinleştirme üzerinde fareyi devre dışı bırak - + Fit options Sığdırma seçenekleri - + Enlarge images to fit width/height Genişliğe/yüksekliği sığmaları için resimleri genişlet - + Double Page options Çift Sayfa seçenekleri - + Show covers as single page Kapakları tek sayfa olarak göster @@ -766,31 +771,28 @@ ShortcutsDialog - Close - Kapat + Kapat - YACReader keyboard shortcuts - YACReader klavye kısayolları + YACReader klavye kısayolları - Keyboard Shortcuts - Klavye Kısayolları + Klavye Kısayolları Viewer - + Press 'O' to open comic. 'O'ya basarak aç. - + Cover! Kapak! @@ -805,12 +807,12 @@ Bulunamadı - + Last page! Son sayfa! - + Loading...please wait! Yükleniyor... lütfen bekleyin! @@ -825,7 +827,7 @@ CRC Hatası - + Page not available! Sayfa bulunamadı! @@ -833,480 +835,490 @@ YACReader::MainWindowViewer - + &Open &Aç - + Open a comic Çizgi romanı aç - + New instance Yeni örnek - + Open Folder Dosyayı Aç - + Open image folder Resim dosyasınıaç - + Open latest comic En son çizgi romanı aç - + Open the latest comic opened in the previous reading session Önceki okuma oturumunda açılan en son çizgi romanı aç - + Clear Temizle - + Clear open recent list Son açılanlar listesini temizle - + Save Kaydet - - + + Save current page Geçerli sayfayı kaydet - + Previous Comic Önce ki çizgi roman - - - + + + Open previous comic Önceki çizgi romanı aç - + Next Comic Sırada ki çizgi roman - - - + + + Open next comic Sıradaki çizgi romanı aç - + &Previous &Geri - - - + + + Go to previous page Önceki sayfaya dön - + &Next &İleri - - - + + + Go to next page Sonra ki sayfaya geç - + Fit Height Yüksekliğe Sığdır - + Fit image to height Uygun yüksekliğe getir - + Fit Width Uygun Genişlik - + Fit image to width Görüntüyü sığdır - + Show full size Tam erken - + Fit to page Sayfaya sığdır - + Reset zoom Yakınlaştırmayı sıfırla - + Show zoom slider Yakınlaştırma çubuğunu göster - + Zoom+ Yakınlaştır - + Zoom- Uzaklaştır - + Rotate image to the left Sayfayı sola yatır - + Rotate image to the right Sayfayı sağa yator - + Double page mode Çift sayfa modu - + Switch to double page mode Çift sayfa moduna geç - + Double page manga mode Çift sayfa manga kipi - + Reverse reading order in double page mode Çift sayfa kipinde ters okuma sırası - + Go To Git - + Go to page ... Sayfata git... - + Options Ayarlar - + YACReader options YACReader ayarları - - + + Help Yardım - + Help, About YACReader YACReader hakkında yardım ve bilgi - + Magnifying glass Büyüteç - + Switch Magnifying glass Büyüteç - + Set bookmark Yer imi yap - + Set a bookmark on the current page Sayfayı yer imi olarak ayarla - + Show bookmarks Yer imlerini göster - + Show the bookmarks of the current comic Bu çizgi romanın yer imlerini göster - + Show keyboard shortcuts Klavye kısayollarını göster - + Show Info Bilgiyi göster - + Close Kapat - + Show Dictionary Sözlüğü göster - + Show go to flow Akışı göster - + Edit shortcuts Kısayolları düzenle - + &File &Dosya - - + + Open recent Son dosyaları aç - + File Dosya - + Edit Düzen - + View Görünüm - + Go Git - + Window Pencere - - + + Open Comic Çizgi Romanı Aç - - + + Comic files Çizgi Roman Dosyaları - + Open folder Dosyayı aç - + page_%1.jpg sayfa_%1.jpg - + Image files (*.jpg) Resim dosyaları (*.jpg) - + Comics Çizgi Roman - + Toggle fullscreen mode Tam ekran kipini aç/kapat - + Hide/show toolbar Araç çubuğunu göster/gizle - + General Genel - + Size up magnifying glass Büyüteci büyüt - + Size down magnifying glass Büyüteci küçült - + Zoom in magnifying glass Büyüteci yakınlaştır - + Zoom out magnifying glass Büyüteci uzaklaştır - + Magnifiying glass Büyüteç - + Toggle between fit to width and fit to height Genişliğe sığdır ile yüksekliğe sığdır arasında geçiş yap - + Page adjustement Sayfa ayarı - + Autoscroll down Otomatik aşağı kaydır - + Autoscroll up Otomatik yukarı kaydır - + Autoscroll forward, horizontal first Otomatik ileri kaydır, önce yatay - + Autoscroll backward, horizontal first Otomatik geri kaydır, önce yatay - + Autoscroll forward, vertical first Otomatik ileri kaydır, önce dikey - + Autoscroll backward, vertical first Otomatik geri kaydır, önce dikey - + Move down Aşağı git - + Move up Yukarı git - + Move left Sola git - + Move right Sağa git - + Go to the first page İlk sayfaya git - + Go to the last page En son sayfaya git - + + Offset double page to the left + + + + + Offset double page to the right + + + + Reading Okuma - + There is a new version available Yeni versiyon mevcut - + Do you want to download the new version? Yeni versiyonu indirmek ister misin ? - + Remind me in 14 days 14 gün içinde hatırlat - + Not now Şimdi değil @@ -1314,7 +1326,7 @@ YACReader::WhatsNewDialog - + Close Kapat diff --git a/YACReader/yacreader_zh_CN.ts b/YACReader/yacreader_zh_CN.ts index 90e192012..27994e97d 100644 --- a/YACReader/yacreader_zh_CN.ts +++ b/YACReader/yacreader_zh_CN.ts @@ -11,67 +11,62 @@ BookmarksDialog - - - Lastest Page - 尾页 - Close 关闭 + + + + Loading... + 载入中... + Click on any image to go to the bookmark 点击任意图片以跳转至相应书签位置 - - - Loading... - 载入中... + + Lastest Page + 尾页 EditShortcutsDialog - - Restore defaults - 恢复默认 + + Shortcut in use + 快捷键被占用 - - To change a shortcut, double click in the key combination and type the new keys. - 更改快捷键: 双击按键组合并输入新的映射. + + Restore defaults + 恢复默认 - + Shortcuts settings 快捷键设置 - - Shortcut in use - 快捷键被占用 - - - + The shortcut "%1" is already assigned to other function 快捷键 "%1" 已被映射至其他功能 + + + To change a shortcut, double click in the key combination and type the new keys. + 更改快捷键: 双击按键组合并输入新的映射. + FileComic - - CRC error on page (%1): some of the pages will not be displayed correctly - 第 %1 页 CRC 校验失败: 部分页面将无法正确显示 - - - - Unknown error opening the file - 打开文件时出现未知错误 + + Format not supported + 不支持的文件格式 @@ -79,27 +74,27 @@ 未找到 7z - - Format not supported - 不支持的文件格式 + + Unknown error opening the file + 打开文件时出现未知错误 + + + + CRC error on page (%1): some of the pages will not be displayed correctly + 第 %1 页 CRC 校验失败: 部分页面将无法正确显示 GoToDialog - - - Page : - 页码 : - Go To 跳转 - - Cancel - 取消 + + Go to... + 跳转至 ... @@ -108,9 +103,14 @@ 总页数: - - Go to... - 跳转至 ... + + Cancel + 取消 + + + + Page : + 页码 : @@ -123,16 +123,16 @@ HelpAboutDialog - - - About - 关于 - Help 帮助 + + + About + 关于 + System info @@ -142,30 +142,25 @@ LogWindow - - Log window - 日志窗口 - - - - &Pause - 中止(&P) + + &Copy + 复制(&C) &Save 保存(&S) + + + &Pause + 中止(&P) + C&lear 清空(&l) - - - &Copy - 复制(&C) - Level: @@ -176,141 +171,161 @@ &Auto scroll 自动滚动(&A) + + + Log window + 日志窗口 + OptionsDialog - - "Go to flow" size - 页面流尺寸 + + Gamma + Gamma值 - - My comics path - 我的漫画路径 + + Reset + 重置 - - Background color - 背景颜色 + + Enlarge images to fit width/height + 放大图片以适应宽度/高度 - - Choose - 选择 + + Disable scroll animations and smooth scrolling + 禁用滚动动画和平滑滚动 - - Quick Navigation Mode - 快速导航模式 + + Use single scroll step to turn page + 使用单滚动步骤翻页 - - Disable mouse over activation - 禁用鼠标激活 + + My comics path + 我的漫画路径 - - Restart is needed - 需要重启 + + Image adjustment + 图像调整 - - Brightness - 亮度 + + "Go to flow" size + 页面流尺寸 - - Scroll behaviour - 滚动效果 + + Choose + 选择 - + + Show covers as single page + 显示封面为单页 + + + Do not turn page using scroll 滚动时不翻页 - - Use single scroll step to turn page - 使用单滚动步骤翻页 + + Fit options + 适应项 - - Contrast - 对比度 + + Image options + 图片选项 - - Gamma - Gamma值 + + Contrast + 对比度 - - Reset - 重置 + + Options + 选项 - - Image options - 图片选项 + + Comics directory + 漫画目录 - - Fit options - 适应项 + + Quick Navigation Mode + 快速导航模式 - - Enlarge images to fit width/height - 放大图片以适应宽度/高度 + + Background color + 背景颜色 - + Double Page options 双页选项 - - Show covers as single page - 显示封面为单页 + + Scroll behaviour + 滚动效果 - - General - 常规 + + Disable mouse over activation + 禁用鼠标激活 - + Page Flow 页面流 - Image adjustment - 图像调整 + General + 常规 - - Options - 选项 + + Brightness + 亮度 - - Comics directory - 漫画目录 + + Restart is needed + 需要重启 QObject - - 7z lib not found - 未找到 7z 库文件 + + Info + 信息 - - unable to load 7z lib from ./utils - 无法从 ./utils 载入 7z 库文件 + + Debug + 除错 + + + + Fatal + 严重错误 + + + + Error + 错误 @@ -318,30 +333,20 @@ 追踪 - - Debug - 除错 + + 7z lib not found + 未找到 7z 库文件 - - Info - 信息 + + unable to load 7z lib from ./utils + 无法从 ./utils 载入 7z 库文件 Warning 警告 - - - Error - 错误 - - - - Fatal - 严重错误 - QsLogging::LogWindowModel @@ -368,16 +373,16 @@ &Pause 中止(&P) - - - &Resume - 恢复(&R) - Save log 保存日志 + + + &Resume + 恢复(&R) + Log file (*.log) @@ -385,577 +390,574 @@ - ShortcutsDialog - - - YACReader keyboard shortcuts - YACReader 键盘快捷键 - - - - Close - 关闭 - + Viewer - - Keyboard Shortcuts - 键盘快捷键 + + Page not available! + 页面不可用! - - - Viewer - + Press 'O' to open comic. 按下 'O' 以打开漫画. - - - Not found - 未找到 - - - - Comic not found - 未找到漫画 - Error opening comic 打开漫画时发生错误 + + + Cover! + 封面! + CRC Error CRC 校验失败 - - Loading...please wait! - 载入中... 请稍候! - - - - Page not available! - 页面不可用! + + Comic not found + 未找到漫画 - - Cover! - 封面! + + Not found + 未找到 - + Last page! 尾页! + + + Loading...please wait! + 载入中... 请稍候! + YACReader::MainWindowViewer - - &Open - 打开(&O) + + Go + 转到 - - Open a comic - 打开漫画 + + Edit + 编辑 - - New instance - 新建实例 + + File + 文件 - - Open Folder - 打开文件夹 + + + Help + 帮助 - - Open image folder - 打开图片文件夹 + + Save + 保存 - - Open latest comic - 打开最近的漫画 + + View + 查看 - - Open the latest comic opened in the previous reading session - 打开最近阅读漫画 + + &File + 文件(&F) - - Clear - 清空 + + &Next + 下一页(&N) - - Clear open recent list - 清空最近访问列表 + + &Open + 打开(&O) - - Save - 保存 + + Clear + 清空 - - - Save current page - 保存当前页面 + + Close + 关闭 - - Previous Comic - 上一个漫画 + + + Open Comic + 打开漫画 - - - - Open previous comic - 打开上一个漫画 + + Go To + 跳转 - - Next Comic - 下一个漫画 + + Zoom+ + 放大 - - - - Open next comic - 打开下一个漫画 + + Zoom- + 缩小 - - &Previous - 上一页(&P) + + Open image folder + 打开图片文件夹 - - - - Go to previous page - 转至上一页 + + Size down magnifying glass + 减小放大镜尺寸 - - &Next - 下一页(&N) + + Zoom out magnifying glass + 减小缩放级别 - - - - Go to next page - 转至下一页 + + New instance + 新建实例 - - Fit Height - 适应高度 + + Open latest comic + 打开最近的漫画 - - Fit image to height - 缩放图片以适应高度 + + Autoscroll up + 向上自动滚动 - - Fit Width - 适合宽度 + + Set bookmark + 设置书签 - - Fit image to width - 缩放图片以适应宽度 + + page_%1.jpg + page_%1.jpg - - Show full size - 显示全尺寸 + + Autoscroll forward, vertical first + 向前自动滚动,垂直优先 - - Fit to page - 适应页面 + + Switch to double page mode + 切换至双页模式 - - Reset zoom - 重置缩放 + + + Save current page + 保存当前页面 - - Show zoom slider - 显示缩放滑块 + + Size up magnifying glass + 增大放大镜尺寸 - - Zoom+ - 放大 + + Double page mode + 双页模式 - - Zoom- - 缩小 + + Move up + 向上移动 - - Rotate image to the left - 向左旋转图片 + + Switch Magnifying glass + 切换放大镜 - - Rotate image to the right - 向右旋转图片 + + Open Folder + 打开文件夹 - - Double page mode - 双页模式 + + Comics + 漫画 - - Switch to double page mode - 切换至双页模式 + + Offset double page to the right + 双页向右偏移 - - Double page manga mode - 双页漫画模式 + + Fit Height + 适应高度 - - Reverse reading order in double page mode - 双页模式 (逆序阅读) + + Autoscroll backward, vertical first + 向后自动滚动,垂直优先 - - Go To - 跳转 + + + Comic files + 漫画文件 - - Go to page ... - 跳转至页面 ... + + Not now + 现在不 - - Options - 选项 + + Go to the first page + 转到第一页 - - YACReader options - YACReader 选项 + + + + Go to previous page + 转至上一页 - - - Help - 帮助 + + Window + 窗口 - - Help, About YACReader - 帮助, 关于 YACReader + + Open the latest comic opened in the previous reading session + 打开最近阅读漫画 - - Magnifying glass - 放大镜 + + Open a comic + 打开漫画 - - Switch Magnifying glass - 切换放大镜 + + Image files (*.jpg) + 图像文件 (*.jpg) - - Set bookmark - 设置书签 + + Next Comic + 下一个漫画 - - Set a bookmark on the current page - 在当前页面设置书签 + + Fit Width + 适合宽度 - - Show bookmarks - 显示书签 + + Options + 选项 - - Show the bookmarks of the current comic - 显示当前漫画的书签 + + Show Info + 显示信息 - - Show keyboard shortcuts - 显示键盘快捷键 + + Open folder + 打开文件夹 - - Show Info - 显示信息 + + Go to page ... + 跳转至页面 ... - - Close - 关闭 + + Magnifiying glass + 放大镜 - - Show Dictionary - 显示字典 + + Fit image to width + 缩放图片以适应宽度 - - Show go to flow - 显示页面流 + + Toggle fullscreen mode + 切换全屏模式 - - Edit shortcuts - 编辑快捷键 + + Toggle between fit to width and fit to height + 切换显示为"适应宽度"或"适应高度" - - &File - 文件(&F) + + Move right + 向右移动 + + + + Zoom in magnifying glass + 增大缩放级别 - - + + Open recent 最近打开的文件 - - File - 文件 + + Offset double page to the left + 双页向左偏移 - - Edit - 编辑 + + Reading + 阅读 - - View - 查看 + + &Previous + 上一页(&P) - - Go - 转到 + + Autoscroll forward, horizontal first + 向前自动滚动,水平优先 - - Window - 窗口 + + + + Go to next page + 转至下一页 - - - Open Comic - 打开漫画 + + Show keyboard shortcuts + 显示键盘快捷键 - - - Comic files - 漫画文件 + + Double page manga mode + 双页漫画模式 - - Open folder - 打开文件夹 + + There is a new version available + 有新版本可用 - - page_%1.jpg - page_%1.jpg + + Autoscroll down + 向下自动滚动 - - Image files (*.jpg) - 图像文件 (*.jpg) + + + + Open next comic + 打开下一个漫画 - - Comics - 漫画 + + Remind me in 14 days + 14天后提醒我 - - Toggle fullscreen mode - 切换全屏模式 + + Fit to page + 适应页面 - - Hide/show toolbar - 隐藏/显示 工具栏 + + Show bookmarks + 显示书签 - - General - 常规 + + + + Open previous comic + 打开上一个漫画 - - Size up magnifying glass - 增大放大镜尺寸 + + Rotate image to the left + 向左旋转图片 - - Size down magnifying glass - 减小放大镜尺寸 + + Fit image to height + 缩放图片以适应高度 - - Zoom in magnifying glass - 增大缩放级别 + + Reset zoom + 重置缩放 - - Zoom out magnifying glass - 减小缩放级别 + + Show the bookmarks of the current comic + 显示当前漫画的书签 - - Magnifiying glass - 放大镜 + + Show Dictionary + 显示字典 - - Toggle between fit to width and fit to height - 切换显示为"适应宽度"或"适应高度" + + Move down + 向下移动 - - Page adjustement - 页面调整 + + Move left + 向左移动 - - Autoscroll down - 向下自动滚动 + + Reverse reading order in double page mode + 双页模式 (逆序阅读) - - Autoscroll up - 向上自动滚动 + + YACReader options + YACReader 选项 - - Autoscroll forward, horizontal first - 向前自动滚动,水平优先 + + Clear open recent list + 清空最近访问列表 - - Autoscroll backward, horizontal first - 向后自动滚动,水平优先 + + Help, About YACReader + 帮助, 关于 YACReader - - Autoscroll forward, vertical first - 向前自动滚动,垂直优先 + + Show go to flow + 显示页面流 - - Autoscroll backward, vertical first - 向后自动滚动,垂直优先 + + Previous Comic + 上一个漫画 - - Move down - 向下移动 + + Show full size + 显示全尺寸 - - Move up - 向上移动 + + Hide/show toolbar + 隐藏/显示 工具栏 - - Move left - 向左移动 + + Magnifying glass + 放大镜 - - Move right - 向右移动 + + Edit shortcuts + 编辑快捷键 - - Go to the first page - 转到第一页 + + General + 常规 - - Go to the last page - 转到最后一页 + + Set a bookmark on the current page + 在当前页面设置书签 - - Reading - 阅读 + + Page adjustement + 页面调整 - - There is a new version available - 有新版本可用 + + Show zoom slider + 显示缩放滑块 + + + + Go to the last page + 转到最后一页 - + Do you want to download the new version? 你要下载新版本吗? - - Remind me in 14 days - 14天后提醒我 + + Rotate image to the right + 向右旋转图片 - - Not now - 现在不 + + Autoscroll backward, horizontal first + 向后自动滚动,水平优先 YACReader::WhatsNewDialog - + Close 关闭 YACReaderFieldEdit + + + Restore to default + 恢复默认 + Click to overwrite 点击以覆盖 + + + YACReaderFieldPlainTextEdit - + Restore to default 恢复默认 - - - YACReaderFieldPlainTextEdit @@ -964,24 +966,19 @@ Click to overwrite 点击以覆盖 - - - Restore to default - 恢复默认 - YACReaderFlowConfigWidget - - - How to show covers: - 封面显示方式: - CoverFlow look 封面流 + + + How to show covers: + 封面显示方式: + Stripe look @@ -996,29 +993,19 @@ YACReaderGLFlowConfigWidget - - Presets: - 预设: - - - - Classic look - 经典 - - - - Stripe look - 条状 + + Zoom + 缩放 - - Overlapped Stripe look - 重叠条状 + + Light + 亮度 - - Modern look - 现代 + + Show advanced settings + 显示高级选项 @@ -1026,19 +1013,14 @@ 轮盘 - - Show advanced settings - 显示高级选项 - - - - Custom: - 自定义: + + Cover Angle + 封面角度 - - View angle - 视角 + + Stripe look + 条状 @@ -1046,9 +1028,14 @@ 位置 - - Cover gap - 封面间距 + + Z offset + Z位移 + + + + Y offset + Y位移 @@ -1056,59 +1043,69 @@ 中心间距 - - Zoom - 缩放 + + Presets: + 预设: - - Y offset - Y位移 + + Overlapped Stripe look + 重叠条状 - - Z offset - Z位移 + + Modern look + 现代 - - Cover Angle - 封面角度 + + View angle + 视角 - - Visibility - 透明度 + + Max angle + 最大角度 - - Light - 亮度 + + Custom: + 自定义: - - Max angle - 最大角度 + + Classic look + 经典 - - Low Performance - 低性能 + + Cover gap + 封面间距 High Performance 高性能 + + + Performance: + 性能: + Use VSync (improve the image quality in fullscreen mode, worse performance) 使用VSync (在全屏模式下提高图像质量, 性能更差) - - Performance: - 性能: + + Visibility + 透明度 + + + + Low Performance + 低性能 @@ -1118,25 +1115,25 @@ Save 保存 + + + Use hardware acceleration (restart needed) + 使用硬件加速 (需要重启) + Cancel 取消 - - - Edit shortcuts - 编辑快捷键 - Shortcuts 快捷键 - - Use hardware acceleration (restart needed) - 使用硬件加速 (需要重启) + + Edit shortcuts + 编辑快捷键 @@ -1149,17 +1146,6 @@ YACReaderTranslator - - - YACReader translator - YACReader 翻译 - - - - - Translation - 翻译 - clear @@ -1170,5 +1156,16 @@ Service not available 服务不可用 + + + + Translation + 翻译 + + + + YACReader translator + YACReader 翻译 + diff --git a/YACReader/yacreader_zh_HK.ts b/YACReader/yacreader_zh_HK.ts index d258c9a5b..cb6cf5d73 100644 --- a/YACReader/yacreader_zh_HK.ts +++ b/YACReader/yacreader_zh_HK.ts @@ -36,27 +36,27 @@ EditShortcutsDialog - + Restore defaults 恢復默認 - + To change a shortcut, double click in the key combination and type the new keys. 更改快捷鍵: 雙擊按鍵組合並輸入新的映射. - + Shortcuts settings 快捷鍵設置 - + Shortcut in use 快捷鍵被佔用 - + The shortcut "%1" is already assigned to other function 快捷鍵 "%1" 已被映射至其他功能 @@ -200,22 +200,22 @@ 選擇 - + Quick Navigation Mode 快速導航模式 - + Disable mouse over activation 禁用滑鼠啟動 - + Restart is needed 需要重啟 - + Brightness 亮度 @@ -226,76 +226,81 @@ + Disable scroll animations and smooth scrolling + + + + Do not turn page using scroll 滾動時不翻頁 - + Use single scroll step to turn page 使用單滾動步驟翻頁 - + Contrast 對比度 - + Gamma Gamma值 - + Reset 重置 - + Image options 圖片選項 - + Fit options 適應項 - + Enlarge images to fit width/height 放大圖片以適應寬度/高度 - + Double Page options 雙頁選項 - + Show covers as single page 顯示封面為單頁 - + General 常規 - + Page Flow 頁面流 - + Image adjustment 圖像調整 - + Options 選項 - + Comics directory 漫畫目錄 @@ -387,26 +392,23 @@ ShortcutsDialog - YACReader keyboard shortcuts - YACReader 鍵盤快捷鍵 + YACReader 鍵盤快捷鍵 - Close - 關閉 + 關閉 - Keyboard Shortcuts - 鍵盤快捷鍵 + 鍵盤快捷鍵 Viewer - + Press 'O' to open comic. 按下 'O' 以打開漫畫. @@ -431,22 +433,22 @@ CRC 校驗失敗 - + Loading...please wait! 載入中... 請稍候! - + Page not available! 頁面不可用! - + Cover! 封面! - + Last page! 尾頁! @@ -454,480 +456,490 @@ YACReader::MainWindowViewer - + &Open 打開(&O) - + Open a comic 打開漫畫 - + New instance 新建實例 - + Open Folder 打開檔夾 - + Open image folder 打開圖片檔夾 - + Open latest comic 打開最近的漫畫 - + Open the latest comic opened in the previous reading session 打開最近閱讀漫畫 - + Clear 清空 - + Clear open recent list 清空最近訪問列表 - + Save 保存 - - + + Save current page 保存當前頁面 - + Previous Comic 上一個漫畫 - - - + + + Open previous comic 打開上一個漫畫 - + Next Comic 下一個漫畫 - - - + + + Open next comic 打開下一個漫畫 - + &Previous 上一頁(&P) - - - + + + Go to previous page 轉至上一頁 - + &Next 下一頁(&N) - - - + + + Go to next page 轉至下一頁 - + Fit Height 適應高度 - + Fit image to height 縮放圖片以適應高度 - + Fit Width 適合寬度 - + Fit image to width 縮放圖片以適應寬度 - + Show full size 顯示全尺寸 - + Fit to page 適應頁面 - + Reset zoom 重置縮放 - + Show zoom slider 顯示縮放滑塊 - + Zoom+ 放大 - + Zoom- 縮小 - + Rotate image to the left 向左旋轉圖片 - + Rotate image to the right 向右旋轉圖片 - + Double page mode 雙頁模式 - + Switch to double page mode 切換至雙頁模式 - + Double page manga mode 雙頁漫畫模式 - + Reverse reading order in double page mode 雙頁模式 (逆序閱讀) - + Go To 跳轉 - + Go to page ... 跳轉至頁面 ... - + Options 選項 - + YACReader options YACReader 選項 - - + + Help 幫助 - + Help, About YACReader 幫助, 關於 YACReader - + Magnifying glass 放大鏡 - + Switch Magnifying glass 切換放大鏡 - + Set bookmark 設置書簽 - + Set a bookmark on the current page 在當前頁面設置書簽 - + Show bookmarks 顯示書簽 - + Show the bookmarks of the current comic 顯示當前漫畫的書簽 - + Show keyboard shortcuts 顯示鍵盤快捷鍵 - + Show Info 顯示資訊 - + Close 關閉 - + Show Dictionary 顯示字典 - + Show go to flow 顯示頁面流 - + Edit shortcuts 編輯快捷鍵 - + &File 檔(&F) - - + + Open recent 最近打開的檔 - + File - + Edit 編輯 - + View 查看 - + Go 轉到 - + Window 窗口 - - + + Open Comic 打開漫畫 - - + + Comic files 漫畫檔 - + Open folder 打開檔夾 - + page_%1.jpg page_%1.jpg - + Image files (*.jpg) 圖像檔 (*.jpg) - + Comics 漫畫 - + Toggle fullscreen mode 切換全屏模式 - + Hide/show toolbar 隱藏/顯示 工具欄 - + General 常規 - + Size up magnifying glass 增大放大鏡尺寸 - + Size down magnifying glass 減小放大鏡尺寸 - + Zoom in magnifying glass 增大縮放級別 - + Zoom out magnifying glass 減小縮放級別 - + Magnifiying glass 放大鏡 - + Toggle between fit to width and fit to height 切換顯示為"適應寬度"或"適應高度" - + Page adjustement 頁面調整 - + Autoscroll down 向下自動滾動 - + Autoscroll up 向上自動滾動 - + Autoscroll forward, horizontal first 向前自動滾動,水準優先 - + Autoscroll backward, horizontal first 向後自動滾動,水準優先 - + Autoscroll forward, vertical first 向前自動滾動,垂直優先 - + Autoscroll backward, vertical first 向後自動滾動,垂直優先 - + Move down 向下移動 - + Move up 向上移動 - + Move left 向左移動 - + Move right 向右移動 - + Go to the first page 轉到第一頁 - + Go to the last page 轉到最後一頁 - + + Offset double page to the left + + + + + Offset double page to the right + + + + Reading 閱讀 - + There is a new version available 有新版本可用 - + Do you want to download the new version? 你要下載新版本嗎? - + Remind me in 14 days 14天後提醒我 - + Not now 現在不 @@ -935,7 +947,7 @@ YACReader::WhatsNewDialog - + Close 關閉 diff --git a/YACReader/yacreader_zh_TW.ts b/YACReader/yacreader_zh_TW.ts index db20fcfe4..5faa6a8fd 100644 --- a/YACReader/yacreader_zh_TW.ts +++ b/YACReader/yacreader_zh_TW.ts @@ -36,27 +36,27 @@ EditShortcutsDialog - + Restore defaults 恢復默認 - + To change a shortcut, double click in the key combination and type the new keys. 更改快捷鍵: 雙擊按鍵組合並輸入新的映射. - + Shortcuts settings 快捷鍵設置 - + Shortcut in use 快捷鍵被佔用 - + The shortcut "%1" is already assigned to other function 快捷鍵 "%1" 已被映射至其他功能 @@ -200,22 +200,22 @@ 選擇 - + Quick Navigation Mode 快速導航模式 - + Disable mouse over activation 禁用滑鼠啟動 - + Restart is needed 需要重啟 - + Brightness 亮度 @@ -226,76 +226,81 @@ + Disable scroll animations and smooth scrolling + + + + Do not turn page using scroll 滾動時不翻頁 - + Use single scroll step to turn page 使用單滾動步驟翻頁 - + Contrast 對比度 - + Gamma Gamma值 - + Reset 重置 - + Image options 圖片選項 - + Fit options 適應項 - + Enlarge images to fit width/height 放大圖片以適應寬度/高度 - + Double Page options 雙頁選項 - + Show covers as single page 顯示封面為單頁 - + General 常規 - + Page Flow 頁面流 - + Image adjustment 圖像調整 - + Options 選項 - + Comics directory 漫畫目錄 @@ -387,26 +392,23 @@ ShortcutsDialog - YACReader keyboard shortcuts - YACReader 鍵盤快捷鍵 + YACReader 鍵盤快捷鍵 - Close - 關閉 + 關閉 - Keyboard Shortcuts - 鍵盤快捷鍵 + 鍵盤快捷鍵 Viewer - + Press 'O' to open comic. 按下 'O' 以打開漫畫. @@ -431,22 +433,22 @@ CRC 校驗失敗 - + Loading...please wait! 載入中... 請稍候! - + Page not available! 頁面不可用! - + Cover! 封面! - + Last page! 尾頁! @@ -454,480 +456,490 @@ YACReader::MainWindowViewer - + &Open 打開(&O) - + Open a comic 打開漫畫 - + New instance 新建實例 - + Open Folder 打開檔夾 - + Open image folder 打開圖片檔夾 - + Open latest comic 打開最近的漫畫 - + Open the latest comic opened in the previous reading session 打開最近閱讀漫畫 - + Clear 清空 - + Clear open recent list 清空最近訪問列表 - + Save 保存 - - + + Save current page 保存當前頁面 - + Previous Comic 上一個漫畫 - - - + + + Open previous comic 打開上一個漫畫 - + Next Comic 下一個漫畫 - - - + + + Open next comic 打開下一個漫畫 - + &Previous 上一頁(&P) - - - + + + Go to previous page 轉至上一頁 - + &Next 下一頁(&N) - - - + + + Go to next page 轉至下一頁 - + Fit Height 適應高度 - + Fit image to height 縮放圖片以適應高度 - + Fit Width 適合寬度 - + Fit image to width 縮放圖片以適應寬度 - + Show full size 顯示全尺寸 - + Fit to page 適應頁面 - + Reset zoom 重置縮放 - + Show zoom slider 顯示縮放滑塊 - + Zoom+ 放大 - + Zoom- 縮小 - + Rotate image to the left 向左旋轉圖片 - + Rotate image to the right 向右旋轉圖片 - + Double page mode 雙頁模式 - + Switch to double page mode 切換至雙頁模式 - + Double page manga mode 雙頁漫畫模式 - + Reverse reading order in double page mode 雙頁模式 (逆序閱讀) - + Go To 跳轉 - + Go to page ... 跳轉至頁面 ... - + Options 選項 - + YACReader options YACReader 選項 - - + + Help 幫助 - + Help, About YACReader 幫助, 關於 YACReader - + Magnifying glass 放大鏡 - + Switch Magnifying glass 切換放大鏡 - + Set bookmark 設置書簽 - + Set a bookmark on the current page 在當前頁面設置書簽 - + Show bookmarks 顯示書簽 - + Show the bookmarks of the current comic 顯示當前漫畫的書簽 - + Show keyboard shortcuts 顯示鍵盤快捷鍵 - + Show Info 顯示資訊 - + Close 關閉 - + Show Dictionary 顯示字典 - + Show go to flow 顯示頁面流 - + Edit shortcuts 編輯快捷鍵 - + &File 檔(&F) - - + + Open recent 最近打開的檔 - + File - + Edit 編輯 - + View 查看 - + Go 轉到 - + Window 窗口 - - + + Open Comic 打開漫畫 - - + + Comic files 漫畫檔 - + Open folder 打開檔夾 - + page_%1.jpg page_%1.jpg - + Image files (*.jpg) 圖像檔 (*.jpg) - + Comics 漫畫 - + Toggle fullscreen mode 切換全屏模式 - + Hide/show toolbar 隱藏/顯示 工具欄 - + General 常規 - + Size up magnifying glass 增大放大鏡尺寸 - + Size down magnifying glass 減小放大鏡尺寸 - + Zoom in magnifying glass 增大縮放級別 - + Zoom out magnifying glass 減小縮放級別 - + Magnifiying glass 放大鏡 - + Toggle between fit to width and fit to height 切換顯示為"適應寬度"或"適應高度" - + Page adjustement 頁面調整 - + Autoscroll down 向下自動滾動 - + Autoscroll up 向上自動滾動 - + Autoscroll forward, horizontal first 向前自動滾動,水準優先 - + Autoscroll backward, horizontal first 向後自動滾動,水準優先 - + Autoscroll forward, vertical first 向前自動滾動,垂直優先 - + Autoscroll backward, vertical first 向後自動滾動,垂直優先 - + Move down 向下移動 - + Move up 向上移動 - + Move left 向左移動 - + Move right 向右移動 - + Go to the first page 轉到第一頁 - + Go to the last page 轉到最後一頁 - + + Offset double page to the left + + + + + Offset double page to the right + + + + Reading 閱讀 - + There is a new version available 有新版本可用 - + Do you want to download the new version? 你要下載新版本嗎? - + Remind me in 14 days 14天後提醒我 - + Not now 現在不 @@ -935,7 +947,7 @@ YACReader::WhatsNewDialog - + Close 關閉 diff --git a/YACReaderLibrary/YACReaderLibrary.pro b/YACReaderLibrary/YACReaderLibrary.pro index bff7643e9..ed79aa38a 100644 --- a/YACReaderLibrary/YACReaderLibrary.pro +++ b/YACReaderLibrary/YACReaderLibrary.pro @@ -81,6 +81,7 @@ HEADERS += comic_flow.h \ db/search_query.h \ folder_content_view.h \ initial_comic_info_extractor.h \ + libraries_update_coordinator.h \ library_comic_opener.h \ library_creator.h \ library_window.h \ @@ -167,6 +168,7 @@ SOURCES += comic_flow.cpp \ db/search_query.cpp \ folder_content_view.cpp \ initial_comic_info_extractor.cpp \ + libraries_update_coordinator.cpp \ library_comic_opener.cpp \ library_creator.cpp \ library_window.cpp \ diff --git a/YACReaderLibrary/classic_comics_view.cpp b/YACReaderLibrary/classic_comics_view.cpp index 772149f7b..5af869a26 100644 --- a/YACReaderLibrary/classic_comics_view.cpp +++ b/YACReaderLibrary/classic_comics_view.cpp @@ -60,10 +60,7 @@ ClassicComicsView::ClassicComicsView(QWidget *parent) sVertical->addWidget(comics); tableView->setContextMenuPolicy(Qt::CustomContextMenu); - - // config-------------------------------------------------- - if (settings->contains(COMICS_VIEW_HEADERS)) - tableView->horizontalHeader()->restoreState(settings->value(COMICS_VIEW_HEADERS).toByteArray()); + tableView->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu); // connections--------------------------------------------- connect(tableView, &QAbstractItemView::clicked, this, &ClassicComicsView::centerComicFlow); @@ -75,6 +72,7 @@ ClassicComicsView::ClassicComicsView(QWidget *parent) connect(tableView->horizontalHeader(), &QHeaderView::sectionResized, this, &ClassicComicsView::saveTableHeadersStatus); connect(comicFlow, &QWidget::customContextMenuRequested, this, &ClassicComicsView::requestedViewContextMenu); connect(tableView, &QWidget::customContextMenuRequested, this, &ClassicComicsView::requestedItemContextMenu); + connect(tableView->horizontalHeader(), &QWidget::customContextMenuRequested, this, &ClassicComicsView::requestedHeaderContextMenu); layout->addWidget(sVertical); setLayout(layout); @@ -84,8 +82,13 @@ ClassicComicsView::ClassicComicsView(QWidget *parent) sVertical->setCollapsible(1, false); #endif - if (settings->contains(COMICS_VIEW_FLOW_SPLITTER_STATUS)) - sVertical->restoreState(settings->value(COMICS_VIEW_FLOW_SPLITTER_STATUS).toByteArray()); + if (settings->contains(COMICS_VIEW_FLOW_SPLITTER_STATUS)) { + try { + sVertical->restoreState(settings->value(COMICS_VIEW_FLOW_SPLITTER_STATUS).toByteArray()); + } catch (...) { + // do nothing + } + } // hide flow widgets hideFlowViewAction = new QAction(this); @@ -135,6 +138,7 @@ void ClassicComicsView::setModel(ComicModel *model) } else { connect(model, &QAbstractItemModel::dataChanged, this, &ClassicComicsView::applyModelChanges, Qt::UniqueConnection); connect(model, &QAbstractItemModel::rowsRemoved, this, &ClassicComicsView::removeItemsFromFlow, Qt::UniqueConnection); + connect(model, &QAbstractItemModel::rowsInserted, this, &ClassicComicsView::addItemsToFlow, Qt::UniqueConnection); // TODO: Missing method resortCovers? connect(model, &ComicModel::resortedIndexes, comicFlow, &ComicFlowWidget::resortCovers, Qt::UniqueConnection); connect(model, &ComicModel::newSelectedIndex, this, &ClassicComicsView::setCurrentIndex, Qt::UniqueConnection); @@ -149,34 +153,48 @@ void ClassicComicsView::setModel(ComicModel *model) #else tableView->horizontalHeader()->setMovable(true); #endif - // TODO parametrizar la configuración de las columnas - /*if(!settings->contains(COMICS_VIEW_HEADERS)) - {*/ - for (int i = 0; i < tableView->horizontalHeader()->count(); i++) - tableView->horizontalHeader()->hideSection(i); - - tableView->horizontalHeader()->showSection(ComicModel::Number); - tableView->horizontalHeader()->showSection(ComicModel::Title); - tableView->horizontalHeader()->showSection(ComicModel::FileName); - tableView->horizontalHeader()->showSection(ComicModel::NumPages); - tableView->horizontalHeader()->showSection(ComicModel::Hash); // Size is part of the Hash...TODO add Columns::Size to Columns - tableView->horizontalHeader()->showSection(ComicModel::ReadColumn); - tableView->horizontalHeader()->showSection(ComicModel::CurrentPage); - tableView->horizontalHeader()->showSection(ComicModel::PublicationDate); - tableView->horizontalHeader()->showSection(ComicModel::Rating); - //} - - // debido a un bug, qt4 no es capaz de ajustar el ancho teniendo en cuenta todas la filas (no sólo las visibles) - // así que se ecala la primera vez y después se deja el control al usuario. - // if(!settings->contains(COMICS_VIEW_HEADERS)) - QStringList paths = model->getPaths(model->getCurrentPath()); // TODO ComicsView: get currentpath from somewhere currentPath()); comicFlow->setImagePaths(paths); comicFlow->setMarks(model->getReadList()); - // comicFlow->setFocus(Qt::OtherFocusReason); - if (settings->contains(COMICS_VIEW_HEADERS)) - tableView->horizontalHeader()->restoreState(settings->value(COMICS_VIEW_HEADERS).toByteArray()); + bool loadDefaults = false; + if (settings->contains(COMICS_VIEW_HEADERS)) { + try { + loadDefaults = !tableView->horizontalHeader()->restoreState(settings->value(COMICS_VIEW_HEADERS).toByteArray()); + } catch (...) { + loadDefaults = true; + } + } else { + loadDefaults = true; + } + + if (loadDefaults) { + // default columns and order + for (int i = 0; i < tableView->horizontalHeader()->count(); i++) + tableView->horizontalHeader()->hideSection(i); + + tableView->horizontalHeader()->showSection(ComicModel::Number); + tableView->horizontalHeader()->showSection(ComicModel::Title); + tableView->horizontalHeader()->showSection(ComicModel::FileName); + tableView->horizontalHeader()->showSection(ComicModel::NumPages); + tableView->horizontalHeader()->showSection(ComicModel::Size); + tableView->horizontalHeader()->showSection(ComicModel::ReadColumn); + tableView->horizontalHeader()->showSection(ComicModel::CurrentPage); + tableView->horizontalHeader()->showSection(ComicModel::PublicationDate); + tableView->horizontalHeader()->showSection(ComicModel::Rating); + + tableView->horizontalHeader()->moveSection(ComicModel::CurrentPage, 3); + tableView->horizontalHeader()->moveSection(ComicModel::Rating, 12); + tableView->horizontalHeader()->moveSection(ComicModel::Size, 5); + } + + // make sure that columns without title are hidden + for (int i = 0; i < tableView->horizontalHeader()->count(); i++) { + auto title = tableView->model()->headerData(i, Qt::Horizontal).toString(); + if (title.isEmpty()) { + tableView->horizontalHeader()->hideSection(i); + } + } tableView->resizeColumnsToContents(); @@ -289,6 +307,27 @@ void ClassicComicsView::requestedItemContextMenu(const QPoint &point) emit customContextMenuItemRequested(tableView->mapTo(this, point)); } +void ClassicComicsView::requestedHeaderContextMenu(const QPoint &point) +{ + QMenu menu; + + for (int i = 0; i < tableView->model()->columnCount(); ++i) { + auto title = tableView->model()->headerData(i, Qt::Horizontal).toString(); + + if (!title.isEmpty()) { + auto action = menu.addAction(tableView->model()->headerData(i, Qt::Horizontal).toString()); + action->setCheckable(true); + action->setChecked(!tableView->isColumnHidden(i)); + connect(action, &QAction::toggled, tableView, [this, i](bool checked) { + tableView->horizontalHeader()->setSectionHidden(i, !checked); + }); + connect(action, &QAction::toggled, this, &ClassicComicsView::saveTableHeadersStatus); + } + } + + menu.exec(this->tableView->horizontalHeader()->mapToGlobal(point)); +} + void ClassicComicsView::setShowMarks(bool show) { comicFlow->setShowMarks(show); @@ -341,6 +380,15 @@ void ClassicComicsView::removeItemsFromFlow(const QModelIndex &parent, int from, comicFlow->remove(i); } +void ClassicComicsView::addItemsToFlow(const QModelIndex &parent, int from, int to) +{ + Q_UNUSED(parent); + for (int i = from; i <= to; i++) { + auto coverPath = model->index(i, 0).data(ComicModel::CoverPathRole).toUrl().toLocalFile(); + comicFlow->add(coverPath, i); + } +} + void ClassicComicsView::closeEvent(QCloseEvent *event) { toolbar->removeAction(startSeparatorAction); diff --git a/YACReaderLibrary/classic_comics_view.h b/YACReaderLibrary/classic_comics_view.h index 6307b4bbc..c492a033e 100644 --- a/YACReaderLibrary/classic_comics_view.h +++ b/YACReaderLibrary/classic_comics_view.h @@ -42,6 +42,7 @@ public slots: void saveSplitterStatus(); void applyModelChanges(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles); void removeItemsFromFlow(const QModelIndex &parent, int from, int to); + void addItemsToFlow(const QModelIndex &parent, int from, int to); // ComicsView void setShowMarks(bool show) override; void selectAll() override; @@ -51,6 +52,7 @@ protected slots: void hideComicFlow(bool hide); void requestedViewContextMenu(const QPoint &point); void requestedItemContextMenu(const QPoint &point); + void requestedHeaderContextMenu(const QPoint &point); private: YACReaderTableView *tableView; diff --git a/YACReaderLibrary/comic_flow.cpp b/YACReaderLibrary/comic_flow.cpp index 2cc4dbd24..a746ecd7f 100644 --- a/YACReaderLibrary/comic_flow.cpp +++ b/YACReaderLibrary/comic_flow.cpp @@ -112,6 +112,18 @@ void ComicFlow::wheelEvent(QWheelEvent *event) event->accept(); } +void ComicFlow::insertSlide(const QString &path, int index) +{ + imageFiles.insert(index, path); + imagesLoaded.insert(index, false); + imagesSetted.insert(index, false); + + YACReaderFlow::insertSlide(index); + + resetWorkerIndex(); + preload(); +} + void ComicFlow::removeSlide(int cover) { imageFiles.removeAt(cover); diff --git a/YACReaderLibrary/comic_flow.h b/YACReaderLibrary/comic_flow.h index 2d5953843..f8cc9a4d9 100644 --- a/YACReaderLibrary/comic_flow.h +++ b/YACReaderLibrary/comic_flow.h @@ -24,6 +24,7 @@ class ComicFlow : public YACReaderFlow void setImagePaths(const QStringList &paths); // bool eventFilter(QObject *target, QEvent *event); void keyPressEvent(QKeyEvent *event) override; + void insertSlide(const QString &path, int index); void removeSlide(int cover); void resortCovers(QList newOrder); diff --git a/YACReaderLibrary/comic_flow_widget.cpp b/YACReaderLibrary/comic_flow_widget.cpp index 372bb46fd..95515d913 100644 --- a/YACReaderLibrary/comic_flow_widget.cpp +++ b/YACReaderLibrary/comic_flow_widget.cpp @@ -133,6 +133,11 @@ void ComicFlowWidgetSW::updateConfig(QSettings *settings) } } +void ComicFlowWidgetSW::add(const QString &path, int index) +{ + flow->insertSlide(path, index); +} + void ComicFlowWidgetSW::remove(int cover) { flow->removeSlide(cover); @@ -327,6 +332,11 @@ void ComicFlowWidgetGL::updateConfig(QSettings *settings) ; } +void ComicFlowWidgetGL::add(const QString &path, int index) +{ + flow->add(path, index); +} + void ComicFlowWidgetGL::remove(int cover) { flow->remove(cover); diff --git a/YACReaderLibrary/comic_flow_widget.h b/YACReaderLibrary/comic_flow_widget.h index 2c2c17595..ace364884 100644 --- a/YACReaderLibrary/comic_flow_widget.h +++ b/YACReaderLibrary/comic_flow_widget.h @@ -30,6 +30,7 @@ public slots: virtual void setFlowType(FlowType flowType) = 0; virtual void render() = 0; virtual void updateConfig(QSettings *settings) = 0; + virtual void add(const QString &path, int index) = 0; virtual void remove(int cover) = 0; virtual void resortCovers(QList newOrder) = 0; signals: @@ -61,6 +62,7 @@ class ComicFlowWidgetSW : public ComicFlowWidget void setFlowType(FlowType flowType) override; void render() override; void updateConfig(QSettings *settings) override; + void add(const QString &path, int index) override; void remove(int cover) override; void resortCovers(QList newOrder) override; @@ -101,6 +103,7 @@ class ComicFlowWidgetGL : public ComicFlowWidget void setFlowType(FlowType flowType) override; void render() override; void updateConfig(QSettings *settings) override; + void add(const QString &path, int index) override; void remove(int cover) override; void resortCovers(QList newOrder) override; // public slots: diff --git a/YACReaderLibrary/comics_remover.cpp b/YACReaderLibrary/comics_remover.cpp index 7cf0aa773..7d11e9282 100644 --- a/YACReaderLibrary/comics_remover.cpp +++ b/YACReaderLibrary/comics_remover.cpp @@ -21,7 +21,9 @@ void ComicsRemover::process() while (i.hasPrevious() && i2.hasPrevious()) { QModelIndex mi = i.previous(); currentComicPath = i2.previous(); - if (QFile::remove(currentComicPath)) + if (QFile::moveToTrash(currentComicPath)) + emit remove(mi.row()); + else if (QFile::remove(currentComicPath)) emit remove(mi.row()); else emit removeError(); @@ -50,7 +52,9 @@ void FoldersRemover::process() QModelIndex mi = i.previous(); currentFolderPath = i2.previous(); QDir d(currentFolderPath); - if (d.removeRecursively() || !d.exists()) // the folder is in the DB but no in the drive... + if (QFile::moveToTrash(currentFolderPath)) + emit remove(mi); + else if (d.removeRecursively() || !d.exists()) // the folder is in the DB but no in the drive... emit remove(mi); else emit removeError(); diff --git a/YACReaderLibrary/comics_view.cpp b/YACReaderLibrary/comics_view.cpp index 64ab0cf4c..b20a42392 100644 --- a/YACReaderLibrary/comics_view.cpp +++ b/YACReaderLibrary/comics_view.cpp @@ -48,6 +48,14 @@ void ComicsView::setModel(ComicModel *m) model = m; } +void ComicsView::reloadContent() +{ + if (model != nullptr) { + model->reload(); + updateInfoForIndex(currentIndex().row()); + } +} + void ComicsView::updateInfoForIndex(int index) { QQmlContext *ctxt = view->rootContext(); diff --git a/YACReaderLibrary/comics_view.h b/YACReaderLibrary/comics_view.h index 12f780a7f..484c73543 100644 --- a/YACReaderLibrary/comics_view.h +++ b/YACReaderLibrary/comics_view.h @@ -30,6 +30,7 @@ class ComicsView : public QWidget virtual void selectIndex(int index) = 0; virtual void updateCurrentComicView() = 0; virtual void focusComicsNavigation(Qt::FocusReason reason) = 0; + virtual void reloadContent(); public slots: virtual void updateInfoForIndex(int index); diff --git a/YACReaderLibrary/db/comic_item.cpp b/YACReaderLibrary/db/comic_item.cpp index 179f0f546..96cc0d800 100644 --- a/YACReaderLibrary/db/comic_item.cpp +++ b/YACReaderLibrary/db/comic_item.cpp @@ -22,6 +22,16 @@ int ComicItem::columnCount() const { return itemData.count(); } + +QList ComicItem::getData() const +{ + return itemData; +} + +void ComicItem::setData(const QList &data) +{ + itemData = data; +} //! [5] //! [6] diff --git a/YACReaderLibrary/db/comic_item.h b/YACReaderLibrary/db/comic_item.h index ae7da7047..24b3da190 100644 --- a/YACReaderLibrary/db/comic_item.h +++ b/YACReaderLibrary/db/comic_item.h @@ -12,6 +12,8 @@ class ComicItem : public QObject ComicItem(const QList &data); ~ComicItem() override; int columnCount() const; + QList getData() const; + void setData(const QList &data); QVariant data(int column) const; void setData(int column, const QVariant &value); int row() const; diff --git a/YACReaderLibrary/db/comic_model.cpp b/YACReaderLibrary/db/comic_model.cpp index 84c488003..23e4cd783 100644 --- a/YACReaderLibrary/db/comic_model.cpp +++ b/YACReaderLibrary/db/comic_model.cpp @@ -10,24 +10,29 @@ #include "qnaturalsorting.h" #include "comic_db.h" #include "db_helper.h" -#include "query_parser.h" #include "reading_list_model.h" // ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read #include "QsLog.h" +auto defaultFolderContentSortFunction = [](const ComicItem *c1, const ComicItem *c2) { + if (c1->data(ComicModel::Number).isNull() && c2->data(ComicModel::Number).isNull()) { + return naturalSortLessThanCI(c1->data(ComicModel::FileName).toString(), c2->data(ComicModel::FileName).toString()); + } else { + if (c1->data(ComicModel::Number).isNull() == false && c2->data(ComicModel::Number).isNull() == false) { + return naturalSortLessThanCI(c1->data(ComicModel::Number).toString(), c2->data(ComicModel::Number).toString()); + } else { + return c2->data(ComicModel::Number).isNull(); + } + } +}; + ComicModel::ComicModel(QObject *parent) : QAbstractItemModel(parent), showRecent(false), recentDays(1) { } -ComicModel::ComicModel(QSqlQuery &sqlquery, QObject *parent) - : QAbstractItemModel(parent), showRecent(false), recentDays(1) -{ - setupModelData(sqlquery); -} - ComicModel::~ComicModel() { qDeleteAll(_data); @@ -38,7 +43,7 @@ int ComicModel::columnCount(const QModelIndex &parent) const Q_UNUSED(parent) if (_data.isEmpty()) return 0; - return _data.first()->columnCount(); + return _data.first()->columnCount() + 1 /* + the number of calculated columns */; } bool ComicModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const @@ -167,7 +172,10 @@ bool ComicModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int case ReadingList: DBHelper::reasignOrderToComicsInReadingList(sourceId, allComicIds, db); break; - default: + case Folder: + case Reading: + case Recent: + case SearchResult: break; } connectionName = db.connectionName(); @@ -233,7 +241,6 @@ QHash ComicModel::roleNames() const roles[PathRole] = "path"; roles[HashRole] = "hash"; roles[ReadColumnRole] = "read_column"; - roles[IsBisRole] = "is_bis"; roles[CurrentPageRole] = "current_page"; roles[RatingRole] = "rating"; roles[HasBeenOpenedRole] = "has_been_opened"; @@ -244,6 +251,10 @@ QHash ComicModel::roleNames() const roles[TypeRole] = "type"; roles[ShowRecentRole] = "show_recent"; roles[RecentRangeRole] = "recent_range"; + roles[SizeRole] = "size"; + roles[SeriesRole] = "series"; + roles[VolumeRole] = "volume"; + roles[StoryArcRole] = "story_arc"; return roles; } @@ -264,7 +275,7 @@ QVariant ComicModel::data(const QModelIndex &index, int role) const return QVariant(Qt::AlignRight | Qt::AlignVCenter); case ComicModel::NumPages: return QVariant(Qt::AlignRight | Qt::AlignVCenter); - case ComicModel::Hash: + case ComicModel::Size: return QVariant(Qt::AlignRight | Qt::AlignVCenter); case ComicModel::CurrentPage: return QVariant(Qt::AlignRight | Qt::AlignVCenter); @@ -278,6 +289,10 @@ QVariant ComicModel::data(const QModelIndex &index, int role) const auto item = static_cast(index.internalPointer()); + auto sizeString = [=] { + return QString::number(item->data(ComicModel::Hash).toString().right(item->data(ComicModel::Hash).toString().length() - 40).toInt() / 1024.0 / 1024.0, 'f', 2) + "Mb"; + }; + if (role == NumberRole) return item->data(Number); else if (role == TitleRole) @@ -301,7 +316,7 @@ QVariant ComicModel::data(const QModelIndex &index, int role) const else if (role == ReadColumnRole) return item->data(ReadColumn).toBool(); else if (role == HasBeenOpenedRole) - return item->data(ComicModel::HasBeenOpened); + return item->data(HasBeenOpened); else if (role == IdRole) return item->data(Id); else if (role == PublicationDateRole) @@ -312,14 +327,24 @@ QVariant ComicModel::data(const QModelIndex &index, int role) const return item->data(Type); else if (role == ShowRecentRole) return showRecent; - else if (role == ComicModel::RecentRangeRole) + else if (role == RecentRangeRole) return recentDays * 86400; + else if (role == SizeRole) + return sizeString(); + else if (role == SeriesRole) + return item->data(Series); + else if (role == VolumeRole) + return item->data(Volume); + else if (role == StoryArcRole) + return item->data(StoryArc); if (role != Qt::DisplayRole) return QVariant(); if (index.column() == ComicModel::Hash) - return QString::number(item->data(index.column()).toString().right(item->data(index.column()).toString().length() - 40).toInt() / 1024.0 / 1024.0, 'f', 2) + "Mb"; + return item->data(ComicModel::Hash).toString(); + if (index.column() == ComicModel::Size) + return sizeString(); if (index.column() == ComicModel::ReadColumn) return (item->data(ComicModel::CurrentPage).toInt() == item->data(ComicModel::NumPages).toInt() || item->data(ComicModel::ReadColumn).toBool()) ? QVariant(tr("yes")) : QVariant(tr("no")); if (index.column() == ComicModel::CurrentPage) @@ -348,8 +373,7 @@ QVariant ComicModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { - switch (section) // TODO obtener esto de la query - { + switch (section) { case ComicModel::Number: return QVariant(QString("#")); case ComicModel::Title: @@ -358,7 +382,7 @@ QVariant ComicModel::headerData(int section, Qt::Orientation orientation, return QVariant(QString(tr("File Name"))); case ComicModel::NumPages: return QVariant(QString(tr("Pages"))); - case ComicModel::Hash: + case ComicModel::Size: return QVariant(QString(tr("Size"))); case ComicModel::ReadColumn: return QVariant(QString(tr("Read"))); @@ -368,17 +392,22 @@ QVariant ComicModel::headerData(int section, Qt::Orientation orientation, return QVariant(QString(tr("Publication Date"))); case ComicModel::Rating: return QVariant(QString(tr("Rating"))); + case ComicModel::Series: + return QVariant(QString(tr("Series"))); + case ComicModel::Volume: + return QVariant(QString(tr("Volume"))); + case ComicModel::StoryArc: + return QVariant(QString(tr("Story Arc"))); } } if (orientation == Qt::Horizontal && role == Qt::TextAlignmentRole) { - switch (section) // TODO obtener esto de la query - { + switch (section) { case ComicModel::Number: return QVariant(Qt::AlignRight | Qt::AlignVCenter); case ComicModel::NumPages: return QVariant(Qt::AlignRight | Qt::AlignVCenter); - case ComicModel::Hash: + case ComicModel::Size: return QVariant(Qt::AlignRight | Qt::AlignVCenter); case ComicModel::CurrentPage: return QVariant(Qt::AlignRight | Qt::AlignVCenter); @@ -456,19 +485,12 @@ QStringList ComicModel::getPaths(const QString &_source) return paths; } -#define COMIC_MODEL_QUERY_FIELDS "ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read,ci.isBis,ci.currentPage,ci.rating,ci.hasBeenOpened,ci.date,ci.added,ci.type" +#define COMIC_MODEL_QUERY_FIELDS "ci.number,ci.title,c.fileName,ci.numPages,c.id,c.parentId,c.path,ci.hash,ci.read,ci.currentPage,ci.rating,ci.hasBeenOpened,ci.date,ci.added,ci.type,ci.lastTimeOpened,ci.series,ci.volume,ci.storyArc" -void ComicModel::setupFolderModelData(unsigned long long int folderId, const QString &databasePath) +QList ComicModel::createFolderModelData(unsigned long long folderId, const QString &databasePath) const { - enableResorting = false; - mode = Folder; - sourceId = folderId; + QList modelData; - beginResetModel(); - qDeleteAll(_data); - _data.clear(); - - _databasePath = databasePath; QString connectionName = ""; { QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); @@ -478,24 +500,37 @@ void ComicModel::setupFolderModelData(unsigned long long int folderId, const QSt "WHERE c.parentId = :parentId"); selectQuery.bindValue(":parentId", folderId); selectQuery.exec(); - setupModelData(selectQuery); + + modelData = createModelData(selectQuery); + connectionName = db.connectionName(); } QSqlDatabase::removeDatabase(connectionName); - endResetModel(); + + return modelData; } -void ComicModel::setupLabelModelData(unsigned long long parentLabel, const QString &databasePath) +void ComicModel::setupFolderModelData(unsigned long long int folderId, const QString &databasePath) { - enableResorting = true; - mode = Label; - sourceId = parentLabel; + enableResorting = false; + mode = Folder; + sourceId = folderId; beginResetModel(); qDeleteAll(_data); _data.clear(); _databasePath = databasePath; + + takeData(createFolderModelData(folderId, databasePath)); + + endResetModel(); +} + +QList ComicModel::createLabelModelData(unsigned long long parentLabel, const QString &databasePath) const +{ + QList modelData; + QString connectionName = ""; { QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); @@ -507,23 +542,35 @@ void ComicModel::setupLabelModelData(unsigned long long parentLabel, const QStri "ORDER BY cl.ordering"); selectQuery.bindValue(":parentLabelId", parentLabel); selectQuery.exec(); - setupModelDataForList(selectQuery); + modelData = createModelDataForList(selectQuery); connectionName = db.connectionName(); } QSqlDatabase::removeDatabase(connectionName); - endResetModel(); + + return modelData; } -void ComicModel::setupReadingListModelData(unsigned long long parentReadingList, const QString &databasePath) +void ComicModel::setupLabelModelData(unsigned long long parentLabel, const QString &databasePath) { - mode = ReadingList; - sourceId = parentReadingList; + enableResorting = true; + mode = Label; + sourceId = parentLabel; beginResetModel(); qDeleteAll(_data); _data.clear(); _databasePath = databasePath; + + takeData(createLabelModelData(parentLabel, databasePath)); + + endResetModel(); +} + +QList ComicModel::createReadingListData(unsigned long long parentReadingList, const QString &databasePath, bool &enableResorting) const +{ + QList modelData; + QString connectionName = ""; { QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); @@ -552,31 +599,35 @@ void ComicModel::setupReadingListModelData(unsigned long long parentReadingList, selectQuery.bindValue(":parentReadingList", id); selectQuery.exec(); - // TODO, extra information is needed (resorting) - QList tempData = _data; - _data.clear(); - - setupModelDataForList(selectQuery); - - _data = tempData << _data; + modelData << createModelDataForList(selectQuery); } connectionName = db.connectionName(); } QSqlDatabase::removeDatabase(connectionName); - endResetModel(); + + return modelData; } -void ComicModel::setupFavoritesModelData(const QString &databasePath) +void ComicModel::setupReadingListModelData(unsigned long long parentReadingList, const QString &databasePath) { - enableResorting = true; - mode = Favorites; - sourceId = -1; + mode = ReadingList; + sourceId = parentReadingList; beginResetModel(); qDeleteAll(_data); _data.clear(); _databasePath = databasePath; + + takeData(createReadingListData(parentReadingList, databasePath, enableResorting)); + + endResetModel(); +} + +QList ComicModel::createFavoritesModelData(const QString &databasePath) const +{ + QList modelData; + QString connectionName = ""; { QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); @@ -588,17 +639,18 @@ void ComicModel::setupFavoritesModelData(const QString &databasePath) "ORDER BY cdrl.ordering"); selectQuery.bindValue(":parentDefaultListId", 1); selectQuery.exec(); - setupModelDataForList(selectQuery); + modelData = createModelDataForList(selectQuery); connectionName = db.connectionName(); } QSqlDatabase::removeDatabase(connectionName); - endResetModel(); + + return modelData; } -void ComicModel::setupReadingModelData(const QString &databasePath) +void ComicModel::setupFavoritesModelData(const QString &databasePath) { - enableResorting = false; - mode = Reading; + enableResorting = true; + mode = Favorites; sourceId = -1; beginResetModel(); @@ -606,6 +658,16 @@ void ComicModel::setupReadingModelData(const QString &databasePath) _data.clear(); _databasePath = databasePath; + + takeData(createFavoritesModelData(databasePath)); + + endResetModel(); +} + +QList ComicModel::createReadingModelData(const QString &databasePath) const +{ + QList modelData; + QString connectionName = ""; { QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); @@ -616,17 +678,18 @@ void ComicModel::setupReadingModelData(const QString &databasePath) "ORDER BY ci.lastTimeOpened DESC"); selectQuery.exec(); - setupModelDataForList(selectQuery); + modelData = createModelDataForList(selectQuery); connectionName = db.connectionName(); } QSqlDatabase::removeDatabase(connectionName); - endResetModel(); + + return modelData; } -void ComicModel::setupRecentModelData(const QString &databasePath) +void ComicModel::setupReadingModelData(const QString &databasePath) { enableResorting = false; - mode = Recent; + mode = Reading; sourceId = -1; beginResetModel(); @@ -635,6 +698,15 @@ void ComicModel::setupRecentModelData(const QString &databasePath) _databasePath = databasePath; + takeData(createReadingModelData(databasePath)); + + endResetModel(); +} + +QList ComicModel::createRecentModelData(const QString &databasePath) const +{ + QList modelData; + QString connectionName = ""; { QSqlDatabase db = DataBaseManagement::loadDatabase(databasePath); @@ -646,15 +718,37 @@ void ComicModel::setupRecentModelData(const QString &databasePath) selectQuery.bindValue(":limit", QDateTime::currentDateTime().addDays(-recentDays).toSecsSinceEpoch()); selectQuery.exec(); - setupModelDataForList(selectQuery); + modelData = createModelDataForList(selectQuery); connectionName = db.connectionName(); } QSqlDatabase::removeDatabase(connectionName); + + return modelData; +} + +void ComicModel::setupRecentModelData(const QString &databasePath) +{ + enableResorting = false; + mode = Recent; + sourceId = -1; + + beginResetModel(); + qDeleteAll(_data); + _data.clear(); + + _databasePath = databasePath; + + takeData(createRecentModelData(databasePath)); + endResetModel(); } void ComicModel::setModelData(QList *data, const QString &databasePath) { + enableResorting = false; + mode = SearchResult; + sourceId = -1; + _databasePath = databasePath; beginResetModel(); @@ -679,8 +773,10 @@ QString ComicModel::getComicPath(QModelIndex mi) return ""; } -void ComicModel::setupModelData(QSqlQuery &sqlquery) +QList ComicModel::createModelData(QSqlQuery &sqlquery) const { + QList modelData; + int numColumns = sqlquery.record().count(); while (sqlquery.next()) { @@ -689,25 +785,19 @@ void ComicModel::setupModelData(QSqlQuery &sqlquery) for (int i = 0; i < numColumns; i++) data << sqlquery.value(i); - _data.append(new ComicItem(data)); + modelData.append(new ComicItem(data)); } - std::sort(_data.begin(), _data.end(), [](const ComicItem *c1, const ComicItem *c2) { - if (c1->data(ComicModel::Number).isNull() && c2->data(ComicModel::Number).isNull()) { - return naturalSortLessThanCI(c1->data(ComicModel::FileName).toString(), c2->data(ComicModel::FileName).toString()); - } else { - if (c1->data(ComicModel::Number).isNull() == false && c2->data(ComicModel::Number).isNull() == false) { - return naturalSortLessThanCI(c1->data(ComicModel::Number).toString(), c2->data(ComicModel::Number).toString()); - } else { - return c2->data(ComicModel::Number).isNull(); - } - } - }); + std::sort(modelData.begin(), modelData.end(), defaultFolderContentSortFunction); + + return modelData; } -// comics are sorted by "ordering", the sorting is done in the sql query -void ComicModel::setupModelDataForList(QSqlQuery &sqlquery) +// the sorting is done in the sql query +QList ComicModel::createModelDataForList(QSqlQuery &sqlquery) const { + QList modelData; + int numColumns = sqlquery.record().count(); while (sqlquery.next()) { @@ -715,7 +805,92 @@ void ComicModel::setupModelDataForList(QSqlQuery &sqlquery) for (int i = 0; i < numColumns; i++) data << sqlquery.value(i); - _data.append(new ComicItem(data)); + modelData.append(new ComicItem(data)); + } + + return modelData; +} + +void ComicModel::takeData(const QList &data) +{ + qDeleteAll(_data); + _data = data; +} + +void ComicModel::takeUpdatedData(const QList &updatedData, std::function comparator) +{ + int lenght = _data.size(); + int lenghtUpdated = updatedData.size(); + + int i; // index of the internal data + int j; // index of the updated children + for (i = 0, j = 0; i < lenght && j < lenghtUpdated;) { + auto comic = _data.at(i); + auto updatedComic = updatedData.at(j); + + auto sameComic = comic->data(ComicModel::Id) == updatedComic->data(ComicModel::Id); + if (sameComic) { + if (comic->getData() != updatedComic->getData()) { + auto modelIndexToUpdate = index(i, 0, QModelIndex()); + + comic->setData(updatedComic->getData()); + + emit dataChanged(modelIndexToUpdate, modelIndexToUpdate); + } + + i++; + j++; + continue; + } + + auto lessThan = comparator(comic, updatedComic); + + // comic added + if (!lessThan) { + beginInsertRows(QModelIndex(), i, i); + + _data.insert(i, updatedComic); + + endInsertRows(); + + i++; + j++; + lenght++; + continue; + } + + // comic removed + if (lessThan) { + beginRemoveRows(QModelIndex(), i, i); + + _data.removeAt(i); + + endRemoveRows(); + + lenght--; + continue; + } + } + + // add remaining comics + for (; j < lenghtUpdated; j++) { + beginInsertRows(QModelIndex(), i, i); + + _data.append(updatedData.at(j)); + + endInsertRows(); + + i++; + } + + // remove remaining comics { + for (; i < lenght; i++) { + beginRemoveRows(QModelIndex(), i, i); + + delete _data.at(i); + _data.removeAt(i); + + endRemoveRows(); } } @@ -855,6 +1030,12 @@ void ComicModel::setComicsType(QList list, FileType type) connectionName = db.connectionName(); } QSqlDatabase::removeDatabase(connectionName); + + foreach (QModelIndex mi, list) { + _data.value(mi.row())->setData(ComicModel::Type, QVariant::fromValue(type)); + } + + emit dataChanged(index(list.first().row(), ComicModel::Type), index(list.last().row(), ComicModel::Type), QVector() << TypeRole); } qint64 ComicModel::asignNumbers(QList list, int startingNumber) @@ -929,6 +1110,7 @@ void ComicModel::removeInTransaction(int row) DBHelper::removeFromDB(&c, dbTransaction); beginRemoveRows(QModelIndex(), row, row); + removeRow(row); delete _data.at(row); _data.removeAt(row); @@ -941,26 +1123,34 @@ void ComicModel::reloadContinueReading() setupReadingModelData(_databasePath); } +// The `comparator` passed to `takeUpdatedData` is used to determine if a row has been removed or added void ComicModel::reload() { switch (mode) { case Folder: - setupFolderModelData(sourceId, _databasePath); + takeUpdatedData(createFolderModelData(sourceId, _databasePath), defaultFolderContentSortFunction); break; case Favorites: - setupFavoritesModelData(_databasePath); + setupFavoritesModelData(_databasePath); // TODO we need a comparator break; case Reading: - setupReadingModelData(_databasePath); + takeUpdatedData(createReadingModelData(_databasePath), [](const ComicItem *c1, const ComicItem *c2) { + return c1->data(ComicModel::LastTimeOpened).toDateTime() > c2->data(ComicModel::LastTimeOpened).toDateTime(); + }); break; case Recent: - setupRecentModelData(_databasePath); + takeUpdatedData(createRecentModelData(_databasePath), [](const ComicItem *c1, const ComicItem *c2) { + return c1->data(ComicModel::Added).toDateTime() > c2->data(ComicModel::Added).toDateTime(); + }); break; case Label: - setupLabelModelData(sourceId, _databasePath); + setupLabelModelData(sourceId, _databasePath); // TODO we need a comparator break; case ReadingList: - setupReadingListModelData(sourceId, _databasePath); + setupReadingListModelData(sourceId, _databasePath); // TODO we need a comparator + break; + case SearchResult: + // TODO: reload search results, we don't have a way to recreate the query in this class break; } } @@ -1005,9 +1195,29 @@ void ComicModel::resetComicRating(const QModelIndex &mi) QSqlDatabase::removeDatabase(connectionName); } +void ComicModel::notifyCoverChange(const ComicDB &comic) +{ + auto it = std::find_if(_data.begin(), _data.end(), [comic](ComicItem *item) { return item->data(ComicModel::Id).toULongLong() == comic.id; }); + auto itemIndex = std::distance(_data.begin(), it); + auto item = _data[itemIndex]; + + // emiting a dataChage doesn't work in QML for some reason, CoverPathRole is requested but the view doesn't update the image + // removing and reading again works with the flow views without any additional code, but it's not the best solution + beginRemoveRows(QModelIndex(), itemIndex, itemIndex); + _data.removeAt(itemIndex); + endRemoveRows(); + + beginInsertRows(QModelIndex(), itemIndex, itemIndex); + _data.insert(itemIndex, item); + endInsertRows(); + + // this doesn't work in QML -> emit dataChanged(index(itemIndex, 0), index(itemIndex, 0), QVector() << CoverPathRole); +} + +// ???? QUrl ComicModel::getCoverUrlPathForComicHash(const QString &hash) const { - return QUrl("file:" + _databasePath + "/covers/" + hash + ".jpg"); + return QUrl::fromLocalFile(_databasePath + "/covers/" + hash + ".jpg"); } void ComicModel::addComicsToFavorites(const QList &comicIds) @@ -1107,6 +1317,9 @@ void ComicModel::deleteComicsFromSpecialList(const QList &comicsLis case ReadingListModel::TypeSpecialList::Favorites: deleteComicsFromFavorites(comicsList); break; + case ReadingListModel::TypeSpecialList::Recent: + // do nothing, recent is read only + break; } } diff --git a/YACReaderLibrary/db/comic_model.h b/YACReaderLibrary/db/comic_model.h index 4b155e7ee..d82b8369a 100644 --- a/YACReaderLibrary/db/comic_model.h +++ b/YACReaderLibrary/db/comic_model.h @@ -23,21 +23,28 @@ class ComicModel : public QAbstractItemModel public: enum Columns { Number = 0, - Title = 1, - FileName = 2, - NumPages = 3, - Id = 4, - Parent_Id = 5, - Path = 6, - Hash = 7, - ReadColumn = 8, - IsBis = 9, // TODO_METADATA: Remove this column - CurrentPage = 10, - Rating = 11, - HasBeenOpened = 12, - PublicationDate = 13, - Added = 14, - Type = 15, + Title, + FileName, + NumPages, + Id, + Parent_Id, + Path, + Hash, + ReadColumn, + CurrentPage, + Rating, + HasBeenOpened, + PublicationDate, + Added, + Type, + LastTimeOpened, + Series, + Volume, + StoryArc, + }; + + enum CalculatedColumns { + Size = Columns::StoryArc + 1, }; enum Roles { @@ -50,7 +57,6 @@ class ComicModel : public QAbstractItemModel PathRole, HashRole, ReadColumnRole, - IsBisRole, CurrentPageRole, RatingRole, HasBeenOpenedRole, @@ -61,6 +67,10 @@ class ComicModel : public QAbstractItemModel TypeRole, ShowRecentRole, RecentRangeRole, + SizeRole, + SeriesRole, + VolumeRole, + StoryArcRole, }; enum Mode { @@ -69,12 +79,12 @@ class ComicModel : public QAbstractItemModel Reading, Recent, Label, - ReadingList + ReadingList, + SearchResult }; public: explicit ComicModel(QObject *parent = nullptr); - explicit ComicModel(QSqlQuery &sqlquery, QObject *parent = nullptr); ~ComicModel() override; QVariant data(const QModelIndex &index, int role) const override; @@ -123,6 +133,7 @@ class ComicModel : public QAbstractItemModel void reload(); void reload(const ComicDB &comic); void resetComicRating(const QModelIndex &mi); + void notifyCoverChange(const ComicDB &comic); Q_INVOKABLE QUrl getCoverUrlPathForComicHash(const QString &hash) const; @@ -162,8 +173,18 @@ public slots: protected: private: - void setupModelData(QSqlQuery &sqlquery); - void setupModelDataForList(QSqlQuery &sqlquery); + QList createModelData(QSqlQuery &sqlquery) const; + QList createModelDataForList(QSqlQuery &sqlquery) const; + + QList createFolderModelData(unsigned long long parentLabel, const QString &databasePath) const; + QList createLabelModelData(unsigned long long parentLabel, const QString &databasePath) const; + QList createReadingListData(unsigned long long parentReadingList, const QString &databasePath, bool &enableResorting) const; + QList createFavoritesModelData(const QString &databasePath) const; + QList createReadingModelData(const QString &databasePath) const; + QList createRecentModelData(const QString &databasePath) const; + + void takeData(const QList &data); + void takeUpdatedData(const QList &updatedData, std::function comparator); ComicDB _getComic(const QModelIndex &mi); QList _data; diff --git a/YACReaderLibrary/db/data_base_management.cpp b/YACReaderLibrary/db/data_base_management.cpp index c764f878e..18c6229c1 100644 --- a/YACReaderLibrary/db/data_base_management.cpp +++ b/YACReaderLibrary/db/data_base_management.cpp @@ -120,7 +120,10 @@ QSqlDatabase DataBaseManagement::createDatabase(QString dest) QSqlDatabase DataBaseManagement::loadDatabase(QString path) { - // TODO check path + if (!QFile::exists(path + "/library.ydb")) { + return QSqlDatabase(); + } + QString threadId = QString::number((long long)QThread::currentThreadId(), 16); QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", path + threadId); db.setDatabaseName(path + "/library.ydb"); @@ -134,7 +137,10 @@ QSqlDatabase DataBaseManagement::loadDatabase(QString path) QSqlDatabase DataBaseManagement::loadDatabaseFromFile(QString filePath) { - // TODO check path + if (!QFile::exists(filePath)) { + return QSqlDatabase(); + } + QString threadId = QString::number((long long)QThread::currentThreadId(), 16); QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", filePath + threadId); db.setDatabaseName(filePath); @@ -154,83 +160,7 @@ bool DataBaseManagement::createTables(QSqlDatabase &database) { // COMIC INFO (representa la información de un cómic, cada cómic tendrá un idéntificador único formado por un hash sha1'de los primeros 512kb' + su tamaño en bytes) - QSqlQuery queryComicInfo(database); - queryComicInfo.prepare("CREATE TABLE comic_info (" - "id INTEGER PRIMARY KEY," - "title TEXT," - - "coverPage INTEGER DEFAULT 1," - "numPages INTEGER," - - "number TEXT," // changed to text from INTEGER (9.13) - "isBis BOOLEAN," - "count INTEGER," - - "volume TEXT," - "storyArc TEXT," - "arcNumber TEXT," // changed to text from INTEGER (9.13) - "arcCount INTEGER," - - "genere TEXT," - - "writer TEXT," - "penciller TEXT," - "inker TEXT," - "colorist TEXT," - "letterer TEXT," - "coverArtist TEXT," - - "date TEXT," // publication date dd/mm/yyyy --> se mostrará en 3 campos diferentes - "publisher TEXT," - "format TEXT," - "color BOOLEAN," - "ageRating TEXT," - - "synopsis TEXT," - "characters TEXT," - "notes TEXT," - - "hash TEXT UNIQUE NOT NULL," - "edited BOOLEAN DEFAULT 0," - "read BOOLEAN DEFAULT 0," - // new 7.0 fields - - "hasBeenOpened BOOLEAN DEFAULT 0," - "rating INTEGER DEFAULT 0," // TODO_METADATA change type to REAL with two decimals - "currentPage INTEGER DEFAULT 1, " - "bookmark1 INTEGER DEFAULT -1, " - "bookmark2 INTEGER DEFAULT -1, " - "bookmark3 INTEGER DEFAULT -1, " - "brightness INTEGER DEFAULT -1, " - "contrast INTEGER DEFAULT -1, " - "gamma INTEGER DEFAULT -1, " - // new 7.1 fields - "comicVineID TEXT," - // new 9.5 fields - "lastTimeOpened INTEGER," - "coverSizeRatio REAL," - "originalCoverSize STRING," // h/w - // new 9.8 fields - "manga BOOLEAN DEFAULT 0," // deprecated 9.13 - // new 9.13 fields - "added INTEGER," - "type INTEGER DEFAULT 0," // 0 = comic, 1 = manga, 2 = manga left to right, 3 = webcomic, 4 = 4koma - "editor TEXT," - "imprint TEXT," - "teams TEXT," - "locations TEXT," - "series TEXT," - "alternateSeries TEXT," - "alternateNumber TEXT," - "alternateCount INTEGER," - "languageISO TEXT," - "seriesGroup TEXT," - "mainCharacterOrTeam TEXT," - "review TEXT," - "tags TEXT" - ")"); - success = success && queryComicInfo.exec(); - // queryComicInfo.finish(); + success = success && DataBaseManagement::createComicInfoTable(database, "comic_info"); // FOLDER (representa una carpeta en disco) QSqlQuery queryFolder(database); @@ -267,7 +197,7 @@ bool DataBaseManagement::createTables(QSqlDatabase &database) // queryDBInfo.finish(); QSqlQuery query("INSERT INTO db_info (version) " - "VALUES ('" VERSION "')", + "VALUES ('" DB_VERSION "')", database); // query.finish(); @@ -278,6 +208,87 @@ bool DataBaseManagement::createTables(QSqlDatabase &database) return success; } +bool DataBaseManagement::createComicInfoTable(QSqlDatabase &database, QString tableName) +{ + QSqlQuery queryComicInfo(database); + queryComicInfo.prepare("CREATE TABLE " + tableName + " (" + "id INTEGER PRIMARY KEY," + "title TEXT," + + "coverPage INTEGER DEFAULT 1," + "numPages INTEGER," + + "number TEXT," // changed to text from INTEGER (9.13) + "isBis BOOLEAN," + "count INTEGER," + + "volume TEXT," + "storyArc TEXT," + "arcNumber TEXT," // changed to text from INTEGER (9.13) + "arcCount INTEGER," + + "genere TEXT," + + "writer TEXT," + "penciller TEXT," + "inker TEXT," + "colorist TEXT," + "letterer TEXT," + "coverArtist TEXT," + + "date TEXT," // publication date dd/mm/yyyy --> se mostrará en 3 campos diferentes + "publisher TEXT," + "format TEXT," + "color BOOLEAN," + "ageRating TEXT," + + "synopsis TEXT," + "characters TEXT," + "notes TEXT," + + "hash TEXT UNIQUE NOT NULL," + "edited BOOLEAN DEFAULT 0," + "read BOOLEAN DEFAULT 0," + // new 7.0 fields + + "hasBeenOpened BOOLEAN DEFAULT 0," + "rating REAL DEFAULT 0," // changed to REAL from INTEGER (9.13) + "currentPage INTEGER DEFAULT 1, " + "bookmark1 INTEGER DEFAULT -1, " + "bookmark2 INTEGER DEFAULT -1, " + "bookmark3 INTEGER DEFAULT -1, " + "brightness INTEGER DEFAULT -1, " + "contrast INTEGER DEFAULT -1, " + "gamma INTEGER DEFAULT -1, " + // new 7.1 fields + "comicVineID TEXT," + // new 9.5 fields + "lastTimeOpened INTEGER," + "coverSizeRatio REAL," + "originalCoverSize STRING," // h/w + // new 9.8 fields + "manga BOOLEAN DEFAULT 0," // deprecated 9.13 + // new 9.13 fields + "added INTEGER," + "type INTEGER DEFAULT 0," // 0 = comic, 1 = manga, 2 = manga left to right, 3 = webcomic, 4 = 4koma + "editor TEXT," + "imprint TEXT," + "teams TEXT," + "locations TEXT," + "series TEXT," + "alternateSeries TEXT," + "alternateNumber TEXT," + "alternateCount INTEGER," + "languageISO TEXT," + "seriesGroup TEXT," + "mainCharacterOrTeam TEXT," + "review TEXT," + "tags TEXT" + ")"); + + return queryComicInfo.exec(); +} + bool DataBaseManagement::createV8Tables(QSqlDatabase &database) { bool success = true; @@ -387,7 +398,7 @@ void DataBaseManagement::exportComicsInfo(QString source, QString dest) queryDBInfo.exec(); QSqlQuery query("INSERT INTO dest.db_info (version) " - "VALUES ('" VERSION "')", + "VALUES ('" DB_VERSION "')", destDB); query.exec(); @@ -401,6 +412,7 @@ void DataBaseManagement::exportComicsInfo(QString source, QString dest) QSqlDatabase::removeDatabase(connectionName); } +// TODO_METADATA: validate imported info bool DataBaseManagement::importComicsInfo(QString source, QString dest) { QString error; @@ -847,6 +859,7 @@ bool DataBaseManagement::updateToCurrentVersion(const QString &path) bool pre9_5 = false; bool pre9_8 = false; bool pre9_13 = false; + bool pre9_14 = false; QString fullPath = path + "/library.ydb"; @@ -862,22 +875,15 @@ bool DataBaseManagement::updateToCurrentVersion(const QString &path) pre9_8 = true; if (compareVersions(DataBaseManagement::checkValidDB(fullPath), "9.13.0") < 0) pre9_13 = true; + if (compareVersions(DataBaseManagement::checkValidDB(fullPath), "9.14.0") < 0) + pre9_14 = true; QString connectionName = ""; - bool returnValue = false; + bool returnValue = true; { QSqlDatabase db = loadDatabaseFromFile(fullPath); if (db.isValid() && db.isOpen()) { - QSqlQuery updateVersion(db); - updateVersion.prepare("UPDATE db_info SET " - "version = :version"); - updateVersion.bindValue(":version", VERSION); - updateVersion.exec(); - - if (updateVersion.numRowsAffected() > 0) - returnValue = true; - if (pre7) // TODO: execute only if previous version was < 7.0 { // new 7.0 fields @@ -1034,6 +1040,52 @@ bool DataBaseManagement::updateToCurrentVersion(const QString &path) returnValue = returnValue && successMigratingManga; } } + + // ensure that INTEGER types migrated to TEXT are actually changed in the table definition to avoid internal type castings, this happened in 9.13 but a migration wasn't shipped with that version. + if (pre9_14) { + { + bool pre9_14_successfulMigration = true; + + QSqlQuery pragmaFKOFF(db); + pragmaFKOFF.prepare("PRAGMA foreign_keys=OFF"); + pre9_14_successfulMigration = pre9_14_successfulMigration && pragmaFKOFF.exec(); + + db.transaction(); + + pre9_14_successfulMigration = pre9_14_successfulMigration && createComicInfoTable(db, "comic_info_migration"); + + QSqlQuery copyComicInfoToComicInfoMigration(db); + copyComicInfoToComicInfoMigration.prepare("INSERT INTO comic_info_migration SELECT * FROM comic_info"); + pre9_14_successfulMigration = pre9_14_successfulMigration && copyComicInfoToComicInfoMigration.exec(); + + QSqlQuery dropComicInfo(db); + dropComicInfo.prepare("DROP TABLE comic_info"); + pre9_14_successfulMigration = pre9_14_successfulMigration && dropComicInfo.exec(); + + QSqlQuery renameComicInfoMigrationToComicInfo(db); + renameComicInfoMigrationToComicInfo.prepare("ALTER TABLE comic_info_migration RENAME TO comic_info"); + pre9_14_successfulMigration = pre9_14_successfulMigration && renameComicInfoMigrationToComicInfo.exec(); + + if (pre9_14_successfulMigration) + db.commit(); + else + db.rollback(); + + QSqlQuery pragmaFKON1("PRAGMA foreign_keys=ON", db); + + returnValue = returnValue && pre9_14_successfulMigration; + } + } + + if (returnValue) { + QSqlQuery updateVersion(db); + updateVersion.prepare("UPDATE db_info SET " + "version = :version"); + updateVersion.bindValue(":version", DB_VERSION); + updateVersion.exec(); + + returnValue = updateVersion.numRowsAffected() > 0; + } } connectionName = db.connectionName(); } diff --git a/YACReaderLibrary/db/data_base_management.h b/YACReaderLibrary/db/data_base_management.h index 293021622..e24505020 100644 --- a/YACReaderLibrary/db/data_base_management.h +++ b/YACReaderLibrary/db/data_base_management.h @@ -49,6 +49,7 @@ class DataBaseManagement : public QObject static QSqlDatabase loadDatabase(QString path); static QSqlDatabase loadDatabaseFromFile(QString path); static bool createTables(QSqlDatabase &database); + static bool createComicInfoTable(QSqlDatabase &database, QString tableName); static bool createV8Tables(QSqlDatabase &database); static void exportComicsInfo(QString source, QString dest); diff --git a/YACReaderLibrary/db/folder_item.cpp b/YACReaderLibrary/db/folder_item.cpp index 9444d3fdc..3b54f13b2 100644 --- a/YACReaderLibrary/db/folder_item.cpp +++ b/YACReaderLibrary/db/folder_item.cpp @@ -22,14 +22,14 @@ void FolderItem::appendChild(FolderItem *item) childItems.append(item); else { FolderItem *last = childItems.back(); - QString nameLast = last->data(1).toString(); // TODO usar info name si est� disponible, sino el nombre del fichero..... - QString nameCurrent = item->data(1).toString(); + QString nameLast = last->data(0).toString(); // TODO usar info name si est� disponible, sino el nombre del fichero..... + QString nameCurrent = item->data(0).toString(); QList::iterator i; i = childItems.end(); i--; while (naturalSortLessThanCI(nameCurrent, nameLast) && i != childItems.begin()) { i--; - nameLast = (*i)->data(1).toString(); + nameLast = (*i)->data(0).toString(); } if (!naturalSortLessThanCI(nameCurrent, nameLast)) // si se ha encontrado un elemento menor que current, se inserta justo despu�s childItems.insert(++i, item); @@ -65,6 +65,17 @@ void FolderItem::setData(int column, const QVariant &value) itemData[column] = value; } +void FolderItem::addChild(FolderItem *child, int childIndex) +{ + child->parentItem = this; + childItems.insert(childIndex, child); +} + +void FolderItem::removeChild(FolderItem *child) +{ + childItems.removeOne(child); +} + void FolderItem::removeChild(int childIndex) { childItems.removeAt(childIndex); @@ -86,6 +97,11 @@ FolderItem *FolderItem::parent() return parentItem; } +void FolderItem::setData(const QList &data) +{ + itemData = data; +} + int FolderItem::row() const { if (parentItem) diff --git a/YACReaderLibrary/db/folder_item.h b/YACReaderLibrary/db/folder_item.h index 2cc4bd459..ef77c4d9b 100644 --- a/YACReaderLibrary/db/folder_item.h +++ b/YACReaderLibrary/db/folder_item.h @@ -64,7 +64,10 @@ class FolderItem unsigned long long int id; QList comicNames; FolderItem *originalItem; + void setData(const QList &data); void setData(int column, const QVariant &value); + void addChild(FolderItem *child, int childIndex); + void removeChild(FolderItem *child); void removeChild(int childIndex); void clearChildren(); QList children(); diff --git a/YACReaderLibrary/db/folder_model.cpp b/YACReaderLibrary/db/folder_model.cpp index 0eec1c270..ba7fdccea 100644 --- a/YACReaderLibrary/db/folder_model.cpp +++ b/YACReaderLibrary/db/folder_model.cpp @@ -53,20 +53,20 @@ void drawMacOSXFinishedFolderIcon() #define ROOT 1 -FolderModel::FolderModel(QObject *parent) - : QAbstractItemModel(parent), isSubfolder(false), rootItem(nullptr), folderIcon(YACReader::noHighlightedIcon(":/images/sidebar/folder.svg")), folderFinishedIcon(YACReader::noHighlightedIcon(":/images/sidebar/folder_finished.svg")), showRecent(false), recentDays(1) +FolderItem *createRoot() { + QList rootData; + rootData << "root"; + auto root = new FolderItem(rootData); + root->id = ROOT; + root->parentItem = nullptr; + + return root; } -FolderModel::FolderModel(QSqlQuery &sqlquery, QObject *parent) - : QAbstractItemModel(parent), isSubfolder(false), rootItem(nullptr), showRecent(false), recentDays(1) +FolderModel::FolderModel(QObject *parent) + : QAbstractItemModel(parent), isSubfolder(false), rootItem(nullptr), folderIcon(YACReader::noHighlightedIcon(":/images/sidebar/folder.svg")), folderFinishedIcon(YACReader::noHighlightedIcon(":/images/sidebar/folder_finished.svg")), showRecent(false), recentDays(1) { - QList rootData; - rootData << "root"; // id 1, parent 1, title "root" - rootItem = new FolderItem(rootData); - rootItem->id = ROOT; - rootItem->parentItem = nullptr; - setupModelData(sqlquery, rootItem); } FolderModel::~FolderModel() @@ -108,13 +108,150 @@ QHash FolderModel::roleNames() const void FolderModel::reload() { - setupModelData(_databasePath); + if (rootItem == nullptr) + return; + + if (!isSubfolder) { + auto newModelData = createModelData(_databasePath); + + takeUpdatedChildrenInfo(rootItem, QModelIndex(), newModelData.rootItem); + + // copy items from newModelData to this model that are not in this model + foreach (auto key, newModelData.items.keys()) { + if (!items.contains(key)) { + items[key] = (newModelData.items[key]); + } + } + + delete newModelData.rootItem; + } else { + QString connectionName = ""; + { + QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); + + QSqlQuery selectQuery(db); + selectQuery.prepare("SELECT * FROM folder WHERE parentId = :parentId and id <> 1"); + selectQuery.bindValue(":parentId", rootItem->id); + selectQuery.exec(); + + auto tempRoot = new FolderItem(rootItem->getData(), rootItem->parentItem); + tempRoot->id = rootItem->id; + auto newModelData = createModelData(selectQuery, tempRoot); + takeUpdatedChildrenInfo(rootItem, QModelIndex(), newModelData.rootItem); + + items = newModelData.items; + + // copy items from newModelData to this model that are not in this model + foreach (auto key, newModelData.items.keys()) { + if (!items.contains(key)) { + items[key] = (newModelData.items[key]); + } + } + + delete newModelData.rootItem; + + connectionName = db.connectionName(); + } + QSqlDatabase::removeDatabase(connectionName); + } +} + +void FolderModel::takeUpdatedChildrenInfo(FolderItem *parent, const QModelIndex &parentModelIndex, FolderItem *updated) +{ + auto currentChildren = parent->children(); + auto updatedChildren = updated->children(); + + int lenght = currentChildren.size(); + int lenghtUpdated = updatedChildren.size(); + + int m; // index that reflects modifications on the actual model for this parent + int i; // index of the original children before update + int j; // index of the updated children + for (m = 0, i = 0, j = 0; (i < lenght) && (j < lenghtUpdated);) { + auto child = currentChildren[i]; + auto updatedChild = updatedChildren[j]; + + // same folder + auto sameFolderId = child->id == updatedChild->id; // and also same name + if (sameFolderId) { + // 1. check if child data needs to be udpated + if (child->getData() != updatedChild->getData()) { + auto modelIndexToUpdate = index(m, 0, parentModelIndex); + + child->setData(updatedChild->getData()); + + emit dataChanged(modelIndexToUpdate, modelIndexToUpdate); + } + + // 2. update children info + takeUpdatedChildrenInfo(child, index(m, 0, parentModelIndex), updatedChild); + + m++; + i++; + j++; + continue; + } + + auto childName = child->data(Name).toString(); + auto childUpdatedName = updatedChild->data(Name).toString(); + + // folder added + if (!naturalSortLessThanCI(childName, childUpdatedName)) { + beginInsertRows(parentModelIndex, m, m); + + parent->addChild(updatedChild, m); + updated->removeChild(updatedChild); + + endInsertRows(); + + m++; + j++; + continue; + } + + // folder removed + if (naturalSortLessThanCI(childName, childUpdatedName)) { + beginRemoveRows(parentModelIndex, m, m); + + delete parent->child(m); + parent->removeChild(m); + + endRemoveRows(); + + i++; + continue; + } + } + + // add remaining children + for (; j < lenghtUpdated; j++) { + auto updatedChild = updatedChildren[j]; + + beginInsertRows(parentModelIndex, m, m); + + parent->addChild(updatedChild, m); + updated->removeChild(updatedChild); + + endInsertRows(); + + m++; + } + + // remove remaining children + for (; i < lenght; i++) { + beginRemoveRows(parentModelIndex, m, m); + + delete parent->child(m); + parent->removeChild(m); + + endRemoveRows(); + } } void FolderModel::reload(const QModelIndex &index) { // TODO: reload just the content under index for better efficiency - setupModelData(_databasePath); + reload(); } QVariant FolderModel::data(const QModelIndex &index, int role) const @@ -290,48 +427,49 @@ int FolderModel::rowCount(const QModelIndex &parent) const void FolderModel::setupModelData(QString path) { beginResetModel(); + if (rootItem != nullptr) delete rootItem; // TODO comprobar que se libera bien la memoria rootItem = nullptr; + _databasePath = path; - // inicializar el nodo ra�z - QList rootData; - rootData << "root"; // id 0, padre 0, title "root" (el id, y el id del padre van a ir en la clase TreeItem) - rootItem = new FolderItem(rootData); - rootItem->id = ROOT; - rootItem->parentItem = nullptr; + setModelData(createModelData(path)); + + endResetModel(); +} + +void FolderModel::setModelData(const ModelData &modelData) +{ + rootItem = modelData.rootItem; + items = modelData.items; +} + +FolderModel::ModelData FolderModel::createModelData(const QString &path) const +{ + ModelData modelData; - // cargar la base de datos - _databasePath = path; - // crear la consulta QString connectionName = ""; { QSqlDatabase db = DataBaseManagement::loadDatabase(path); QSqlQuery selectQuery("select * from folder where id <> 1 order by parentId,name", db); - setupModelData(selectQuery, rootItem); + auto root = createRoot(); + modelData = createModelData(selectQuery, root); + connectionName = db.connectionName(); } - // selectQuery.finish(); QSqlDatabase::removeDatabase(connectionName); - endResetModel(); -} -void FolderModel::fullSetup(QSqlQuery &sqlquery, FolderItem *parent) -{ - rootItem = parent; - - setupModelData(sqlquery, parent); + return modelData; } -void FolderModel::setupModelData(QSqlQuery &sqlquery, FolderItem *parent) +FolderModel::ModelData FolderModel::createModelData(QSqlQuery &sqlquery, FolderItem *parent) const { - // 64 bits para la primary key, es decir la misma precisi�n que soporta sqlit 2^64 - // el diccionario permitir� encontrar cualquier nodo del �rbol r�pidamente, de forma que a�adir un hijo a un padre sea O(1) - items.clear(); - // se a�ade el nodo 0 - items.insert(parent->id, parent); + QMap itemsLookup; + + // add parent to the lookup + itemsLookup.insert(parent->id, parent); QSqlRecord record = sqlquery.record(); @@ -366,11 +504,13 @@ void FolderModel::setupModelData(QSqlQuery &sqlquery, FolderItem *parent) item->id = sqlquery.value(id).toULongLong(); // la inserci�n de hijos se hace de forma ordenada - FolderItem *parent = items.value(sqlquery.value(parentId).toULongLong()); + FolderItem *parent = itemsLookup.value(sqlquery.value(parentId).toULongLong()); parent->appendChild(item); // se a�ade el item al map, de forma que se pueda encontrar como padre en siguientes iteraciones - items.insert(item->id, item); + itemsLookup.insert(item->id, item); } + + return FolderModel::ModelData { parent, itemsLookup }; } QString FolderModel::getDatabase() @@ -518,7 +658,7 @@ FolderModel *FolderModel::getSubfoldersModel(const QModelIndex &mi) selectQuery.exec(); if (parent != nullptr) { - model->fullSetup(selectQuery, parent); + model->setModelData(createModelData(selectQuery, parent)); } connectionName = db.connectionName(); @@ -553,7 +693,7 @@ Folder FolderModel::getFolder(const QModelIndex &mi) return folder; } -QModelIndex FolderModel::getIndexFromFolder(const Folder &folder, const QModelIndex &parent) +QModelIndex FolderModel::getIndexFromFolderId(qulonglong folderId, const QModelIndex &parent) { if (rootItem == nullptr) { return QModelIndex(); @@ -566,16 +706,16 @@ QModelIndex FolderModel::getIndexFromFolder(const Folder &folder, const QModelIn if (modelIndex.isValid()) { auto folderItem = static_cast(modelIndex.internalPointer()); - if (folderItem->id == folder.id) { + if (folderItem->id == folderId) { return modelIndex; } - auto childModelIndex = getIndexFromFolder(folder, modelIndex); + auto childModelIndex = getIndexFromFolderId(folderId, modelIndex); if (childModelIndex.isValid()) { auto folderItem = static_cast(childModelIndex.internalPointer()); - if (folderItem->id == folder.id) { + if (folderItem->id == folderId) { return childModelIndex; } } @@ -585,6 +725,11 @@ QModelIndex FolderModel::getIndexFromFolder(const Folder &folder, const QModelIn return QModelIndex(); } +QModelIndex FolderModel::getIndexFromFolder(const Folder &folder, const QModelIndex &parent) +{ + return getIndexFromFolderId(folder.id, parent); +} + QModelIndex FolderModel::addFolderAtParent(const QString &folderName, const QModelIndex &parent) { FolderItem *parentItem; @@ -639,7 +784,7 @@ QModelIndex FolderModel::addFolderAtParent(const QString &folderName, const QMod QUrl FolderModel::getCoverUrlPathForComicHash(const QString &hash) const { - return QUrl("file:" + _databasePath + "/covers/" + hash + ".jpg"); + return QUrl::fromLocalFile(_databasePath + "/covers/" + hash + ".jpg"); } void FolderModel::setShowRecent(bool showRecent) diff --git a/YACReaderLibrary/db/folder_model.h b/YACReaderLibrary/db/folder_model.h index eac85b3be..ee44d57cc 100644 --- a/YACReaderLibrary/db/folder_model.h +++ b/YACReaderLibrary/db/folder_model.h @@ -44,7 +44,6 @@ class FolderModel : public QAbstractItemModel public: explicit FolderModel(QObject *parent = nullptr); - explicit FolderModel(QSqlQuery &sqlquery, QObject *parent = nullptr); ~FolderModel() override; // QAbstractItemModel methods @@ -72,9 +71,10 @@ class FolderModel : public QAbstractItemModel void updateFolderType(const QModelIndexList &list, YACReader::FileType type); QStringList getSubfoldersNames(const QModelIndex &mi); - FolderModel *getSubfoldersModel(const QModelIndex &mi); + FolderModel *getSubfoldersModel(const QModelIndex &mi); // it creates a model that contains just the direct subfolders Folder getFolder(const QModelIndex &mi); + QModelIndex getIndexFromFolderId(qulonglong folderId, const QModelIndex &parent = QModelIndex()); QModelIndex getIndexFromFolder(const Folder &folder, const QModelIndex &parent = QModelIndex()); QModelIndex addFolderAtParent(const QString &folderName, const QModelIndex &parent); @@ -118,11 +118,20 @@ public slots: void updateFolderChildrenInfo(qulonglong folderId); private: - void fullSetup(QSqlQuery &sqlquery, FolderItem *parent); - void setupModelData(QSqlQuery &sqlquery, FolderItem *parent); + struct ModelData { + FolderItem *rootItem; // items tree + QMap items; // items lookup + }; + + void setModelData(const ModelData &modelData); + ModelData createModelData(const QString &path) const; + ModelData createModelData(QSqlQuery &sqlquery, FolderItem *parent) const; + + // parent contains the current data in the model (parentModelIndex is its index), updated contains fresh info loaded from the DB, + void takeUpdatedChildrenInfo(FolderItem *parent, const QModelIndex &parentModelIndex, FolderItem *updated); - FolderItem *rootItem; // el árbol - QMap items; // relación entre folders + FolderItem *rootItem; // items tree + QMap items; // items lookup QString _databasePath; diff --git a/YACReaderLibrary/db/folder_query_result_processor.cpp b/YACReaderLibrary/db/folder_query_result_processor.cpp index 41774eb27..ec276a592 100644 --- a/YACReaderLibrary/db/folder_query_result_processor.cpp +++ b/YACReaderLibrary/db/folder_query_result_processor.cpp @@ -60,22 +60,10 @@ void YACReader::FolderQueryResultProcessor::setupFilteredModelData(QSqlQuery &sq QSqlRecord record = sqlquery.record(); - int name = record.indexOf("name"); - int path = record.indexOf("path"); - int finished = record.indexOf("finished"); - int completed = record.indexOf("completed"); int parentIdIndex = record.indexOf("parentId"); - while (sqlquery.next()) { // se procesan todos los folders que cumplen con el filtro - // datos de la base de datos - QList data; - - data << sqlquery.value(name).toString(); - data << sqlquery.value(path).toString(); - data << sqlquery.value(finished).toBool(); - data << sqlquery.value(completed).toBool(); - - auto item = new FolderItem(data); + while (sqlquery.next()) { + auto item = new FolderItem(QList()); // no need for data, we just need the ids of the folders in the search result item->id = sqlquery.value(0).toULongLong(); // id del padre diff --git a/YACReaderLibrary/db/folder_query_result_processor.h b/YACReaderLibrary/db/folder_query_result_processor.h index 92d5aa34b..fd966aee8 100644 --- a/YACReaderLibrary/db/folder_query_result_processor.h +++ b/YACReaderLibrary/db/folder_query_result_processor.h @@ -3,7 +3,6 @@ #include -#include "yacreader_global.h" #include "concurrent_queue.h" class FolderItem; diff --git a/YACReaderLibrary/db_helper.cpp b/YACReaderLibrary/db_helper.cpp index b315a4467..1a3292331 100644 --- a/YACReaderLibrary/db_helper.cpp +++ b/YACReaderLibrary/db_helper.cpp @@ -189,6 +189,57 @@ QString DBHelper::getFolderName(qulonglong libraryId, qulonglong id) QSqlDatabase::removeDatabase(connectionName); return name; } + +Folder DBHelper::getFolder(qulonglong libraryId, qulonglong id) +{ + QString libraryPath = DBHelper::getLibraries().getPath(libraryId); + + Folder folder; + QString connectionName = ""; + + { + QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); + QSqlQuery selectQuery(db); // TODO check + selectQuery.prepare("SELECT * FROM folder WHERE id = :id"); + selectQuery.bindValue(":id", id); + selectQuery.exec(); + + auto record = selectQuery.record(); + + int name = record.indexOf("name"); + int path = record.indexOf("path"); + int finished = record.indexOf("finished"); + int completed = record.indexOf("completed"); + int id = record.indexOf("id"); + int parentId = record.indexOf("parentId"); + int numChildren = record.indexOf("numChildren"); + int firstChildHash = record.indexOf("firstChildHash"); + int customImage = record.indexOf("customImage"); + int type = record.indexOf("type"); + int added = record.indexOf("added"); + int updated = record.indexOf("updated"); + + if (selectQuery.next()) { + folder = Folder(selectQuery.value(id).toULongLong(), selectQuery.value(parentId).toULongLong(), selectQuery.value(name).toString(), selectQuery.value(path).toString()); + + folder.finished = selectQuery.value(finished).toBool(); + folder.completed = selectQuery.value(completed).toBool(); + if (!selectQuery.value(numChildren).isNull() && selectQuery.value(numChildren).isValid()) { + folder.numChildren = selectQuery.value(numChildren).toInt(); + } + folder.firstChildHash = selectQuery.value(firstChildHash).toString(); + folder.customImage = selectQuery.value(customImage).toString(); + folder.type = selectQuery.value(type).value(); + folder.added = selectQuery.value(added).toLongLong(); + folder.updated = selectQuery.value(updated).toLongLong(); + } + connectionName = db.connectionName(); + } + + QSqlDatabase::removeDatabase(connectionName); + return folder; +} + QList DBHelper::getLibrariesNames() { auto names = getLibraries().getNames(); @@ -292,7 +343,7 @@ QList DBHelper::getReading(qulonglong libraryId) { QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); QSqlQuery selectQuery(db); - selectQuery.prepare("SELECT c.id,c.parentId,c.fileName,ci.title,ci.currentPage,ci.numPages,ci.hash,ci.read,ci.coverSizeRatio " + selectQuery.prepare("SELECT c.id,c.parentId,c.fileName,ci.title,ci.currentPage,ci.numPages,ci.hash,ci.read,ci.coverSizeRatio,ci.number " "FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) " "WHERE ci.hasBeenOpened = 1 AND ci.read = 0 " "ORDER BY ci.lastTimeOpened DESC"); @@ -301,6 +352,7 @@ QList DBHelper::getReading(qulonglong libraryId) while (selectQuery.next()) { ComicDB comic; + // TODO: use QVariant when possible to keep nulls comic.id = selectQuery.value(0).toULongLong(); comic.parentId = selectQuery.value(1).toULongLong(); comic.name = selectQuery.value(2).toString(); @@ -310,6 +362,7 @@ QList DBHelper::getReading(qulonglong libraryId) comic.info.hash = selectQuery.value(6).toString(); comic.info.read = selectQuery.value(7).toBool(); comic.info.coverSizeRatio = selectQuery.value(8).toFloat(); + comic.info.number = selectQuery.value(9); list.append(comic); } @@ -911,6 +964,7 @@ void DBHelper::updateReadingRemoteProgress(const ComicInfo &comicInfo, QSqlDatab updateComicInfo.clear(); } +// server v1 void DBHelper::updateFromRemoteClient(qulonglong libraryId, const ComicInfo &comicInfo) { QString libraryPath = DBHelper::getLibraries().getPath(libraryId); @@ -944,47 +998,7 @@ void DBHelper::updateFromRemoteClient(qulonglong libraryId, const ComicInfo &com QSqlDatabase::removeDatabase(connectionName); } -void DBHelper::updateFromRemoteClientWithHash(const ComicInfo &comicInfo) -{ - YACReaderLibraries libraries = DBHelper::getLibraries(); - - QStringList names = libraries.getNames(); - QString connectionName = ""; - - foreach (QString name, names) { - QString libraryPath = DBHelper::getLibraries().getPath(libraries.getId(name)); - - { - QSqlDatabase db = DataBaseManagement::loadDatabase(libraryPath + "/.yacreaderlibrary"); - ComicInfo info = loadComicInfo(comicInfo.hash, db); - - if (!info.existOnDb) { - continue; - } - - if (comicInfo.currentPage > 0) { - info.currentPage = comicInfo.currentPage; - - if (info.currentPage == info.numPages) - info.read = true; - - info.hasBeenOpened = true; - - if (info.lastTimeOpened.toULongLong() < comicInfo.lastTimeOpened.toULongLong()) - info.lastTimeOpened = comicInfo.lastTimeOpened; - } - - if (comicInfo.rating > 0) - info.rating = comicInfo.rating; - - DBHelper::update(&info, db); - connectionName = db.connectionName(); - } - QSqlDatabase::removeDatabase(connectionName); - } -} - -QMap> DBHelper::updateFromRemoteClient(const QMap> &comics) +QMap> DBHelper::updateFromRemoteClient(const QMap> &comics, bool clientSendsHasBeenOpened) { QMap> moreRecentComics; @@ -1010,13 +1024,18 @@ QMap> DBHelper::updateFromRemoteClient(const QMap comicInfo.id contains comic id ComicDB comic = DBHelper::loadComic(comicInfo.id, db, found); if (comic.info.hash == comicInfo.hash) { bool isMoreRecent = false; // completion takes precedence over lastTimeOpened, if we just want to synchronize the lastest status we should use only lastTimeOpened - if ((comic.info.currentPage > 1 && comic.info.currentPage > comicInfo.currentPage) || comic.info.hasBeenOpened || (comic.info.read && !comicInfo.read)) { + if ((comic.info.currentPage > 1 && comic.info.currentPage > comicInfo.currentPage) || (comic.info.read && !comicInfo.read)) { + isMoreRecent = true; + } + + if (comic.info.hasBeenOpened && comic.info.currentPage > comicInfo.currentPage) { isMoreRecent = true; } @@ -1031,7 +1050,11 @@ QMap> DBHelper::updateFromRemoteClient(const QMap 0; + if (clientSendsHasBeenOpened) { + comic.info.hasBeenOpened = comic.info.hasBeenOpened || comicInfo.hasBeenOpened; // android + } else { + comic.info.hasBeenOpened = comic.info.hasBeenOpened || comicInfo.currentPage > 0; // ios (legacy) + } if (comic.info.lastTimeOpened.toULongLong() < comicInfo.lastTimeOpened.toULongLong() && comicInfo.lastTimeOpened.toULongLong() > 0) comic.info.lastTimeOpened = comicInfo.lastTimeOpened; @@ -1265,13 +1288,15 @@ qulonglong DBHelper::insert(ComicDB *comic, QSqlDatabase &db, bool insertAllInfo if (!comic->info.existOnDb) { QSqlQuery comicInfoInsert(db); - comicInfoInsert.prepare("INSERT INTO comic_info (hash,numPages,coverSizeRatio,originalCoverSize,added) " - "VALUES (:hash,:numPages,:coverSizeRatio,:originalCoverSize,:added)"); + comicInfoInsert.prepare("INSERT INTO comic_info (hash,numPages,coverSizeRatio,originalCoverSize,added,type) " + "VALUES (:hash,:numPages,:coverSizeRatio,:originalCoverSize,:added,:type)"); comicInfoInsert.bindValue(":hash", comic->info.hash); comicInfoInsert.bindValue(":numPages", comic->info.numPages); comicInfoInsert.bindValue(":coverSizeRatio", comic->info.coverSizeRatio); comicInfoInsert.bindValue(":originalCoverSize", comic->info.originalCoverSize); comicInfoInsert.bindValue(":added", added); + auto intType = static_cast(comic->info.type.value()); + comicInfoInsert.bindValue(":type", intType); comicInfoInsert.exec(); comic->info.id = comicInfoInsert.lastInsertId().toULongLong(); comic->info.added = added; @@ -1292,13 +1317,22 @@ qulonglong DBHelper::insert(ComicDB *comic, QSqlDatabase &db, bool insertAllInfo query.bindValue(":path", comic->path); query.exec(); + // loop through parents and update their updated field + // TODO: use stored procedures QSqlQuery updateFolder(db); updateFolder.prepare("UPDATE folder SET " "updated = :updated " "WHERE id = :id "); - updateFolder.bindValue(":updated", added); - updateFolder.bindValue(":id", comic->parentId); - updateFolder.exec(); + auto currentParentId = comic->parentId; + while (currentParentId != 1 && currentParentId != 0) { + updateFolder.bindValue(":updated", added); + updateFolder.bindValue(":id", currentParentId); + updateFolder.exec(); + + auto f = loadFolder(currentParentId, db); + currentParentId = f.parentId; + } + //---- return query.lastInsertId().toULongLong(); } diff --git a/YACReaderLibrary/db_helper.h b/YACReaderLibrary/db_helper.h index 5f0ace4c4..a843572c3 100644 --- a/YACReaderLibrary/db_helper.h +++ b/YACReaderLibrary/db_helper.h @@ -31,6 +31,7 @@ class DBHelper static ComicDB getComicInfo(qulonglong libraryId, qulonglong id); static QList getSiblings(qulonglong libraryId, qulonglong parentId); static QString getFolderName(qulonglong libraryId, qulonglong id); + static Folder getFolder(qulonglong libraryId, qulonglong id); static QList getLibrariesNames(); static QString getLibraryName(int id); static QList getLabelComics(qulonglong libraryId, qulonglong labelId); @@ -72,10 +73,9 @@ class DBHelper static void updateChildrenInfo(QSqlDatabase &db); static void updateProgress(qulonglong libraryId, const ComicInfo &comicInfo); static void setComicAsReading(qulonglong libraryId, const ComicInfo &comicInfo); - static void updateFromRemoteClient(qulonglong libraryId, const ComicInfo &comicInfo); - static void updateFromRemoteClientWithHash(const ComicInfo &comicInfo); + [[deprecated("Server v1")]] static void updateFromRemoteClient(qulonglong libraryId, const ComicInfo &comicInfo); static void updateReadingRemoteProgress(const ComicInfo &comicInfo, QSqlDatabase &db); - static QMap> updateFromRemoteClient(const QMap> &comics); + static QMap> updateFromRemoteClient(const QMap> &comics, bool clientSendsHasBeenOpened); static void updateFromRemoteClientWithHash(const QList &comics); static void renameLabel(qulonglong id, const QString &name, QSqlDatabase &db); static void renameList(qulonglong id, const QString &name, QSqlDatabase &db); diff --git a/YACReaderLibrary/folder_content_view.cpp b/YACReaderLibrary/folder_content_view.cpp index d546b91bf..822470594 100644 --- a/YACReaderLibrary/folder_content_view.cpp +++ b/YACReaderLibrary/folder_content_view.cpp @@ -203,6 +203,12 @@ void FolderContentView::setContinueReadingModel(ComicModel *model) } } +void FolderContentView::reloadContent() +{ + folderModel->reload(); + reloadContinueReadingModel(); +} + void FolderContentView::reloadContinueReadingModel() { if (!folderModel->isSubfolder) { diff --git a/YACReaderLibrary/folder_content_view.h b/YACReaderLibrary/folder_content_view.h index cebb548ae..d0f07e6a9 100644 --- a/YACReaderLibrary/folder_content_view.h +++ b/YACReaderLibrary/folder_content_view.h @@ -22,6 +22,7 @@ class FolderContentView : public QWidget explicit FolderContentView(QAction *toogleRecentVisibilityAction, QWidget *parent = nullptr); void setModel(const QModelIndex &parent, FolderModel *model); void setContinueReadingModel(ComicModel *model); + void reloadContent(); void reloadContinueReadingModel(); void setShowRecent(bool visible); void setRecentRange(int days); diff --git a/YACReaderLibrary/grid_comics_view.cpp b/YACReaderLibrary/grid_comics_view.cpp index c490e7759..1b6133530 100644 --- a/YACReaderLibrary/grid_comics_view.cpp +++ b/YACReaderLibrary/grid_comics_view.cpp @@ -493,6 +493,12 @@ void GridComicsView::focusComicsNavigation(Qt::FocusReason reason) view->setFocus(reason); } +void GridComicsView::reloadContent() +{ + ComicsView::reloadContent(); + updateCurrentComicView(); +} + void GridComicsView::startDrag() { auto drag = new QDrag(this); diff --git a/YACReaderLibrary/grid_comics_view.h b/YACReaderLibrary/grid_comics_view.h index 6b47c3a3d..6ae460a70 100644 --- a/YACReaderLibrary/grid_comics_view.h +++ b/YACReaderLibrary/grid_comics_view.h @@ -51,6 +51,7 @@ class GridComicsView : public ComicsView QByteArray getMimeDataFromSelection(); void updateCurrentComicView() override; void focusComicsNavigation(Qt::FocusReason reason) override; + void reloadContent() override; public slots: // ComicsView diff --git a/YACReaderLibrary/libraries_update_coordinator.cpp b/YACReaderLibrary/libraries_update_coordinator.cpp new file mode 100644 index 000000000..8252be461 --- /dev/null +++ b/YACReaderLibrary/libraries_update_coordinator.cpp @@ -0,0 +1,148 @@ + +#include "libraries_update_coordinator.h" + +#include "library_creator.h" +#include "yacreader_libraries.h" +#include "yacreader_global.h" + +LibrariesUpdateCoordinator::LibrariesUpdateCoordinator(QSettings *settings, YACReaderLibraries &libraries, const std::function &canStartUpdateProvider, QObject *parent) + : QObject(parent), libraries(libraries), canStartUpdateProvider(canStartUpdateProvider) +{ + libraries.load(); + + this->settings = settings; + + timer.setInterval(1000 * 60); + + connect(&timer, &QTimer::timeout, this, &LibrariesUpdateCoordinator::checkUpdatePolicy); +} + +void LibrariesUpdateCoordinator::init() +{ + timer.start(); + elapsedTimer.start(); + + if (settings->value(UPDATE_LIBRARIES_AT_STARTUP, false).toBool()) { + updateLibraries(); + } +} + +void LibrariesUpdateCoordinator::checkUpdatePolicy() +{ + if (settings->value(UPDATE_LIBRARIES_PERIODICALLY, false).toBool()) { + auto variant = settings->value(UPDATE_LIBRARIES_PERIODICALLY_INTERVAL, static_cast::type>(YACReader::LibrariesUpdateInterval::Hours2)); + + bool itIsDue = false; + auto interval = static_cast(variant.toInt()); + switch (interval) { + case YACReader::LibrariesUpdateInterval::Minutes30: + itIsDue = elapsedTimer.elapsed() >= 1000 * 60 * 30; + break; + case YACReader::LibrariesUpdateInterval::Hourly: + itIsDue = elapsedTimer.elapsed() >= 1000 * 60 * 60; + break; + case YACReader::LibrariesUpdateInterval::Hours2: + itIsDue = elapsedTimer.elapsed() >= 1000 * 60 * 60 * 2; + break; + case YACReader::LibrariesUpdateInterval::Hours4: + itIsDue = elapsedTimer.elapsed() >= 1000 * 60 * 60 * 4; + break; + case YACReader::LibrariesUpdateInterval::Hours8: + itIsDue = elapsedTimer.elapsed() >= 1000 * 60 * 60 * 8; + break; + case YACReader::LibrariesUpdateInterval::Hours12: + itIsDue = elapsedTimer.elapsed() >= 1000 * 60 * 60 * 12; + break; + case YACReader::LibrariesUpdateInterval::Daily: + itIsDue = elapsedTimer.elapsed() >= 1000 * 60 * 60 * 24; + break; + } + + if (itIsDue) { + elapsedTimer.restart(); + updateLibraries(); + return; + } + } + + if (settings->value(UPDATE_LIBRARIES_AT_CERTAIN_TIME, false).toBool()) { + QTime time = settings->value(UPDATE_LIBRARIES_AT_CERTAIN_TIME_TIME, "00:00").toTime(); + QTime currentTime = QTime::currentTime(); + + if (currentTime.hour() == time.hour() && currentTime.minute() == time.minute()) { + updateLibraries(); + return; + } + } +} + +void LibrariesUpdateCoordinator::updateLibraries() +{ + if (canStartUpdateProvider()) { + startUpdate(); + } +} + +bool LibrariesUpdateCoordinator::isRunning() const +{ + return updateFuture.valid() && updateFuture.wait_for(std::chrono::seconds(0)) != std::future_status::ready; +} + +void LibrariesUpdateCoordinator::startUpdate() +{ + if (updateFuture.valid() && updateFuture.wait_for(std::chrono::seconds(0)) != std::future_status::ready) { + return; + } + + canceled = false; + + updateFuture = std::async(std::launch::async, [this] { + emit updateStarted(); + for (auto library : libraries.getLibraries()) { + if (!canceled) { + updateLibrary(library.getPath()); + } + } + emit updateEnded(); + }); +} + +void LibrariesUpdateCoordinator::updateLibrary(const QString &path) +{ + QDir pathDir(path); + if (!pathDir.exists()) { + return; + } + + QEventLoop eventLoop; + auto libraryCreator = new LibraryCreator(settings); + std::shared_ptr sharedPtr(libraryCreator); + currentLibraryCreator = sharedPtr; + + QString cleanPath = QDir::cleanPath(pathDir.absolutePath()); + + libraryCreator->updateLibrary(cleanPath, QDir::cleanPath(pathDir.absolutePath() + "/.yacreaderlibrary")); + + connect(libraryCreator, &LibraryCreator::finished, &eventLoop, &QEventLoop::quit); + + libraryCreator->start(); + eventLoop.exec(); +} + +void LibrariesUpdateCoordinator::stop() +{ + canceled = true; + + if (auto libraryCreator = currentLibraryCreator.lock()) { + libraryCreator->stop(); + } +} + +void LibrariesUpdateCoordinator::cancel() +{ + canceled = true; + + if (auto libraryCreator = currentLibraryCreator.lock()) { + libraryCreator->cancel(); + } +} diff --git a/YACReaderLibrary/libraries_update_coordinator.h b/YACReaderLibrary/libraries_update_coordinator.h new file mode 100644 index 000000000..ae17977bf --- /dev/null +++ b/YACReaderLibrary/libraries_update_coordinator.h @@ -0,0 +1,45 @@ + +#ifndef LIBRARIES_UPDATE_COORDINATOR_H +#define LIBRARIES_UPDATE_COORDINATOR_H + +#include + +class YACReaderLibraries; +class LibraryCreator; + +class LibrariesUpdateCoordinator : public QObject +{ + Q_OBJECT +public: + LibrariesUpdateCoordinator(QSettings *settings, YACReaderLibraries &libraries, const std::function &canStartUpdateProvider, QObject *parent = 0); + + void init(); + void updateLibraries(); + bool isRunning() const; + +public slots: + void stop(); + void cancel(); + +signals: + void updateStarted(); + void updateEnded(); + +private slots: + void checkUpdatePolicy(); + void startUpdate(); + void updateLibrary(const QString &path); + +private: + QSettings *settings; + YACReaderLibraries &libraries; + QTimer timer; + QElapsedTimer elapsedTimer; + std::future updateFuture; + bool canceled; + std::weak_ptr currentLibraryCreator; + + std::function canStartUpdateProvider; +}; + +#endif // LIBRARIES_UPDATE_COORDINATOR_H diff --git a/YACReaderLibrary/library_comic_opener.cpp b/YACReaderLibrary/library_comic_opener.cpp index 0a4d3a02e..638cf9a18 100644 --- a/YACReaderLibrary/library_comic_opener.cpp +++ b/YACReaderLibrary/library_comic_opener.cpp @@ -34,8 +34,9 @@ bool YACReader::openComic(const ComicDB &comic, #endif #ifdef Q_OS_WIN + QString executablePath = QDir::cleanPath(QCoreApplication::applicationDirPath() + "/YACReader.exe"); QStringList parameters { path, QString("--comicId=%1").arg(comic.id), QString("--libraryId=%1").arg(libraryId), labelParam }; - yacreaderFound = QProcess::startDetached(QDir::cleanPath(QCoreApplication::applicationDirPath() + "/YACReader.exe"), parameters); + yacreaderFound = QProcess::startDetached(executablePath, parameters, QCoreApplication::applicationDirPath()); #endif #if defined Q_OS_UNIX && !defined Q_OS_MACOS diff --git a/YACReaderLibrary/library_creator.cpp b/YACReaderLibrary/library_creator.cpp index b517cda8f..c77ba1bba 100644 --- a/YACReaderLibrary/library_creator.cpp +++ b/YACReaderLibrary/library_creator.cpp @@ -42,7 +42,9 @@ void LibraryCreator::updateLibrary(const QString &source, const QString &target) { checkModifiedDatesOnUpdate = settings->value(COMPARE_MODIFIED_DATE_ON_LIBRARY_UPDATES, false).toBool(); partialUpdate = false; - processLibrary(source, target); + _source = source; + _target = target; + _mode = UPDATER; } void LibraryCreator::updateFolder(const QString &source, const QString &target, const QString &sourceFolder, const QModelIndex &dest) @@ -73,6 +75,14 @@ void LibraryCreator::updateFolder(const QString &source, const QString &target, { QSqlDatabase db = DataBaseManagement::loadDatabase(target); + if (!db.isValid()) { + QString error = "Unable to find database at: " + _target; + QLOG_ERROR() << error; + emit failedOpeningDB(error); + emit finished(); + return; + } + foreach (QString folderName, folders) { if (folderName.isEmpty()) { break; @@ -110,6 +120,7 @@ void LibraryCreator::processLibrary(const QString &source, const QString &target void LibraryCreator::run() { stopRunning = false; + canceled = false; #if !defined use_unarr && !defined use_libarchive // check for 7z lib #if defined Q_OS_UNIX && !defined Q_OS_MACOS @@ -167,11 +178,20 @@ void LibraryCreator::run() } { auto _database = DataBaseManagement::loadDatabase(_target); + + if (!_database.isValid()) { + QString error = "Unable to find database at: " + _target; + QLOG_ERROR() << error; + emit failedOpeningDB(error); + emit finished(); + return; + } + _databaseConnection = _database.connectionName(); //_database.setDatabaseName(_target+"/library.ydb"); if (!_database.open()) { - QLOG_ERROR() << "Unable to open data base" << _database.lastError().databaseText() + "-" + _database.lastError().driverText(); + QLOG_ERROR() << "Unable to open database" << _database.lastError().databaseText() + "-" + _database.lastError().driverText(); emit failedOpeningDB(_database.lastError().databaseText() + "-" + _database.lastError().driverText()); emit finished(); creation = false; @@ -187,13 +207,15 @@ void LibraryCreator::run() update(QDir(_source)); } - if (partialUpdate) { - auto folder = DBHelper::updateChildrenInfo(folderDestinationModelIndex.data(FolderModel::IdRole).toULongLong(), _database); - DBHelper::propagateFolderUpdatesToParent(folder, _database); - } else - DBHelper::updateChildrenInfo(_database); + if (!canceled) { + if (partialUpdate) { + auto folder = DBHelper::updateChildrenInfo(folderDestinationModelIndex.data(FolderModel::IdRole).toULongLong(), _database); + DBHelper::propagateFolderUpdatesToParent(folder, _database); + } else + DBHelper::updateChildrenInfo(_database); - _database.commit(); + _database.commit(); + } _database.close(); } @@ -209,12 +231,12 @@ void LibraryCreator::run() } QLOG_INFO() << "Update library END"; } - // msleep(100);//TODO try to solve the problem with the udpate dialog (ya no se usa más...) + if (partialUpdate) { emit updatedCurrentFolder(folderDestinationModelIndex); - emit finished(); - } else // TODO check this part!! - emit finished(); + } + + emit finished(); creation = false; } @@ -224,6 +246,13 @@ void LibraryCreator::stop() stopRunning = true; } +void LibraryCreator::cancel() +{ + QSqlDatabase::database(_databaseConnection).rollback(); + canceled = true; + stopRunning = true; +} + // retorna el id del ultimo de los folders qulonglong LibraryCreator::insertFolders() { @@ -332,7 +361,7 @@ void LibraryCreator::insertComic(const QString &relativePath, const QFileInfo &f } comic.parentId = _currentPathFolders.last().id; - comic.info.type = QVariant::fromValue(_currentPathFolders.last().type); // TODO_METADATA test this + comic.info.type = QVariant::fromValue(_currentPathFolders.last().type); DBHelper::insert(&comic, _database, parsed); } @@ -376,6 +405,10 @@ void LibraryCreator::replaceComic(const QString &relativePath, const QFileInfo & void LibraryCreator::update(QDir dirS) { + if (stopRunning) { + return; + } + auto _database = QSqlDatabase::database(_databaseConnection); // QLOG_TRACE() << "Updating" << dirS.absolutePath(); // QLOG_TRACE() << "Getting info from dir" << dirS.absolutePath(); diff --git a/YACReaderLibrary/library_creator.h b/YACReaderLibrary/library_creator.h index 4b6e9d5cd..84d82ea85 100644 --- a/YACReaderLibrary/library_creator.h +++ b/YACReaderLibrary/library_creator.h @@ -26,7 +26,8 @@ class LibraryCreator : public QThread void createLibrary(const QString &source, const QString &target); void updateLibrary(const QString &source, const QString &target); void updateFolder(const QString &source, const QString &target, const QString &folder, const QModelIndex &dest); - void stop(); + void stop(); // used to stop the process and keep the changes + void cancel(); // cancels this run and changes in the DB are rolled back private: void processLibrary(const QString &source, const QString &target); @@ -51,6 +52,7 @@ class LibraryCreator : public QThread // qulonglong insertFolder(qulonglong parentId,const Folder & folder); // qulonglong insertComic(const Comic & comic); bool stopRunning; + bool canceled; // LibraryCreator está en modo creación si creation == true; bool creation; bool partialUpdate; diff --git a/YACReaderLibrary/library_window.cpp b/YACReaderLibrary/library_window.cpp index 00690e5d4..3d0abfba9 100644 --- a/YACReaderLibrary/library_window.cpp +++ b/YACReaderLibrary/library_window.cpp @@ -502,6 +502,24 @@ void LibraryWindow::doModels() void LibraryWindow::setupCoordinators() { recentVisibilityCoordinator = new RecentVisibilityCoordinator(settings, foldersModel, contentViewsManager->folderContentView, comicsModel); + + auto canStartUpdateProvider = [this]() { + return comicVineDialog->isVisible() == false && + propertiesDialog->isVisible() == false; + }; + librariesUpdateCoordinator = new LibrariesUpdateCoordinator(settings, libraries, canStartUpdateProvider, this); + + connect(librariesUpdateCoordinator, &LibrariesUpdateCoordinator::updateStarted, sideBar->librariesTitle, &YACReaderTitledToolBar::showBusyIndicator); + connect(librariesUpdateCoordinator, &LibrariesUpdateCoordinator::updateEnded, sideBar->librariesTitle, &YACReaderTitledToolBar::hideBusyIndicator); + + connect(librariesUpdateCoordinator, &LibrariesUpdateCoordinator::updateStarted, this, [=]() { + disableAllActions(); + }); + connect(librariesUpdateCoordinator, &LibrariesUpdateCoordinator::updateEnded, this, &LibraryWindow::reloadCurrentLibrary); + + librariesUpdateCoordinator->init(); + + connect(sideBar->librariesTitle, &YACReaderTitledToolBar::cancelOperationRequested, librariesUpdateCoordinator, &LibrariesUpdateCoordinator::cancel); } void LibraryWindow::createActions() @@ -933,6 +951,11 @@ void LibraryWindow::createActions() } void LibraryWindow::disableComicsActions(bool disabled) { + if (!disabled && librariesUpdateCoordinator->isRunning()) { + disableComicsActions(true); + return; + } + // if there aren't comics, no fullscreen option will be available #ifndef Q_OS_MACOS toggleFullScreenAction->setDisabled(disabled); @@ -1283,10 +1306,13 @@ void LibraryWindow::createConnections() connect(importComicsInfoAction, &QAction::triggered, this, &LibraryWindow::showImportComicsInfo); // properties & config - connect(propertiesDialog, &QDialog::accepted, navigationController, &YACReaderNavigationController::reselectCurrentSource); + connect(propertiesDialog, &QDialog::accepted, contentViewsManager, &YACReaderContentViewsManager::updateCurrentContentView); + connect(propertiesDialog, &PropertiesDialog::coverChangedSignal, this, [=](const ComicDB &comic) { + comicsModel->notifyCoverChange(comic); + }); // comic vine - connect(comicVineDialog, &QDialog::accepted, navigationController, &YACReaderNavigationController::reselectCurrentSource, Qt::QueuedConnection); + connect(comicVineDialog, &QDialog::accepted, contentViewsManager, &YACReaderContentViewsManager::updateCurrentContentView, Qt::QueuedConnection); connect(updateLibraryAction, &QAction::triggered, this, &LibraryWindow::updateLibrary); connect(renameLibraryAction, &QAction::triggered, this, &LibraryWindow::renameLibrary); @@ -1420,7 +1446,7 @@ void LibraryWindow::loadLibrary(const QString &name) QString dbVersion; if (d.exists(path) && d.exists(path + "/library.ydb") && (dbVersion = DataBaseManagement::checkValidDB(path + "/library.ydb")) != "") // si existe en disco la biblioteca seleccionada, y es válida.. { - int comparation = DataBaseManagement::compareVersions(dbVersion, VERSION); + int comparation = DataBaseManagement::compareVersions(dbVersion, DB_VERSION); if (comparation < 0) { int ret = QMessageBox::question(this, tr("Update needed"), tr("This library was created with a previous version of YACReaderLibrary. It needs to be updated. Update now?"), QMessageBox::Yes, QMessageBox::No); @@ -1698,15 +1724,11 @@ void LibraryWindow::reloadAfterCopyMove(const QModelIndex &mi) if (item == nullptr) { foldersModel->reload(); - navigationController->loadFolderInfo(QModelIndex()); } else { - auto id = item->id; foldersModel->reload(mi); - auto newMi = foldersModel->index(id); - - foldersView->setCurrentIndex(foldersModelProxy->mapFromSource(newMi)); - navigationController->loadFolderInfo(newMi); } + + contentViewsManager->updateCurrentContentView(); } enableNeededActions(); @@ -1879,6 +1901,71 @@ void LibraryWindow::addSelectedComicsToFavorites() void LibraryWindow::showComicsViewContextMenu(const QPoint &point) { + showComicsContextMenu(point, true); +} + +void LibraryWindow::showComicsItemContextMenu(const QPoint &point) +{ + showComicsContextMenu(point, false); +} + +void LibraryWindow::showComicsContextMenu(const QPoint &point, bool showFullScreenAction) +{ + auto selection = this->getSelectedComics(); + + auto setNormalAction = new QAction(); + setNormalAction->setText(tr("comic")); + + auto setMangaAction = new QAction(); + setMangaAction->setText(tr("manga")); + + auto setWesternMangaAction = new QAction(); + setWesternMangaAction->setText(tr("western manga (left to right)")); + + auto setWebComicAction = new QAction(); + setWebComicAction->setText(tr("web comic")); + + auto setYonkomaAction = new QAction(); + setYonkomaAction->setText(tr("4koma (top to botom)")); + + setNormalAction->setCheckable(true); + setMangaAction->setCheckable(true); + setWesternMangaAction->setCheckable(true); + setWebComicAction->setCheckable(true); + setYonkomaAction->setCheckable(true); + + connect(setNormalAction, &QAction::triggered, this->setNormalAction, &QAction::trigger); + connect(setMangaAction, &QAction::triggered, this->setMangaAction, &QAction::trigger); + connect(setWesternMangaAction, &QAction::triggered, this->setWesternMangaAction, &QAction::trigger); + connect(setWebComicAction, &QAction::triggered, this->setWebComicAction, &QAction::trigger); + connect(setYonkomaAction, &QAction::triggered, this->setYonkomaAction, &QAction::trigger); + + auto setupActions = [=](FileType type) { + switch (type) { + case YACReader::FileType::Comic: + setNormalAction->setChecked(true); + break; + case YACReader::FileType::Manga: + setMangaAction->setChecked(true); + break; + case YACReader::FileType::WesternManga: + setWesternMangaAction->setChecked(true); + break; + case YACReader::FileType::WebComic: + setWebComicAction->setChecked(true); + break; + case YACReader::FileType::Yonkoma: + setYonkomaAction->setChecked(true); + break; + } + }; + + if (selection.size() == 1) { + QModelIndex index = selection.at(0); + auto type = index.data(ComicModel::TypeRole).value(); + setupActions(type); + } + QMenu menu; menu.addAction(openComicAction); @@ -1915,51 +2002,15 @@ void LibraryWindow::showComicsViewContextMenu(const QPoint &point) setupAddToSubmenu(subMenu); #ifndef Q_OS_MACOS - menu.addSeparator(); - menu.addAction(toggleFullScreenAction); + if (showFullScreenAction) { + menu.addSeparator(); + menu.addAction(toggleFullScreenAction); + } #endif menu.exec(contentViewsManager->comicsView->mapToGlobal(point)); } -void LibraryWindow::showComicsItemContextMenu(const QPoint &point) -{ - QMenu menu; - - menu.addAction(openComicAction); - menu.addAction(saveCoversToAction); - menu.addSeparator(); - menu.addAction(openContainingFolderComicAction); - menu.addAction(updateCurrentFolderAction); - menu.addSeparator(); - menu.addAction(resetComicRatingAction); - menu.addSeparator(); - menu.addAction(editSelectedComicsAction); - menu.addAction(getInfoAction); - menu.addAction(asignOrderAction); - menu.addSeparator(); - menu.addAction(setAsReadAction); - menu.addAction(setAsNonReadAction); - menu.addSeparator(); - auto typeMenu = new QMenu(tr("Set type")); - menu.addMenu(typeMenu); - typeMenu->addAction(setNormalAction); - typeMenu->addAction(setMangaAction); - typeMenu->addAction(setWesternMangaAction); - typeMenu->addAction(setWebComicAction); - typeMenu->addAction(setYonkomaAction); - menu.addSeparator(); - menu.addAction(deleteMetadataAction); - menu.addSeparator(); - menu.addAction(deleteComicsAction); - menu.addSeparator(); - menu.addAction(addToMenuAction); - QMenu subMenu; - setupAddToSubmenu(subMenu); - - menu.exec(contentViewsManager->comicsView->mapToGlobal(point)); -} - void LibraryWindow::showGridFoldersContextMenu(QPoint point, Folder folder) { QMenu menu; @@ -1992,13 +2043,13 @@ void LibraryWindow::showGridFoldersContextMenu(QPoint point, Folder folder) setFolderAsNormalAction->setText(tr("comic")); auto setFolderAsWesternMangaAction = new QAction(); - setFolderAsMangaAction->setText(tr("manga (or left to right)")); + setFolderAsWesternMangaAction->setText(tr("western manga (left to right)")); auto setFolderAsWebComicAction = new QAction(); - setFolderAsNormalAction->setText(tr("web comic")); + setFolderAsWebComicAction->setText(tr("web comic")); auto setFolderAs4KomaAction = new QAction(); - setFolderAsMangaAction->setText(tr("4koma (or top to botom")); + setFolderAs4KomaAction->setText(tr("4koma (top to botom)")); menu.addAction(openContainingFolderAction); menu.addAction(updateFolderAction); @@ -2016,6 +2067,30 @@ void LibraryWindow::showGridFoldersContextMenu(QPoint point, Folder folder) menu.addAction(setFolderAsReadAction); menu.addSeparator(); + setFolderAsNormalAction->setCheckable(true); + setFolderAsMangaAction->setCheckable(true); + setFolderAsWesternMangaAction->setCheckable(true); + setFolderAsWebComicAction->setCheckable(true); + setFolderAs4KomaAction->setCheckable(true); + + switch (folder.type) { + case FileType::Comic: + setFolderAsNormalAction->setChecked(true); + break; + case FileType::Manga: + setFolderAsMangaAction->setChecked(true); + break; + case FileType::WesternManga: + setFolderAsWesternMangaAction->setChecked(true); + break; + case FileType::WebComic: + setFolderAsWebComicAction->setChecked(true); + break; + case FileType::Yonkoma: + setFolderAs4KomaAction->setChecked(true); + break; + } + auto typeMenu = new QMenu(tr("Set type")); menu.addMenu(typeMenu); typeMenu->addAction(setFolderAsNormalAction); @@ -2270,8 +2345,10 @@ void LibraryWindow::create(QString source, QString dest, QString name) void LibraryWindow::reloadCurrentLibrary() { - qDebug() << "reloadCurrentLibrary"; - loadLibrary(selectedLibrary->currentText()); + foldersModel->reload(); + contentViewsManager->updateCurrentContentView(); + + enableNeededActions(); } void LibraryWindow::openLastCreated() @@ -2844,6 +2921,10 @@ void LibraryWindow::closeEvent(QCloseEvent *event) void LibraryWindow::prepareToCloseApp() { httpServer->stop(); + + libraryCreator->stop(); + librariesUpdateCoordinator->stop(); + settings->setValue(MAIN_WINDOW_GEOMETRY, saveGeometry()); contentViewsManager->comicsView->close(); @@ -3018,6 +3099,37 @@ void LibraryWindow::showFoldersContextMenu(const QPoint &point) bool isCompleted = sourceMI.data(FolderModel::CompletedRole).toBool(); bool isRead = sourceMI.data(FolderModel::FinishedRole).toBool(); + auto type = sourceMI.data(FolderModel::TypeRole).value(); + + setFolderAsNormalAction->setCheckable(true); + setFolderAsMangaAction->setCheckable(true); + setFolderAsWesternMangaAction->setCheckable(true); + setFolderAsWebComicAction->setCheckable(true); + setFolderAsYonkomaAction->setCheckable(true); + + setFolderAsNormalAction->setChecked(false); + setFolderAsMangaAction->setChecked(false); + setFolderAsWesternMangaAction->setChecked(false); + setFolderAsWebComicAction->setChecked(false); + setFolderAsYonkomaAction->setChecked(false); + + switch (type) { + case FileType::Comic: + setFolderAsNormalAction->setChecked(true); + break; + case FileType::Manga: + setFolderAsMangaAction->setChecked(true); + break; + case FileType::WesternManga: + setFolderAsWesternMangaAction->setChecked(true); + break; + case FileType::WebComic: + setFolderAsWebComicAction->setChecked(true); + break; + case FileType::Yonkoma: + setFolderAsYonkomaAction->setChecked(true); + break; + } QMenu menu; diff --git a/YACReaderLibrary/library_window.h b/YACReaderLibrary/library_window.h index d5b63e37f..95ae0b0ad 100644 --- a/YACReaderLibrary/library_window.h +++ b/YACReaderLibrary/library_window.h @@ -9,6 +9,7 @@ #include "yacreader_global.h" #include "yacreader_global_gui.h" #include "yacreader_libraries.h" +#include "libraries_update_coordinator.h" #include "yacreader_navigation_controller.h" #include "comic_query_result_processor.h" @@ -145,8 +146,9 @@ class LibraryWindow : public QMainWindow ComicModel *comicsModel; ReadingListModel *listsModel; ReadingListModelProxy *listsModelProxy; - // QStringList paths; + YACReaderLibraries libraries; + LibrariesUpdateCoordinator *librariesUpdateCoordinator; QStackedWidget *mainWidget; NoLibrariesWidget *noLibrariesWidget; @@ -314,7 +316,7 @@ class LibraryWindow : public QMainWindow QPoint _pos; protected: - virtual void closeEvent(QCloseEvent *event); + virtual void closeEvent(QCloseEvent *event) override; public: LibraryWindow(); @@ -423,6 +425,7 @@ public slots: void addSelectedComicsToFavorites(); void showComicsViewContextMenu(const QPoint &point); void showComicsItemContextMenu(const QPoint &point); + void showComicsContextMenu(const QPoint &point, bool showFullScreenAction); void setupAddToSubmenu(QMenu &menu); void onAddComicsToLabel(); void setToolbarTitle(const QModelIndex &modelIndex); diff --git a/YACReaderLibrary/main.cpp b/YACReaderLibrary/main.cpp index afedc607f..5aae101b4 100644 --- a/YACReaderLibrary/main.cpp +++ b/YACReaderLibrary/main.cpp @@ -38,8 +38,10 @@ using namespace QsLogging; void logSystemAndConfig() { QLOG_INFO() << "---------- System & configuration ----------"; + QLOG_INFO() << "YACReader version:" << VERSION; + QLOG_INFO() << "Qt version:" << qVersion(); QLOG_INFO() << "OS:" << QSysInfo::prettyProductName() << "Version: " << QSysInfo::productVersion(); - QLOG_INFO() << "Kernel:" << QSysInfo::kernelType() << QSysInfo::kernelVersion() << "Architecture:" << QSysInfo::currentCpuArchitecture(); + QLOG_INFO() << "Kernel:" << QSysInfo::kernelType() << QSysInfo::kernelVersion() << "Architecture:" << QSysInfo::currentCpuArchitecture() << "ABI:" << QSysInfo::buildAbi(); #if !defined use_unarr && !defined use_libarchive #ifdef Q_OS_WIN diff --git a/YACReaderLibrary/options_dialog.cpp b/YACReaderLibrary/options_dialog.cpp index 296f05afb..24eabb441 100644 --- a/YACReaderLibrary/options_dialog.cpp +++ b/YACReaderLibrary/options_dialog.cpp @@ -16,33 +16,133 @@ FlowType flowType = Strip; OptionsDialog::OptionsDialog(QWidget *parent) : YACReaderOptionsDialog(parent) { - auto tabWidget = new QTabWidget(); - - auto layout = new QVBoxLayout(this); - - auto flowLayout = new QVBoxLayout; - auto gridViewLayout = new QVBoxLayout(); - auto generalLayout = new QVBoxLayout(); + auto generalW = createGeneralTab(); + auto librariesW = createLibrariesTab(); + auto comicFlowW = createFlowTab(); + auto gridViewW = createGridTab(); - auto switchFlowType = new QHBoxLayout(); - switchFlowType->addStretch(); + auto tabWidget = new QTabWidget(); + tabWidget->addTab(generalW, tr("General")); + tabWidget->addTab(librariesW, tr("Libraries")); + tabWidget->addTab(comicFlowW, tr("Comic Flow")); #ifndef NO_OPENGL - switchFlowType->addWidget(useGL); + tabWidget->addTab(gridViewW, tr("Grid view")); #endif + auto buttons = new QHBoxLayout(); buttons->addStretch(); buttons->addWidget(accept); buttons->addWidget(cancel); - flowLayout->addWidget(sw); -#ifndef NO_OPENGL - flowLayout->addWidget(gl); -#endif - flowLayout->addLayout(switchFlowType); + auto layout = new QVBoxLayout(this); + layout->addWidget(tabWidget); + layout->addLayout(buttons); + setLayout(layout); + setModal(true); + setWindowTitle(tr("Options")); -#ifndef NO_OPENGL - sw->hide(); -#endif + this->layout()->setSizeConstraint(QLayout::SetFixedSize); +} + +void OptionsDialog::editApiKey() +{ + ApiKeyDialog d; + d.exec(); +} + +void OptionsDialog::restoreOptions(QSettings *settings) +{ + YACReaderOptionsDialog::restoreOptions(settings); + + trayIconCheckbox->setChecked(settings->value(CLOSE_TO_TRAY, false).toBool()); + startToTrayCheckbox->setChecked(settings->value(START_TO_TRAY, false).toBool()); + startToTrayCheckbox->setEnabled(trayIconCheckbox->isChecked()); + + comicInfoXMLCheckbox->setChecked(settings->value(IMPORT_COMIC_INFO_XML_METADATA, false).toBool()); + + recentIntervalSlider->setValue(settings->value(NUM_DAYS_TO_CONSIDER_RECENT, 1).toInt()); + + bool useBackgroundImage = settings->value(USE_BACKGROUND_IMAGE_IN_GRID_VIEW, true).toBool(); + + useBackgroundImageCheck->setChecked(useBackgroundImage); + backgroundImageOpacitySlider->setValue(settings->value(OPACITY_BACKGROUND_IMAGE_IN_GRID_VIEW, 0.2).toFloat() * 100); + backgroundImageBlurRadiusSlider->setValue(settings->value(BLUR_RADIUS_BACKGROUND_IMAGE_IN_GRID_VIEW, 75).toInt()); + useCurrentComicCoverCheck->setChecked(settings->value(USE_SELECTED_COMIC_COVER_AS_BACKGROUND_IMAGE_IN_GRID_VIEW, false).toBool()); + + backgroundImageOpacitySlider->setVisible(useBackgroundImage); + backgroundImageBlurRadiusSlider->setVisible(useBackgroundImage); + opacityLabel->setVisible(useBackgroundImage); + blurLabel->setVisible(useBackgroundImage); + useCurrentComicCoverCheck->setVisible(useBackgroundImage); + + displayContinueReadingBannerCheck->setChecked(settings->value(DISPLAY_CONTINUE_READING_IN_GRID_VIEW, true).toBool()); + + updateLibrariesAtStartupCheck->setChecked(settings->value(UPDATE_LIBRARIES_AT_STARTUP, false).toBool()); + detectChangesAutomaticallyCheck->setChecked(settings->value(DETECT_CHANGES_IN_LIBRARIES_AUTOMATICALLY, false).toBool()); + updateLibrariesPeriodicallyCheck->setChecked(settings->value(UPDATE_LIBRARIES_PERIODICALLY, false).toBool()); + intervalComboBox->setCurrentIndex(settings->value(UPDATE_LIBRARIES_PERIODICALLY_INTERVAL, static_cast::type>(LibrariesUpdateInterval::Hours2)).toInt()); + updateLibrariesAtCertainTimeCheck->setChecked(settings->value(UPDATE_LIBRARIES_AT_CERTAIN_TIME, false).toBool()); + updateLibrariesTimeEdit->setTime(settings->value(UPDATE_LIBRARIES_AT_CERTAIN_TIME_TIME, "00:00").toTime()); + + compareModifiedDateWhenUpdatingLibrariesCheck->setChecked(settings->value(COMPARE_MODIFIED_DATE_ON_LIBRARY_UPDATES, false).toBool()); +} + +void OptionsDialog::useBackgroundImageCheckClicked(bool checked) +{ + settings->setValue(USE_BACKGROUND_IMAGE_IN_GRID_VIEW, checked); + + backgroundImageOpacitySlider->setVisible(checked); + backgroundImageBlurRadiusSlider->setVisible(checked); + opacityLabel->setVisible(checked); + blurLabel->setVisible(checked); + useCurrentComicCoverCheck->setVisible(checked); + + emit optionsChanged(); +} + +void OptionsDialog::backgroundImageOpacitySliderChanged(int value) +{ + settings->setValue(OPACITY_BACKGROUND_IMAGE_IN_GRID_VIEW, value / 100.0); + + emit optionsChanged(); +} + +void OptionsDialog::backgroundImageBlurRadiusSliderChanged(int value) +{ + settings->setValue(BLUR_RADIUS_BACKGROUND_IMAGE_IN_GRID_VIEW, value); + + emit optionsChanged(); +} + +void OptionsDialog::useCurrentComicCoverCheckClicked(bool checked) +{ + settings->setValue(USE_SELECTED_COMIC_COVER_AS_BACKGROUND_IMAGE_IN_GRID_VIEW, checked); + + emit optionsChanged(); +} + +void OptionsDialog::numDaysToConsiderRecentChanged(int value) +{ + settings->setValue(NUM_DAYS_TO_CONSIDER_RECENT, value); + + numDaysLabel->setText(QString("%1").arg(value)); + + emit optionsChanged(); +} + +void OptionsDialog::resetToDefaults() +{ + settings->setValue(OPACITY_BACKGROUND_IMAGE_IN_GRID_VIEW, 0.2); + settings->setValue(BLUR_RADIUS_BACKGROUND_IMAGE_IN_GRID_VIEW, 75); + settings->setValue(USE_SELECTED_COMIC_COVER_AS_BACKGROUND_IMAGE_IN_GRID_VIEW, false); + + restoreOptions(settings); + + emit optionsChanged(); +} + +QWidget *OptionsDialog::createGeneralTab() +{ // Tray icon settings QGroupBox *trayIconBox = new QGroupBox(tr("Tray icon settings (experimental)")); QVBoxLayout *trayLayout = new QVBoxLayout(); @@ -76,7 +176,7 @@ OptionsDialog::OptionsDialog(QWidget *parent) auto comicInfoXMLBox = new QGroupBox(tr("ComicInfo.xml legacy support")); - comicInfoXMLCheckbox = new QCheckBox(tr("Import metada from ComicInfo.xml when adding new comics")); + comicInfoXMLCheckbox = new QCheckBox(tr("Import metadata from ComicInfo.xml when adding new comics")); connect(comicInfoXMLCheckbox, &QCheckBox::clicked, this, [=](bool checked) { settings->setValue(IMPORT_COMIC_INFO_XML_METADATA, checked); @@ -98,9 +198,97 @@ OptionsDialog::OptionsDialog(QWidget *parent) connect(recentIntervalSlider, &QAbstractSlider::valueChanged, this, &OptionsDialog::numDaysToConsiderRecentChanged); - auto libraryUpdatesBox = new QGroupBox(tr("Library update")); + auto generalLayout = new QVBoxLayout(); + generalLayout->addWidget(trayIconBox); + generalLayout->addWidget(shortcutsBox); + generalLayout->addWidget(apiKeyBox); + generalLayout->addWidget(comicInfoXMLBox); + generalLayout->addWidget(recentlyAddedBox); + generalLayout->addStretch(); + + auto generalW = new QWidget; + generalW->setLayout(generalLayout); + + return generalW; +} + +QWidget *OptionsDialog::createLibrariesTab() +{ + updateLibrariesAtStartupCheck = new QCheckBox(tr("Update libraries at startup")); + connect(updateLibrariesAtStartupCheck, &QCheckBox::clicked, this, + [=](bool checked) { + settings->setValue(UPDATE_LIBRARIES_AT_STARTUP, checked); + }); + detectChangesAutomaticallyCheck = new QCheckBox(tr("Try to detect changes automatically")); + connect(detectChangesAutomaticallyCheck, &QCheckBox::clicked, this, + [=](bool checked) { + settings->setValue(DETECT_CHANGES_IN_LIBRARIES_AUTOMATICALLY, checked); + }); + updateLibrariesPeriodicallyCheck = new QCheckBox(tr("Update libraries periodically")); + connect(updateLibrariesPeriodicallyCheck, &QCheckBox::clicked, this, + [=](bool checked) { + settings->setValue(UPDATE_LIBRARIES_PERIODICALLY, checked); + }); + + auto intervalLabel = new QLabel(tr("Interval:")); + intervalComboBox = new QComboBox; + intervalComboBox->addItem(tr("30 minutes"), static_cast::type>(LibrariesUpdateInterval::Minutes30)); + intervalComboBox->addItem(tr("1 hour"), static_cast::type>(LibrariesUpdateInterval::Hourly)); + intervalComboBox->addItem(tr("2 hours"), static_cast::type>(LibrariesUpdateInterval::Hours2)); + intervalComboBox->addItem(tr("4 hours"), static_cast::type>(LibrariesUpdateInterval::Hours4)); + intervalComboBox->addItem(tr("8 hours"), static_cast::type>(LibrariesUpdateInterval::Hours8)); + intervalComboBox->addItem(tr("12 hours"), static_cast::type>(LibrariesUpdateInterval::Hours12)); + intervalComboBox->addItem(tr("daily"), static_cast::type>(LibrariesUpdateInterval::Daily)); + + connect(intervalComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, + [=](int index) { + settings->setValue(UPDATE_LIBRARIES_PERIODICALLY_INTERVAL, index); + }); + + updateLibrariesAtCertainTimeCheck = new QCheckBox(tr("Update libraries at certain time")); + connect(updateLibrariesAtCertainTimeCheck, &QCheckBox::clicked, this, + [=](bool checked) { + settings->setValue(UPDATE_LIBRARIES_AT_CERTAIN_TIME, checked); + }); + + auto timeLabel = new QLabel(tr("Time:")); + updateLibrariesTimeEdit = new QTimeEdit; + updateLibrariesTimeEdit->setDisplayFormat("hh:mm"); + connect(updateLibrariesTimeEdit, &QTimeEdit::timeChanged, this, + [=](const QTime &time) { + settings->setValue(UPDATE_LIBRARIES_AT_CERTAIN_TIME_TIME, time.toString("hh:mm")); + }); + + auto updateLibrariesPeriodicallyLayout = new QHBoxLayout; + updateLibrariesPeriodicallyLayout->addWidget(intervalLabel); + updateLibrariesPeriodicallyLayout->addWidget(intervalComboBox); + updateLibrariesPeriodicallyLayout->addStretch(); + + auto updateLibrariesAtCertainTimeLayout = new QHBoxLayout; + updateLibrariesAtCertainTimeLayout->addWidget(timeLabel); + updateLibrariesAtCertainTimeLayout->addWidget(updateLibrariesTimeEdit); + updateLibrariesAtCertainTimeLayout->addStretch(); + + auto librariesBoxLayout = new QVBoxLayout(); + librariesBoxLayout->addWidget(updateLibrariesAtStartupCheck); + // TODO: try to use `QFileSystemWatcher` + // librariesBoxLayout->addWidget(detectChangesAutomaticallyCheck); + librariesBoxLayout->addWidget(updateLibrariesPeriodicallyCheck); + librariesBoxLayout->addLayout(updateLibrariesPeriodicallyLayout); + librariesBoxLayout->addWidget(updateLibrariesAtCertainTimeCheck); + librariesBoxLayout->addLayout(updateLibrariesAtCertainTimeLayout); - compareModifiedDateWhenUpdatingLibrariesCheck = new QCheckBox(tr("Compare the modified date of files when updating a library")); + librariesBoxLayout->addWidget(new QLabel(tr("WARNING! During library updates writes to the database are disabled!\n" + "Don't schedule updates while you may be using the app actively.\n" + "During automatic updates the app will block some of the actions until the update is finished.\n" + "To stop an automatic update tap on the loading indicator next to the Libraries title."))); + + auto librariesBox = new QGroupBox(tr("Libraries")); + librariesBox->setLayout(librariesBoxLayout); + + auto libraryModificationsBox = new QGroupBox(tr("Modifications detection")); + + compareModifiedDateWhenUpdatingLibrariesCheck = new QCheckBox(tr("Compare the modified date of files when updating a library (not recommended)")); connect(compareModifiedDateWhenUpdatingLibrariesCheck, &QCheckBox::clicked, this, [=](bool checked) { settings->setValue(COMPARE_MODIFIED_DATE_ON_LIBRARY_UPDATES, checked); @@ -108,8 +296,46 @@ OptionsDialog::OptionsDialog(QWidget *parent) auto libraryUpdatesBoxLayout = new QVBoxLayout(); libraryUpdatesBoxLayout->addWidget(compareModifiedDateWhenUpdatingLibrariesCheck); - libraryUpdatesBox->setLayout(libraryUpdatesBoxLayout); + libraryModificationsBox->setLayout(libraryUpdatesBoxLayout); + + auto layout = new QVBoxLayout(); + layout->addWidget(librariesBox); + layout->addWidget(libraryModificationsBox); + layout->addStretch(); + + auto librariesW = new QWidget; + librariesW->setLayout(layout); + + return librariesW; +} + +QWidget *OptionsDialog::createFlowTab() +{ + auto switchFlowType = new QHBoxLayout(); + switchFlowType->addStretch(); +#ifndef NO_OPENGL + switchFlowType->addWidget(useGL); +#endif + auto flowLayout = new QVBoxLayout; + flowLayout->addWidget(sw); +#ifndef NO_OPENGL + flowLayout->addWidget(gl); +#endif + flowLayout->addLayout(switchFlowType); + +#ifndef NO_OPENGL + sw->hide(); +#endif + + auto comicFlowW = new QWidget; + comicFlowW->setLayout(flowLayout); + + return comicFlowW; +} + +QWidget *OptionsDialog::createGridTab() +{ // grid view background config useBackgroundImageCheck = new QCheckBox(tr("Enable background image")); @@ -147,10 +373,6 @@ OptionsDialog::OptionsDialog(QWidget *parent) auto continueReadingGroup = new QGroupBox(tr("Continue reading")); continueReadingGroup->setLayout(continueReadingLayout); - gridViewLayout->addWidget(gridBackgroundGroup); - gridViewLayout->addWidget(continueReadingGroup); - gridViewLayout->addStretch(); - connect(useBackgroundImageCheck, &QAbstractButton::clicked, this, &OptionsDialog::useBackgroundImageCheckClicked); connect(backgroundImageOpacitySlider, &QAbstractSlider::valueChanged, this, &OptionsDialog::backgroundImageOpacitySliderChanged); connect(backgroundImageBlurRadiusSlider, &QAbstractSlider::valueChanged, this, &OptionsDialog::backgroundImageBlurRadiusSliderChanged); @@ -164,123 +386,13 @@ OptionsDialog::OptionsDialog(QWidget *parent) emit optionsChanged(); }); - auto comicFlowW = new QWidget; - comicFlowW->setLayout(flowLayout); + auto gridViewLayout = new QVBoxLayout(); + gridViewLayout->addWidget(gridBackgroundGroup); + gridViewLayout->addWidget(continueReadingGroup); + gridViewLayout->addStretch(); auto gridViewW = new QWidget; gridViewW->setLayout(gridViewLayout); - auto generalW = new QWidget; - generalW->setLayout(generalLayout); - generalLayout->addWidget(trayIconBox); - generalLayout->addWidget(shortcutsBox); - generalLayout->addWidget(apiKeyBox); - generalLayout->addWidget(comicInfoXMLBox); - generalLayout->addWidget(recentlyAddedBox); - generalLayout->addWidget(libraryUpdatesBox); - generalLayout->addStretch(); - - tabWidget->addTab(generalW, tr("General")); - tabWidget->addTab(comicFlowW, tr("Comic Flow")); -#ifndef NO_OPENGL - tabWidget->addTab(gridViewW, tr("Grid view")); -#endif - - layout->addWidget(tabWidget); - layout->addLayout(buttons); - setLayout(layout); - setModal(true); - setWindowTitle(tr("Options")); - - this->layout()->setSizeConstraint(QLayout::SetFixedSize); -} - -void OptionsDialog::editApiKey() -{ - ApiKeyDialog d; - d.exec(); -} - -void OptionsDialog::restoreOptions(QSettings *settings) -{ - YACReaderOptionsDialog::restoreOptions(settings); - - trayIconCheckbox->setChecked(settings->value(CLOSE_TO_TRAY, false).toBool()); - startToTrayCheckbox->setChecked(settings->value(START_TO_TRAY, false).toBool()); - startToTrayCheckbox->setEnabled(trayIconCheckbox->isChecked()); - - comicInfoXMLCheckbox->setChecked(settings->value(IMPORT_COMIC_INFO_XML_METADATA, false).toBool()); - - recentIntervalSlider->setValue(settings->value(NUM_DAYS_TO_CONSIDER_RECENT, 1).toInt()); - - compareModifiedDateWhenUpdatingLibrariesCheck->setChecked(settings->value(COMPARE_MODIFIED_DATE_ON_LIBRARY_UPDATES, false).toBool()); - - bool useBackgroundImage = settings->value(USE_BACKGROUND_IMAGE_IN_GRID_VIEW, true).toBool(); - - useBackgroundImageCheck->setChecked(useBackgroundImage); - backgroundImageOpacitySlider->setValue(settings->value(OPACITY_BACKGROUND_IMAGE_IN_GRID_VIEW, 0.2).toFloat() * 100); - backgroundImageBlurRadiusSlider->setValue(settings->value(BLUR_RADIUS_BACKGROUND_IMAGE_IN_GRID_VIEW, 75).toInt()); - useCurrentComicCoverCheck->setChecked(settings->value(USE_SELECTED_COMIC_COVER_AS_BACKGROUND_IMAGE_IN_GRID_VIEW, false).toBool()); - - backgroundImageOpacitySlider->setVisible(useBackgroundImage); - backgroundImageBlurRadiusSlider->setVisible(useBackgroundImage); - opacityLabel->setVisible(useBackgroundImage); - blurLabel->setVisible(useBackgroundImage); - useCurrentComicCoverCheck->setVisible(useBackgroundImage); - - displayContinueReadingBannerCheck->setChecked(settings->value(DISPLAY_CONTINUE_READING_IN_GRID_VIEW, true).toBool()); -} - -void OptionsDialog::useBackgroundImageCheckClicked(bool checked) -{ - settings->setValue(USE_BACKGROUND_IMAGE_IN_GRID_VIEW, checked); - - backgroundImageOpacitySlider->setVisible(checked); - backgroundImageBlurRadiusSlider->setVisible(checked); - opacityLabel->setVisible(checked); - blurLabel->setVisible(checked); - useCurrentComicCoverCheck->setVisible(checked); - - emit optionsChanged(); -} - -void OptionsDialog::backgroundImageOpacitySliderChanged(int value) -{ - settings->setValue(OPACITY_BACKGROUND_IMAGE_IN_GRID_VIEW, value / 100.0); - - emit optionsChanged(); -} - -void OptionsDialog::backgroundImageBlurRadiusSliderChanged(int value) -{ - settings->setValue(BLUR_RADIUS_BACKGROUND_IMAGE_IN_GRID_VIEW, value); - - emit optionsChanged(); -} - -void OptionsDialog::useCurrentComicCoverCheckClicked(bool checked) -{ - settings->setValue(USE_SELECTED_COMIC_COVER_AS_BACKGROUND_IMAGE_IN_GRID_VIEW, checked); - - emit optionsChanged(); -} - -void OptionsDialog::numDaysToConsiderRecentChanged(int value) -{ - settings->setValue(NUM_DAYS_TO_CONSIDER_RECENT, value); - - numDaysLabel->setText(QString("%1").arg(value)); - - emit optionsChanged(); -} - -void OptionsDialog::resetToDefaults() -{ - settings->setValue(OPACITY_BACKGROUND_IMAGE_IN_GRID_VIEW, 0.2); - settings->setValue(BLUR_RADIUS_BACKGROUND_IMAGE_IN_GRID_VIEW, 75); - settings->setValue(USE_SELECTED_COMIC_COVER_AS_BACKGROUND_IMAGE_IN_GRID_VIEW, false); - - restoreOptions(settings); - - emit optionsChanged(); + return gridViewW; } diff --git a/YACReaderLibrary/options_dialog.h b/YACReaderLibrary/options_dialog.h index a62c9dcde..ff8aae65b 100644 --- a/YACReaderLibrary/options_dialog.h +++ b/YACReaderLibrary/options_dialog.h @@ -28,20 +28,36 @@ private slots: void resetToDefaults(); private: - QCheckBox *useBackgroundImageCheck; - QCheckBox *useCurrentComicCoverCheck; - QSlider *backgroundImageOpacitySlider; - QSlider *backgroundImageBlurRadiusSlider; - QLabel *opacityLabel; - QLabel *blurLabel; - QPushButton *resetButton; + // General tabs QCheckBox *displayContinueReadingBannerCheck; QCheckBox *trayIconCheckbox; QCheckBox *startToTrayCheckbox; QCheckBox *comicInfoXMLCheckbox; QSlider *recentIntervalSlider; QLabel *numDaysLabel; + + // Libraries tab + QCheckBox *updateLibrariesAtStartupCheck; + QCheckBox *detectChangesAutomaticallyCheck; + QCheckBox *updateLibrariesPeriodicallyCheck; + QComboBox *intervalComboBox; + QCheckBox *updateLibrariesAtCertainTimeCheck; + QTimeEdit *updateLibrariesTimeEdit; QCheckBox *compareModifiedDateWhenUpdatingLibrariesCheck; + + // Grid tab + QCheckBox *useBackgroundImageCheck; + QCheckBox *useCurrentComicCoverCheck; + QSlider *backgroundImageOpacitySlider; + QSlider *backgroundImageBlurRadiusSlider; + QLabel *opacityLabel; + QLabel *blurLabel; + QPushButton *resetButton; + + QWidget *createGeneralTab(); + QWidget *createLibrariesTab(); + QWidget *createFlowTab(); + QWidget *createGridTab(); }; #endif diff --git a/YACReaderLibrary/properties_dialog.cpp b/YACReaderLibrary/properties_dialog.cpp index 3096deff2..729c2f249 100644 --- a/YACReaderLibrary/properties_dialog.cpp +++ b/YACReaderLibrary/properties_dialog.cpp @@ -737,7 +737,7 @@ void PropertiesDialog::setMultipleCover() { ComicDB lastComic = comics.last(); QPixmap last = lastComic.info.getCover(basePath); - last = last.scaledToHeight(444, Qt::SmoothTransformation); + last = last.scaledToHeight(575, Qt::SmoothTransformation); coverImage = QPixmap::fromImage(blurred(last.toImage(), QRect(0, 0, last.width(), last.height()), 15)); @@ -961,6 +961,8 @@ void PropertiesDialog::save() comics[currentComicIndex].info.originalCoverSize = QString("%1x%2").arg(ie.getOriginalCoverSize().first).arg(ie.getOriginalCoverSize().second); comics[currentComicIndex].info.coverSizeRatio = static_cast(ie.getOriginalCoverSize().first) / ie.getOriginalCoverSize().second; } + + emit coverChangedSignal(comics[currentComicIndex]); } } } diff --git a/YACReaderLibrary/properties_dialog.h b/YACReaderLibrary/properties_dialog.h index f83adb9f2..7485656a5 100644 --- a/YACReaderLibrary/properties_dialog.h +++ b/YACReaderLibrary/properties_dialog.h @@ -171,5 +171,8 @@ public slots: void loadNextCover(); void loadPreviousCover(); bool close(); + +signals: + void coverChangedSignal(const ComicDB &comic); }; #endif diff --git a/YACReaderLibrary/server/controllers/v2/comicfullinfocontroller_v2.cpp b/YACReaderLibrary/server/controllers/v2/comicfullinfocontroller_v2.cpp index 344d3a95f..8bc43ce64 100644 --- a/YACReaderLibrary/server/controllers/v2/comicfullinfocontroller_v2.cpp +++ b/YACReaderLibrary/server/controllers/v2/comicfullinfocontroller_v2.cpp @@ -4,12 +4,10 @@ #include "db_helper.h" #include "comic_db.h" -#include "folder.h" +#include "yacreader_libraries.h" #include "yacreader_server_data_helper.h" -#include "qnaturalsorting.h" - #include using stefanfrings::HttpRequest; @@ -35,9 +33,11 @@ void ComicFullinfoController_v2::service(HttpRequest &request, HttpResponse &res void ComicFullinfoController_v2::serviceContent(const int &libraryId, const qulonglong &comicId, HttpResponse &response) { + auto libraryUuid = DBHelper::getLibraries().getLibraryIdFromLegacyId(libraryId); + ComicDB comic = DBHelper::getComicInfo(libraryId, comicId); - QJsonObject json = YACReaderServerDataHelper::fullComicToJSON(libraryId, comic); + QJsonObject json = YACReaderServerDataHelper::fullComicToJSON(libraryId, libraryUuid, comic); QJsonDocument output(json); diff --git a/YACReaderLibrary/server/controllers/v2/favoritescontroller_v2.cpp b/YACReaderLibrary/server/controllers/v2/favoritescontroller_v2.cpp index 7717ee84f..a7bc39fb4 100644 --- a/YACReaderLibrary/server/controllers/v2/favoritescontroller_v2.cpp +++ b/YACReaderLibrary/server/controllers/v2/favoritescontroller_v2.cpp @@ -3,6 +3,7 @@ #include "db_helper.h" #include "comic_db.h" +#include "yacreader_libraries.h" #include "yacreader_server_data_helper.h" using stefanfrings::HttpRequest; @@ -25,12 +26,14 @@ void FavoritesControllerV2::service(HttpRequest &request, HttpResponse &response void FavoritesControllerV2::serviceContent(const int library, HttpResponse &response) { + auto libraryUuid = DBHelper::getLibraries().getLibraryIdFromLegacyId(library); + QList comics = DBHelper::getFavorites(library); QJsonArray items; for (const ComicDB &comic : comics) { - items.append(YACReaderServerDataHelper::comicToJSON(library, comic)); + items.append(YACReaderServerDataHelper::comicToJSON(library, libraryUuid, comic)); } QJsonDocument output(items); diff --git a/YACReaderLibrary/server/controllers/v2/foldercontentcontroller_v2.cpp b/YACReaderLibrary/server/controllers/v2/foldercontentcontroller_v2.cpp index 9c59f67c8..6f99993ec 100644 --- a/YACReaderLibrary/server/controllers/v2/foldercontentcontroller_v2.cpp +++ b/YACReaderLibrary/server/controllers/v2/foldercontentcontroller_v2.cpp @@ -6,6 +6,7 @@ #include "comic_db.h" #include "folder.h" +#include "yacreader_libraries.h" #include "yacreader_server_data_helper.h" #include "qnaturalsorting.h" @@ -41,6 +42,8 @@ void FolderContentControllerV2::serviceContent(const int &library, const qulongl #ifdef QT_DEBUG auto started = std::chrono::high_resolution_clock::now(); #endif + auto libraryUuid = DBHelper::getLibraries().getLibraryIdFromLegacyId(library); + QList folderContent = DBHelper::getFolderSubfoldersFromLibrary(library, folderId); QList folderComics = DBHelper::getFolderComicsFromLibrary(library, folderId); @@ -56,10 +59,10 @@ void FolderContentControllerV2::serviceContent(const int &library, const qulongl for (QList::const_iterator itr = folderContent.constBegin(); itr != folderContent.constEnd(); itr++) { if ((*itr)->isDir()) { currentFolder = (Folder *)(*itr); - items.append(YACReaderServerDataHelper::folderToJSON(library, *currentFolder)); + items.append(YACReaderServerDataHelper::folderToJSON(library, libraryUuid, *currentFolder)); } else { currentComic = (ComicDB *)(*itr); - items.append(YACReaderServerDataHelper::comicToJSON(library, *currentComic)); + items.append(YACReaderServerDataHelper::comicToJSON(library, libraryUuid, *currentComic)); } } diff --git a/YACReaderLibrary/server/controllers/v2/foldermetadatacontroller_v2.cpp b/YACReaderLibrary/server/controllers/v2/foldermetadatacontroller_v2.cpp new file mode 100644 index 000000000..8910dcc7d --- /dev/null +++ b/YACReaderLibrary/server/controllers/v2/foldermetadatacontroller_v2.cpp @@ -0,0 +1,34 @@ +#include "foldermetadatacontroller_v2.h" + +#include "db_helper.h" +#include "folder.h" + +#include "yacreader_libraries.h" +#include "yacreader_server_data_helper.h" + +FolderMetadataControllerV2::FolderMetadataControllerV2() { } + +void FolderMetadataControllerV2::service(stefanfrings::HttpRequest &request, stefanfrings::HttpResponse &response) +{ + response.setHeader("Content-Type", "application/json"); + + QString path = QUrl::fromPercentEncoding(request.getPath()).toUtf8(); + QStringList pathElements = path.split('/'); + int libraryId = pathElements.at(3).toInt(); + qulonglong folderId = pathElements.at(5).toULongLong(); + + auto folder = DBHelper::getFolder(libraryId, folderId); + if (!folder.knownId) { + response.setStatus(404, "not found"); + response.write("404 not found", true); + return; + } + + auto libraryUuid = DBHelper::getLibraries().getLibraryIdFromLegacyId(libraryId); + + auto json = YACReaderServerDataHelper::folderToJSON(libraryId, libraryUuid, folder); + + QJsonDocument output(json); + + response.write(output.toJson(QJsonDocument::Compact)); +} diff --git a/YACReaderLibrary/server/controllers/v2/foldermetadatacontroller_v2.h b/YACReaderLibrary/server/controllers/v2/foldermetadatacontroller_v2.h new file mode 100644 index 000000000..03980355c --- /dev/null +++ b/YACReaderLibrary/server/controllers/v2/foldermetadatacontroller_v2.h @@ -0,0 +1,20 @@ +#ifndef FOLDERMETADATACONTROLLERV2_H +#define FOLDERMETADATACONTROLLERV2_H + +#include "httprequest.h" +#include "httpresponse.h" +#include "httprequesthandler.h" + +class FolderMetadataControllerV2 : public stefanfrings::HttpRequestHandler +{ + Q_OBJECT + Q_DISABLE_COPY(FolderMetadataControllerV2) +public: + /** Constructor */ + FolderMetadataControllerV2(); + + /** Generates the response */ + void service(stefanfrings::HttpRequest &request, stefanfrings::HttpResponse &response) override; +}; + +#endif // FOLDERMETADATACONTROLLERV2_H diff --git a/YACReaderLibrary/server/controllers/v2/librariescontroller_v2.cpp b/YACReaderLibrary/server/controllers/v2/librariescontroller_v2.cpp index ca5c84f93..ea949499d 100644 --- a/YACReaderLibrary/server/controllers/v2/librariescontroller_v2.cpp +++ b/YACReaderLibrary/server/controllers/v2/librariescontroller_v2.cpp @@ -2,11 +2,6 @@ #include "db_helper.h" //get libraries #include "yacreader_libraries.h" -#include "template.h" -#include "../static.h" - -#include "QsLog.h" - using stefanfrings::HttpRequest; using stefanfrings::HttpResponse; @@ -16,20 +11,18 @@ void LibrariesControllerV2::service(HttpRequest & /* request */, HttpResponse &r { response.setHeader("Content-Type", "application/json"); - YACReaderLibraries libraries = DBHelper::getLibraries(); - QList names = DBHelper::getLibrariesNames(); + auto libraries = DBHelper::getLibraries().sortedLibraries(); QJsonArray librariesJson; - int currentId = 0; - foreach (QString name, names) { - currentId = libraries.getId(name); - QJsonObject library; + foreach (YACReaderLibrary library, libraries) { + QJsonObject libraryJson; - library["name"] = name; - library["id"] = currentId; + libraryJson["name"] = library.getName(); + libraryJson["id"] = library.getLegacyId(); + libraryJson["uuid"] = library.getId().toString(); - librariesJson.append(library); + librariesJson.append(libraryJson); } QJsonDocument output(librariesJson); diff --git a/YACReaderLibrary/server/controllers/v2/readingcomicscontroller_v2.cpp b/YACReaderLibrary/server/controllers/v2/readingcomicscontroller_v2.cpp index 6db58772f..a63b3d7cc 100644 --- a/YACReaderLibrary/server/controllers/v2/readingcomicscontroller_v2.cpp +++ b/YACReaderLibrary/server/controllers/v2/readingcomicscontroller_v2.cpp @@ -3,6 +3,7 @@ #include "db_helper.h" #include "comic_db.h" +#include "yacreader_libraries.h" #include "yacreader_server_data_helper.h" using stefanfrings::HttpRequest; @@ -28,12 +29,14 @@ void ReadingComicsControllerV2::service(HttpRequest &request, HttpResponse &resp void ReadingComicsControllerV2::serviceContent(const int &library, HttpResponse &response) { + auto libraryUuid = DBHelper::getLibraries().getLibraryIdFromLegacyId(library); + QList readingComics = DBHelper::getReading(library); QJsonArray comics; for (const ComicDB &comic : readingComics) { - comics.append(YACReaderServerDataHelper::comicToJSON(library, comic)); + comics.append(YACReaderServerDataHelper::comicToJSON(library, libraryUuid, comic)); } QJsonDocument output(comics); diff --git a/YACReaderLibrary/server/controllers/v2/readinglistcontentcontroller_v2.cpp b/YACReaderLibrary/server/controllers/v2/readinglistcontentcontroller_v2.cpp index 4a5028830..0abb55fce 100644 --- a/YACReaderLibrary/server/controllers/v2/readinglistcontentcontroller_v2.cpp +++ b/YACReaderLibrary/server/controllers/v2/readinglistcontentcontroller_v2.cpp @@ -3,6 +3,7 @@ #include "db_helper.h" #include "comic_db.h" +#include "yacreader_libraries.h" #include "yacreader_server_data_helper.h" using stefanfrings::HttpRequest; @@ -28,12 +29,14 @@ void ReadingListContentControllerV2::service(HttpRequest &request, HttpResponse void ReadingListContentControllerV2::serviceContent(const int &library, const qulonglong &readingListId, HttpResponse &response) { + auto libraryUuid = DBHelper::getLibraries().getLibraryIdFromLegacyId(library); + QList comics = DBHelper::getReadingListFullContent(library, readingListId); QJsonArray items; for (const ComicDB &comic : comics) { - items.append(YACReaderServerDataHelper::comicToJSON(library, comic)); + items.append(YACReaderServerDataHelper::comicToJSON(library, libraryUuid, comic)); } QJsonDocument output(items); diff --git a/YACReaderLibrary/server/controllers/v2/readinglistscontroller_v2.cpp b/YACReaderLibrary/server/controllers/v2/readinglistscontroller_v2.cpp index a791c121d..63da5fab0 100644 --- a/YACReaderLibrary/server/controllers/v2/readinglistscontroller_v2.cpp +++ b/YACReaderLibrary/server/controllers/v2/readinglistscontroller_v2.cpp @@ -2,6 +2,7 @@ #include "db_helper.h" #include "reading_list.h" +#include "yacreader_libraries.h" #include "yacreader_server_data_helper.h" using stefanfrings::HttpRequest; @@ -26,12 +27,14 @@ void ReadingListsControllerV2::service(HttpRequest &request, HttpResponse &respo void ReadingListsControllerV2::serviceContent(const int library, HttpResponse &response) { + auto libraryUuid = DBHelper::getLibraries().getLibraryIdFromLegacyId(library); + QList readingLists = DBHelper::getReadingLists(library); QJsonArray items; for (QList::const_iterator itr = readingLists.constBegin(); itr != readingLists.constEnd(); itr++) { - items.append(YACReaderServerDataHelper::readingListToJSON(library, *itr)); + items.append(YACReaderServerDataHelper::readingListToJSON(library, libraryUuid, *itr)); } QJsonDocument output(items); diff --git a/YACReaderLibrary/server/controllers/v2/synccontroller_v2.cpp b/YACReaderLibrary/server/controllers/v2/synccontroller_v2.cpp index 46686e92f..3b34ba70a 100644 --- a/YACReaderLibrary/server/controllers/v2/synccontroller_v2.cpp +++ b/YACReaderLibrary/server/controllers/v2/synccontroller_v2.cpp @@ -5,6 +5,7 @@ #include "comic_db.h" #include "db_helper.h" +#include "yacreader_libraries.h" #include "yacreader_server_data_helper.h" using stefanfrings::HttpRequest; @@ -33,10 +34,52 @@ void SyncControllerV2::service(HttpRequest &request, HttpResponse &response) QString hash; QMap> comics; QList comicsWithNoLibrary; + + auto libraries = DBHelper::getLibraries(); + + bool clientSendsHasBeenOpened = false; + foreach (QString comicInfo, data) { QList comicInfoProgress = comicInfo.split("\t"); - if (comicInfoProgress.length() >= 6) { + if (comicInfoProgress.length() >= 9) { + if (comicInfoProgress.at(0) != "u") { + continue; + } + + clientSendsHasBeenOpened = true; + + auto libraryUuid = QUuid(comicInfoProgress.at(1)); + if (!libraryUuid.isNull()) { + auto libraryId = libraries.getIdFromUuid(libraryUuid); + if (libraryId == -1) { + continue; + } + comicId = comicInfoProgress.at(2).toULongLong(); + hash = comicInfoProgress.at(3); + currentPage = comicInfoProgress.at(4).toInt(); + + ComicInfo info; + info.currentPage = currentPage; + info.hash = hash; // TODO remove the hash check and add UUIDs for libraries + info.id = comicId; + + currentRating = comicInfoProgress.at(5).toInt(); + info.rating = currentRating; + + lastTimeOpened = comicInfoProgress.at(6).toULong(); + info.lastTimeOpened = lastTimeOpened; + + info.hasBeenOpened = comicInfoProgress.at(7).toInt(); + + info.read = comicInfoProgress.at(8).toInt(); + + if (!comics.contains(libraryId)) { + comics[libraryId] = QList(); + } + comics[libraryId].push_back(info); + } + } else if (comicInfoProgress.length() >= 6) { if (comicInfoProgress.at(0) != "unknown") { libraryId = comicInfoProgress.at(0).toULongLong(); comicId = comicInfoProgress.at(1).toULongLong(); @@ -81,13 +124,17 @@ void SyncControllerV2::service(HttpRequest &request, HttpResponse &response) } } - auto moreRecentComicsFound = DBHelper::updateFromRemoteClient(comics); - QJsonArray items; - foreach (qulonglong libraryId, moreRecentComicsFound.keys()) { - foreach (ComicDB comic, moreRecentComicsFound[libraryId]) { - items.append(YACReaderServerDataHelper::comicToJSON(libraryId, comic)); + if (!comics.isEmpty()) { + auto moreRecentComicsFound = DBHelper::updateFromRemoteClient(comics, clientSendsHasBeenOpened); + + foreach (qulonglong libraryId, moreRecentComicsFound.keys()) { + auto libraryUuid = DBHelper::getLibraries().getLibraryIdFromLegacyId(libraryId); + + foreach (ComicDB comic, moreRecentComicsFound[libraryId]) { + items.append(YACReaderServerDataHelper::comicToJSON(libraryId, libraryUuid, comic)); + } } } diff --git a/YACReaderLibrary/server/controllers/v2/tagcontentcontroller_v2.cpp b/YACReaderLibrary/server/controllers/v2/tagcontentcontroller_v2.cpp index 0aa353ec0..8aca99cf7 100644 --- a/YACReaderLibrary/server/controllers/v2/tagcontentcontroller_v2.cpp +++ b/YACReaderLibrary/server/controllers/v2/tagcontentcontroller_v2.cpp @@ -3,6 +3,7 @@ #include "db_helper.h" #include "comic_db.h" +#include "yacreader_libraries.h" #include "yacreader_server_data_helper.h" #include @@ -30,12 +31,14 @@ void TagContentControllerV2::service(HttpRequest &request, HttpResponse &respons void TagContentControllerV2::serviceContent(const int &library, const qulonglong &tagId, HttpResponse &response) { + auto libraryUuid = DBHelper::getLibraries().getLibraryIdFromLegacyId(library); + QList comics = DBHelper::getLabelComics(library, tagId); QJsonArray items; for (const ComicDB &comic : comics) { - items.append(YACReaderServerDataHelper::comicToJSON(library, comic)); + items.append(YACReaderServerDataHelper::comicToJSON(library, libraryUuid, comic)); } QJsonDocument output(items); diff --git a/YACReaderLibrary/server/controllers/v2/tagscontroller_v2.cpp b/YACReaderLibrary/server/controllers/v2/tagscontroller_v2.cpp index 954f1d030..28337ec74 100644 --- a/YACReaderLibrary/server/controllers/v2/tagscontroller_v2.cpp +++ b/YACReaderLibrary/server/controllers/v2/tagscontroller_v2.cpp @@ -4,13 +4,9 @@ #include "yacreader_libraries.h" #include "reading_list.h" -#include "../static.h" -#include "yacreader_global.h" #include "yacreader_server_data_helper.h" -#include "QsLog.h" - using stefanfrings::HttpRequest; using stefanfrings::HttpResponse; @@ -26,10 +22,12 @@ void TagsControllerV2::service(HttpRequest &request, HttpResponse &response) QList