diff --git a/app/app.pro b/app/app.pro index b9a5ea0..9816aa1 100644 --- a/app/app.pro +++ b/app/app.pro @@ -109,10 +109,13 @@ SOURCES += \ src/BooksImportModel.cpp \ src/BooksListWatcher.cpp \ src/BooksLoadingProperty.cpp \ + src/BooksMediaPlugin.cpp \ src/BooksPageStack.cpp \ src/BooksPageWidget.cpp \ src/BooksPaintContext.cpp \ src/BooksPathModel.cpp \ + src/BooksPluginLoader.cpp \ + src/BooksPolicyPlugin.cpp \ src/BooksSaveTimer.cpp \ src/BooksSettings.cpp \ src/BooksShelf.cpp \ @@ -151,10 +154,13 @@ HEADERS += \ src/BooksItem.h \ src/BooksListWatcher.h \ src/BooksLoadingProperty.h \ + src/BooksMediaPlugin.h \ src/BooksPageStack.h \ src/BooksPageWidget.h \ src/BooksPaintContext.h \ src/BooksPathModel.h \ + src/BooksPluginLoader.h \ + src/BooksPolicyPlugin.h \ src/BooksPos.h \ src/BooksSaveTimer.h \ src/BooksSettings.h \ diff --git a/app/qml/BooksBookView.qml b/app/qml/BooksBookView.qml index 58f1846..c2d647c 100644 --- a/app/qml/BooksBookView.qml +++ b/app/qml/BooksBookView.qml @@ -34,6 +34,9 @@ import QtQuick 2.0 import Sailfish.Silica 1.0 import harbour.books 1.0 +//import Sailfish.Media 1.0 // Not allowed +//import org.nemomobile.policy 1.0 // Not allowed + SilicaFlickable { id: root @@ -57,10 +60,21 @@ SilicaFlickable { (!imageView || !imageView.visible) && (!footnoteView || !footnoteView.visible) + readonly property bool viewActive: Qt.application.active && book + readonly property bool haveVolumeUpAction: Settings.volumeUpAction !== BooksSettings.ActionNone + readonly property bool haveVolumeDownAction: Settings.volumeDownAction !== BooksSettings.ActionNone + readonly property bool haveKeyAction: haveVolumeUpAction || haveVolumeDownAction + property var linkMenu property var imageView property var footnoteView + function hideViews() { + if (linkMenu) linkMenu.hide() + if (imageView) imageView.hide() + if (footnoteView) footnoteView.hide() + } + onOrientationChanged: { if (footnoteView) { footnoteView.cancel() @@ -111,6 +125,7 @@ SilicaFlickable { opacity: loading ? 0 : 1 visible: opacity > 0 interactive: root.interactive + readonly property real maxContentX: Math.max(0, contentWidth - width) readonly property int currentPage: stackModel.currentPage property bool completed @@ -143,7 +158,7 @@ SilicaFlickable { } } function updateModel() { - if (linkMenu) linkMenu.hide() + hideViews() //console.trace() stackModel.currentPage = currentIndex if (!pager.pressed) { @@ -212,6 +227,32 @@ SilicaFlickable { } } + function prevPage() { + if (!scrollAnimation.running && contentX > 0) { + hideViews(); + scrollAnimation.from = contentX + scrollAnimation.to = Math.max(0, contentX - width - spacing) + scrollAnimation.start() + } + } + + function nextPage() { + if (!scrollAnimation.running && contentX < maxContentX) { + hideViews(); + scrollAnimation.from = contentX + scrollAnimation.to = Math.min(maxContentX, contentX + width + spacing) + scrollAnimation.start() + } + } + + NumberAnimation { + id: scrollAnimation + target: bookView + property: "contentX" + duration: 500 + easing.type: Easing.InOutQuad + } + Behavior on opacity { FadeAnimation {} } Timer { @@ -326,4 +367,48 @@ SilicaFlickable { //% "Formatting..." qsTrId("harbour-books-book-view-formatting")) : "" } + + function performAction(action) + { + switch (action) { + case BooksSettings.ActionPreviousPage: + bookView.prevPage() + return + case BooksSettings.ActionNextPage: + bookView.nextPage() + return + } + } + + MediaKey { + enabled: viewActive && haveVolumeUpAction + key: Qt.Key_VolumeUp + onPressed: volumeUpAction() + onRepeat: volumeUpAction() + function volumeUpAction() { + performAction(Settings.volumeUpAction) + } + } + + MediaKey { + enabled: viewActive && haveVolumeDownAction + key: Qt.Key_VolumeDown + onPressed: volumeDownAction() + onRepeat: volumeDownAction() + function volumeDownAction() { + performAction(Settings.volumeDownAction) + } + } + + Permissions { + enabled: viewActive && haveKeyAction + autoRelease: true + applicationClass: "camera" + + Resource { + id: volumeKeysResource + type: Resource.ScaleButton + optional: true + } + } } diff --git a/app/qml/BooksMain.qml b/app/qml/BooksMain.qml index 214a5d4..7106862 100644 --- a/app/qml/BooksMain.qml +++ b/app/qml/BooksMain.qml @@ -1,5 +1,5 @@ /* - Copyright (C) 2015-2016 Jolla Ltd. + Copyright (C) 2015-2017 Jolla Ltd. Contact: Slava Monich You may use this file under the terms of BSD license as follows: @@ -39,9 +39,9 @@ ApplicationWindow { allowedOrientations: { switch (Settings.orientation) { default: - case Settings.OrientationAny: return Orientation.All - case Settings.OrientationPortrait: return Orientation.Portrait - case Settings.OrientationLandscape: return Orientation.Landscape + case BooksSettings.OrientationAny: return Orientation.All + case BooksSettings.OrientationPortrait: return Orientation.Portrait + case BooksSettings.OrientationLandscape: return Orientation.Landscape } } diff --git a/app/settings/BooksActionSelector.qml b/app/settings/BooksActionSelector.qml new file mode 100644 index 0000000..59d3de8 --- /dev/null +++ b/app/settings/BooksActionSelector.qml @@ -0,0 +1,92 @@ +/* + Copyright (C) 2017 Jolla Ltd. + Contact: Slava Monich + + You may use this file under the terms of BSD license as follows: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Jolla Ltd nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + THE POSSIBILITY OF SUCH DAMAGE. +*/ + +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import org.nemomobile.configuration 1.0 + +ComboBox { + id: actionComboBox + property alias key: configuration.key + property alias defaultValue: configuration.defaultValue + property bool ready + + value: currentItem ? currentItem.text : "" + menu: ContextMenu { + id: actionMenu + readonly property int defaultIndex: 0 + MenuItem { + //: Combo box value for no action + //% "No action" + text: qsTrId("harbour-books-settings-page-action-none") + readonly property int value: 0 + } + MenuItem { + //: Combo box value for previous page action + //% "Previous page" + text: qsTrId("harbour-books-settings-page-action-previous_page") + readonly property int value: 1 + } + MenuItem { + //: Combo box value for next page action + //% "Next page" + text: qsTrId("harbour-books-settings-page-action-next_page") + readonly property int value: 2 + } + } + onCurrentItemChanged: { + if (ready && currentItem) { + configuration.value = currentItem.value + } + } + Component.onCompleted: { + configuration.updateControls() + ready = true + } + + ConfigurationValue { + id: configuration + defaultValue: 0 + onValueChanged: updateControls() + function updateControls() { + var n = actionMenu.children.length + var index = actionMenu.defaultIndex + for (var i=0; i You may use this file under the terms of BSD license as follows: @@ -78,6 +78,12 @@ Page { title: qsTrId("harbour-books-settings-page-header") } + SectionHeader { + //: Section header for display settings + //% "Display" + text: qsTrId("harbour-books-settings-page-display-section_header") + } + Slider { id: fontSizeSlider minimumValue: -5 @@ -161,6 +167,28 @@ Page { } } + SectionHeader { + //: Section header for media keys + //% "Media keys" + text: qsTrId("harbour-books-settings-page-media-keys-section_header") + } + + BooksActionSelector { + //: Combo box label + //% "Volume up" + label: qsTrId("harbour-books-settings-page-volume_up-label") + key: rootPath + "volumeUpAction" + defaultValue: 2 // BooksSettings.ActionNextPage + } + + BooksActionSelector { + //: Combo box label + //% "Volume down" + label: qsTrId("harbour-books-settings-page-volume_down-label") + key: rootPath + "volumeDownAction" + defaultValue: 1 // BooksSettings.ActionPreviousPage + } + SectionHeader { //: Section header for memory card settings //% "Memory card" diff --git a/app/src/BooksMediaPlugin.cpp b/app/src/BooksMediaPlugin.cpp new file mode 100644 index 0000000..1a48bcb --- /dev/null +++ b/app/src/BooksMediaPlugin.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2017 Jolla Ltd. + * Contact: Slava Monich + * + * You may use this file under the terms of the BSD license as follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Jolla Ltd nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "BooksMediaPlugin.h" + +// Workaround for org.nemomobile.policy (or Sailfish.Media) not being +// allowed in harbour apps + +BooksMediaPlugin* BooksMediaPlugin::gInstance = Q_NULLPTR; + +const char BooksMediaPlugin::MEDIAKEY_QML_TYPE[] = "MediaKey"; + +BooksMediaPlugin::BooksMediaPlugin( + QQmlEngine* aEngine) : + BooksPluginLoader(aEngine, "Sailfish.Media", 1, 0) +{ +} + +void +BooksMediaPlugin::registerTypes( + const char* aModule, + int aMajor, + int aMinor) +{ + reRegisterType(MEDIAKEY_QML_TYPE, aModule, aMajor, aMinor); +} + +void +BooksMediaPlugin::registerTypes( + QQmlEngine* aEngine, + const char* aModule, + int aMajor, + int aMinor) +{ + if (!gInstance) { + gInstance = new BooksMediaPlugin(aEngine); + } + gInstance->registerTypes(aModule, aMajor, aMinor); +} diff --git a/app/src/BooksMediaPlugin.h b/app/src/BooksMediaPlugin.h new file mode 100644 index 0000000..8ee3e25 --- /dev/null +++ b/app/src/BooksMediaPlugin.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2017 Jolla Ltd. + * Contact: Slava Monich + * + * You may use this file under the terms of the BSD license as follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Jolla Ltd nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BOOKS_MEDIA_PLUGIN_H +#define BOOKS_MEDIA_PLUGIN_H + +#include "BooksPluginLoader.h" + +class BooksMediaPlugin : public BooksPluginLoader +{ + static BooksMediaPlugin* gInstance; + static const char MEDIAKEY_QML_TYPE[]; + +public: + static void registerTypes(QQmlEngine* aEngine, const char* aModule, + int aMajor, int aMinor); + +private: + BooksMediaPlugin(QQmlEngine* aEngine); + void registerTypes(const char* aModule, int aMajor, int aMinor); +}; + +#endif // BOOKS_MEDIA_KEY_H diff --git a/app/src/BooksPluginLoader.cpp b/app/src/BooksPluginLoader.cpp new file mode 100644 index 0000000..3419181 --- /dev/null +++ b/app/src/BooksPluginLoader.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2017 Jolla Ltd. + * Contact: Slava Monich + * + * You may use this file under the terms of the BSD license as follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Jolla Ltd nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "BooksPluginLoader.h" + +#include "HarbourDebug.h" + +#include +#include +#include + +#include +#include +#include +#include + +// This hack allows to use prohibited QML imports by re-registering +// then under harbour.books + +// PRIVATE QT API! +class Q_QML_EXPORT QQmlType +{ +public: + int typeId() const; + int qListTypeId() const; + typedef void (*CreateFunc)(void *); + CreateFunc createFunction() const; + int createSize() const; + const QMetaObject *metaObject() const; + int parserStatusCast() const; + int propertyValueSourceCast() const; + int propertyValueInterceptorCast() const; +}; + +// PRIVATE QT API! +class Q_QML_EXPORT QQmlMetaType +{ +public: + static QQmlType* qmlType(const QString &qualifiedName, int, int); +}; + +BooksPluginLoader::BooksPluginLoader( + QQmlEngine* aEngine, + QString aModule, + int aMajor, + int aMinor) : + iTypesRegistered(false), + iPlugin(pluginLoader(aEngine, aModule)), + iModule(aModule), + iMajor(aMajor), + iMinor(aMinor) +{} + +BooksPluginLoader::~BooksPluginLoader() +{ + delete iPlugin; +} + +QPluginLoader* +BooksPluginLoader::pluginLoader( + QQmlEngine* aEngine, + QString aModule) +{ + QStringList pathList = aEngine->importPathList(); + aModule.replace('.', '/'); + const int n = pathList.count(); + for (int i=0; iload()) { + HDEBUG("loaded" << qPrintable(loader->fileName())); + return loader; + } else { + HWARN("Failed to load" << qPrintable(loader->fileName())); + delete loader; + } + } + } + return NULL; +} + +QPluginLoader* +BooksPluginLoader::pluginLoader( + QString aPluginDir) +{ + QString qmldir(QString(aPluginDir).append('/').append("qmldir")); + QFile f(qmldir); + if (f.open(QIODevice::ReadOnly)) { + QTextStream in(&f); + while (!in.atEnd()) { + static const QString plugin("plugin"); + QString line = in.readLine(); + if (line.indexOf(plugin) >= 0) { + QStringList parts = line.split(' ', QString::SkipEmptyParts); + if (parts.count() == 2 && parts.at(0) == plugin) { + QString path(QString(aPluginDir).append("/lib"). + append(parts.at(1)).append(".so")); + if (QFile::exists(path)) { + return new QPluginLoader(path); + } + } + } + } + } + return NULL; +} + +QQmlType* +BooksPluginLoader::qmlType( + QString aName) +{ + if (iPlugin) { + if (!iTypesRegistered) { + iTypesRegistered = true; + QObject* root = iPlugin->instance(); + if (root) { + QQmlTypesExtensionInterface* ext = + qobject_cast(root); + if (ext) { + QByteArray str = iModule.toLocal8Bit(); + ext->registerTypes(str.constData()); + } + } else { + HWARN("Could not load" << qPrintable(iPlugin->fileName())); + } + } + QString fullName(iModule + '/' + aName); + QQmlType* type = QQmlMetaType::qmlType(fullName, iMajor, iMinor); + if (!type) { + HWARN("Failed to load" << fullName); + } + return type; + } + return NULL; +} + +void +BooksPluginLoader::reRegisterType( + const char* aQmlName, + const char* aModule, + int aMajor, + int aMinor) +{ + // Re-register with the same type name (in different module) + reRegisterType(qmlType(aQmlName), aQmlName, aModule, aMajor, aMinor); +} + +// Re-registers the existing QML type under a different name/module +void +BooksPluginLoader::reRegisterType( + QQmlType* aType, + const char* aQmlName, + const char* aModule, + int aMajor, + int aMinor) +{ + if (aType) { + QQmlPrivate::RegisterType type = { + 0, // int version; + aType->typeId(), // int typeId; + aType->qListTypeId(), // int listId; + aType->createSize(), // int objectSize; + aType->createFunction(), // void (*create)(void *); + QString(), // QString noCreationReason; + aModule, // const char *uri; + aMajor, // int versionMajor; + aMinor, // int versionMinor; + aQmlName, // const char *elementName; + aType->metaObject(), // const QMetaObject *metaObject; +#if 0 // We don't need those, it seems + aType->attachedPropertiesFunction(), + aType->attachedPropertiesType(), +#else + Q_NULLPTR, // QQmlAttachedPropertiesFunc attachedPropertiesFunction; + Q_NULLPTR, // const QMetaObject *attachedPropertiesMetaObject; +#endif + aType->parserStatusCast(), // int parserStatusCast; + aType->propertyValueSourceCast(), // int valueSourceCast; + aType->propertyValueInterceptorCast(), // int valueInterceptorCast; + Q_NULLPTR, // QObject *(*extensionObjectCreate)(QObject *); + Q_NULLPTR, // const QMetaObject *extensionMetaObject; + Q_NULLPTR, // QQmlCustomParser *customParser; + 0 // int revision; + }; + QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); + } +} diff --git a/app/src/BooksPluginLoader.h b/app/src/BooksPluginLoader.h new file mode 100644 index 0000000..4c9528e --- /dev/null +++ b/app/src/BooksPluginLoader.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2017 Jolla Ltd. + * Contact: Slava Monich + * + * You may use this file under the terms of the BSD license as follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Jolla Ltd nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BOOKS_PLUGIN_LOADER_H +#define BOOKS_PLUGIN_LOADER_H + +#include + +class QQmlType; +class QQmlEngine; +class QPluginLoader; + +class BooksPluginLoader +{ +protected: + BooksPluginLoader(QQmlEngine* aEngine, QString aModule, int aMajor, int aMinor); + ~BooksPluginLoader(); + + QQmlType* qmlType(QString aName); + + void reRegisterType(QQmlType* aType, const char* aQmlName, + const char* aModule, int aMajor, int aMinor); + void reRegisterType(const char* aQmlName, + const char* aModule, int aMajor, int aMinor); + + static QPluginLoader* pluginLoader(QQmlEngine* aEngine, QString aModule); + static QPluginLoader* pluginLoader(QString aPluginDir); + +private: + bool iTypesRegistered; + QPluginLoader* iPlugin; + QString iModule; + int iMajor; + int iMinor; +}; + +#endif // BOOKS_PLUGIN_LOADER_H diff --git a/app/src/BooksPolicyPlugin.cpp b/app/src/BooksPolicyPlugin.cpp new file mode 100644 index 0000000..056fa05 --- /dev/null +++ b/app/src/BooksPolicyPlugin.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2017 Jolla Ltd. + * Contact: Slava Monich + * + * You may use this file under the terms of the BSD license as follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Jolla Ltd nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "BooksPolicyPlugin.h" + +// Workaround for org.nemomobile.policy (or Nemo.Policy) not being +// allowed in harbour apps + +BooksPolicyPlugin* BooksPolicyPlugin::gInstance = Q_NULLPTR; + +const char BooksPolicyPlugin::RESOURCE_QML_TYPE[] = "Resource"; +const char BooksPolicyPlugin::PERMISSIONS_QML_TYPE[] = "Permissions"; + +BooksPolicyPlugin::BooksPolicyPlugin( + QQmlEngine* aEngine) : + BooksPluginLoader(aEngine, "org.nemomobile.policy", 1, 0) +{ +} + +void +BooksPolicyPlugin::registerTypes( + const char* aModule, + int aMajor, + int aMinor) +{ + reRegisterType(RESOURCE_QML_TYPE, aModule, aMajor, aMinor); + reRegisterType(PERMISSIONS_QML_TYPE, aModule, aMajor, aMinor); +} + +void +BooksPolicyPlugin::registerTypes( + QQmlEngine* aEngine, + const char* aModule, + int aMajor, + int aMinor) +{ + if (!gInstance) { + gInstance = new BooksPolicyPlugin(aEngine); + } + gInstance->registerTypes(aModule, aMajor, aMinor); +} diff --git a/app/src/BooksPolicyPlugin.h b/app/src/BooksPolicyPlugin.h new file mode 100644 index 0000000..a04bbee --- /dev/null +++ b/app/src/BooksPolicyPlugin.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2017 Jolla Ltd. + * Contact: Slava Monich + * + * You may use this file under the terms of the BSD license as follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Jolla Ltd nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef BOOKS_POLICY_PLUGIN_H +#define BOOKS_POLICY_PLUGIN_H + +#include "BooksPluginLoader.h" + +class QQmlEngine; + +class BooksPolicyPlugin : public BooksPluginLoader +{ + static BooksPolicyPlugin* gInstance; + static const char RESOURCE_QML_TYPE[]; + static const char PERMISSIONS_QML_TYPE[]; + +public: + static void registerTypes(QQmlEngine* aEngine, const char* aModule, + int aMajor, int aMinor); + +private: + BooksPolicyPlugin(QQmlEngine* aEngine); + void registerTypes(const char* aModule, int aMajor, int aMinor); +}; + +#endif // BOOKS_POLICY_PLUGIN_H diff --git a/app/src/BooksSettings.cpp b/app/src/BooksSettings.cpp index 78fc13b..ba318eb 100644 --- a/app/src/BooksSettings.cpp +++ b/app/src/BooksSettings.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2016 Jolla Ltd. + * Copyright (C) 2015-2017 Jolla Ltd. * Contact: Slava Monich * * You may use this file under the terms of the BSD license as follows: @@ -42,21 +42,26 @@ #include -#define DCONF_PATH BOOKS_DCONF_ROOT -#define KEY_FONT_SIZE "fontSize" -#define KEY_PAGE_DETAILS "pageDetails" -#define KEY_CURRENT_BOOK "currentBook" -#define KEY_CURRENT_FOLDER "currentFolder" -#define KEY_REMOVABLE_ROOT "removableRoot" -#define KEY_INVERT_COLORS "invertColors" -#define KEY_ORIENTATION "orientation" -#define DEFAULT_FONT_SIZE 0 -#define DEFAULT_PAGE_DETAILS 0 -#define DEFAULT_CURRENT_BOOK QString() -#define DEFAULT_CURRENT_FOLDER QString() -#define DEFAULT_REMOVABLE_ROOT "Books" -#define DEFAULT_INVERT_COLORS false -#define DEFAULT_ORIENTATION (BooksSettings::OrientationAny) +#define DCONF_PATH BOOKS_DCONF_ROOT +#define KEY_FONT_SIZE "fontSize" +#define KEY_PAGE_DETAILS "pageDetails" +#define KEY_CURRENT_BOOK "currentBook" +#define KEY_CURRENT_FOLDER "currentFolder" +#define KEY_REMOVABLE_ROOT "removableRoot" +#define KEY_INVERT_COLORS "invertColors" +#define KEY_VOLUME_UP_ACTION "volumeUpAction" +#define KEY_VOLUME_DOWN_ACTION "volumeDownAction" +#define KEY_ORIENTATION "orientation" + +#define DEFAULT_FONT_SIZE 0 +#define DEFAULT_PAGE_DETAILS 0 +#define DEFAULT_CURRENT_BOOK QString() +#define DEFAULT_CURRENT_FOLDER QString() +#define DEFAULT_REMOVABLE_ROOT "Books" +#define DEFAULT_INVERT_COLORS false +#define DEFAULT_VOLUME_UP_ACTION (BooksSettings::ActionNextPage) +#define DEFAULT_VOLUME_DOWN_ACTION (BooksSettings::ActionPreviousPage) +#define DEFAULT_ORIENTATION (BooksSettings::OrientationAny) #define PAGETOOL_COLOR QColor(128,128,128) // any bg #define NORMAL_PAGETOOL_HIGHLIGHT_COLOR QColor(64,64,64) // on white @@ -214,6 +219,7 @@ public: QString currentFolder() const; shared_ptr textStyle(int aFontSizeAdjust) const; void setCurrentBook(QObject* aBook); + static Action getAction(MGConfItem* aItem, Action aDefault); private Q_SLOTS: void onFontSizeValueChanged(); @@ -226,6 +232,8 @@ public: MGConfItem* iFontSizeConf; MGConfItem* iPageDetailsConf; MGConfItem* iInvertColorsConf; + MGConfItem* iVolumeUpActionConf; + MGConfItem* iVolumeDownActionConf; MGConfItem* iCurrentFolderConf; MGConfItem* iCurrentBookPathConf; MGConfItem* iOrientationConf; @@ -244,6 +252,8 @@ BooksSettings::Private::Private(BooksSettings* aParent) : iFontSizeConf(new MGConfItem(DCONF_PATH KEY_FONT_SIZE, this)), iPageDetailsConf(new MGConfItem(DCONF_PATH KEY_PAGE_DETAILS, this)), iInvertColorsConf(new MGConfItem(DCONF_PATH KEY_INVERT_COLORS, this)), + iVolumeUpActionConf(new MGConfItem(DCONF_PATH KEY_VOLUME_UP_ACTION, this)), + iVolumeDownActionConf(new MGConfItem(DCONF_PATH KEY_VOLUME_DOWN_ACTION, this)), iCurrentFolderConf(new MGConfItem(DCONF_PATH KEY_CURRENT_FOLDER, this)), iCurrentBookPathConf(new MGConfItem(DCONF_PATH KEY_CURRENT_BOOK, this)), iOrientationConf(new MGConfItem(DCONF_PATH KEY_ORIENTATION, this)), @@ -257,6 +267,8 @@ BooksSettings::Private::Private(BooksSettings* aParent) : connect(iPageDetailsConf, SIGNAL(valueChanged()), iParent, SIGNAL(pageDetailsChanged())); connect(iInvertColorsConf, SIGNAL(valueChanged()), iParent, SIGNAL(invertColorsChanged())); connect(iInvertColorsConf, SIGNAL(valueChanged()), iParent, SIGNAL(pageBackgroundColorChanged())); + connect(iVolumeUpActionConf, SIGNAL(valueChanged()), iParent, SIGNAL(volumeUpActionChanged())); + connect(iVolumeDownActionConf, SIGNAL(valueChanged()), iParent, SIGNAL(volumeDownActionChanged())); connect(iOrientationConf, SIGNAL(valueChanged()), iParent, SIGNAL(orientationChanged())); connect(iRemovableRootConf, SIGNAL(valueChanged()), iParent, SIGNAL(removableRootChanged())); } @@ -405,11 +417,29 @@ BooksSettings::Private::onCurrentBookPathChanged() } } +BooksSettings::Action +BooksSettings::Private::getAction( + MGConfItem* aItem, + Action aDefault) +{ + // Need to cast int to enum right away to force "enumeration value not + // handled in switch" warning if we miss one of the actions: + Action value = (Action)aItem->value(aDefault).toInt(); + switch (value) { + case ActionNone: + case ActionPreviousPage: + case ActionNextPage: + return value; + } + return aDefault; +} + // ========================================================================== // BooksSettings // ========================================================================== -BooksSettings::BooksSettings() : +BooksSettings::BooksSettings(QObject* aParent) : + QObject(aParent), iPrivate(new Private(this)) { } @@ -513,6 +543,36 @@ BooksSettings::setInvertColors( iPrivate->iInvertColorsConf->set(aValue); } +BooksSettings::Action +BooksSettings::volumeUpAction() const +{ + return Private::getAction(iPrivate->iVolumeUpActionConf, + DEFAULT_VOLUME_UP_ACTION); +} + +void +BooksSettings::setVolumeUpAction( + int aValue) +{ + HDEBUG(aValue); + iPrivate->iVolumeUpActionConf->set(aValue); +} + +BooksSettings::Action +BooksSettings::volumeDownAction() const +{ + return Private::getAction(iPrivate->iVolumeDownActionConf, + DEFAULT_VOLUME_DOWN_ACTION); +} + +void +BooksSettings::setVolumeDownAction( + int aValue) +{ + HDEBUG(aValue); + iPrivate->iVolumeDownActionConf->set(aValue); +} + QString BooksSettings::removableRoot() const { diff --git a/app/src/BooksSettings.h b/app/src/BooksSettings.h index 8359efb..57adf38 100644 --- a/app/src/BooksSettings.h +++ b/app/src/BooksSettings.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2016 Jolla Ltd. + * Copyright (C) 2015-2017 Jolla Ltd. * Contact: Slava Monich * * You may use this file under the terms of the BSD license as follows: @@ -45,9 +45,12 @@ class BooksSettings : public QObject Q_OBJECT Q_ENUMS(FontSize) Q_ENUMS(Orientation) + Q_ENUMS(Action) Q_PROPERTY(int fontSize READ fontSize WRITE setFontSize NOTIFY fontSizeChanged) Q_PROPERTY(int pageDetails READ pageDetails WRITE setPageDetails NOTIFY pageDetailsChanged) Q_PROPERTY(bool invertColors READ invertColors WRITE setInvertColors NOTIFY invertColorsChanged) + Q_PROPERTY(int volumeUpAction READ volumeUpAction WRITE setVolumeUpAction NOTIFY volumeUpActionChanged) + Q_PROPERTY(int volumeDownAction READ volumeDownAction WRITE setVolumeDownAction NOTIFY volumeDownActionChanged) Q_PROPERTY(QObject* currentBook READ currentBook WRITE setCurrentBook NOTIFY currentBookChanged) Q_PROPERTY(QString currentFolder READ currentFolder WRITE setCurrentFolder NOTIFY currentFolderChanged) Q_PROPERTY(QString currentStorage READ currentStorage NOTIFY currentStorageChanged) @@ -60,9 +63,6 @@ class BooksSettings : public QObject Q_PROPERTY(int orientation READ orientation NOTIFY orientationChanged) class TextStyle; - // Use sharedInstance() to instantiate this class - BooksSettings(); - public: enum FontSize { MinFontSize = -5, @@ -77,6 +77,14 @@ public: OrientationLandscape }; + enum Action { + ActionNone, + ActionPreviousPage, + ActionNextPage + }; + + // Use sharedInstance() to instantiate this class + explicit BooksSettings(QObject* aParent = Q_NULLPTR); static QSharedPointer sharedInstance(); Q_INVOKABLE bool increaseFontSize(); @@ -93,6 +101,12 @@ public: bool invertColors() const; void setInvertColors(bool aValue); + Action volumeUpAction() const; + void setVolumeUpAction(int aValue); + + Action volumeDownAction() const; + void setVolumeDownAction(int aValue); + QObject* currentBook() const; void setCurrentBook(QObject* aBook); @@ -113,6 +127,8 @@ Q_SIGNALS: void textStyleChanged(); void pageDetailsChanged(); void invertColorsChanged(); + void volumeUpActionChanged(); + void volumeDownActionChanged(); void currentBookChanged(); void currentFolderChanged(); void currentStorageChanged(); diff --git a/app/src/ZLibrary.cpp b/app/src/ZLibrary.cpp index c38ffd8..4f61a77 100644 --- a/app/src/ZLibrary.cpp +++ b/app/src/ZLibrary.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2016 Jolla Ltd. + * Copyright (C) 2015-2017 Jolla Ltd. * Contact: Slava Monich * * You may use this file under the terms of the BSD license as follows: @@ -36,6 +36,8 @@ #include "BooksPaintContext.h" #include "BooksDialogManager.h" #include "BooksImageProvider.h" +#include "BooksMediaPlugin.h" +#include "BooksPolicyPlugin.h" #include "BooksSettings.h" #include "HarbourDebug.h" @@ -199,9 +201,15 @@ void ZLibrary::run(ZLApplication* aApp) QQuickView* view = SailfishApp::createView(); QQmlContext* root = view->rootContext(); + QQmlEngine* engine = root->engine(); QSharedPointer settings = BooksSettings::sharedInstance(); - root->engine()->addImageProvider(BooksImageProvider::PROVIDER_ID, + BooksPolicyPlugin::registerTypes(engine, BOOKS_QML_PLUGIN, + BOOKS_QML_PLUGIN_V1, BOOKS_QML_PLUGIN_V2); + BooksMediaPlugin::registerTypes(engine, BOOKS_QML_PLUGIN, + BOOKS_QML_PLUGIN_V1, BOOKS_QML_PLUGIN_V2); + engine->addImageProvider(BooksImageProvider::PROVIDER_ID, new BooksImageProvider(root)); + root->setContextProperty("PointsPerInch", booksPPI); root->setContextProperty("MaximumHintCount", 1); root->setContextProperty("BooksSettingsMenu", diff --git a/app/src/main.cpp b/app/src/main.cpp index cb3156e..770a07c 100644 --- a/app/src/main.cpp +++ b/app/src/main.cpp @@ -83,6 +83,7 @@ Q_DECL_EXPORT int main(int argc, char **argv) BOOKS_QML_REGISTER(BooksListWatcher, "ListWatcher"); BOOKS_QML_REGISTER(BooksCoverWidget, "BookCover"); BOOKS_QML_REGISTER(BooksHints, "BooksHints"); + BOOKS_QML_REGISTER(BooksSettings, "BooksSettings"); HarbourLib::registerTypes(BOOKS_QML_PLUGIN, BOOKS_QML_PLUGIN_V1, BOOKS_QML_PLUGIN_V2); diff --git a/app/translations/harbour-books-de.ts b/app/translations/harbour-books-de.ts index 4b78514..25cb1ee 100644 --- a/app/translations/harbour-books-de.ts +++ b/app/translations/harbour-books-de.ts @@ -99,11 +99,31 @@ Import page placeholder Keine neuen Bücher gefunden + + Link + External link menu title + Link + + + Open in browser + Open link in browser + Im Browser öffnen + + + Copy to clipboard + Copy link to clipboard + In Zwischenablage kopieren + Books Settings page header Bücher + + Display + Section header for display settings + Display + Font size Slider label @@ -134,6 +154,36 @@ Combo box value for landscape orientation Querformat + + No action + Combo box value for no action + Keine Aktion + + + Previous page + Combo box value for previous page action + Vorherige Seite + + + Next page + Combo box value for next page action + Folge Seite + + + Media keys + Section header for media keys + Medienschlüssel + + + Volume up + Combo box label + Lautstärke erhöhen + + + Volume down + Combo box label + Lautstärke runter + Memory card Section header for memory card settings @@ -149,21 +199,5 @@ Settings field description Lassen Sie den Verzeichnisnamen leer, um die gesamte Speicherkarte für Bücher zu scannen. - - Link - External link - External link menu title - Link - - - Open in browser - Open link in browser - Im Browser öffnen - - - Copy to clipboard - Copy link to clipboard - In Zwischenablage kopieren - diff --git a/app/translations/harbour-books-fi.ts b/app/translations/harbour-books-fi.ts index de4e186..50ca6dc 100644 --- a/app/translations/harbour-books-fi.ts +++ b/app/translations/harbour-books-fi.ts @@ -99,11 +99,31 @@ Import page placeholder Uusia kirjoja ei löytynyt + + Link + External link menu title + Linkki + + + Open in browser + Open link in browser + Avaa selaimessa + + + Copy to clipboard + Copy link to clipboard + Kopioi leikepöydälle + Books Settings page header Kirjat + + Display + Section header for display settings + Näyttö + Font size Slider label @@ -134,6 +154,36 @@ Combo box value for landscape orientation Vaaka + + No action + Combo box value for no action + Ei käytössä + + + Previous page + Combo box value for previous page action + Edelliselle sivulle + + + Next page + Combo box value for next page action + Seuraavalle sivulle + + + Media keys + Section header for media keys + Media näppäimet + + + Volume up + Combo box label + Äänenvoimakkuus ylös + + + Volume down + Combo box label + Äänenvoimakkuus alas + Memory card Section header for memory card settings @@ -149,21 +199,5 @@ Settings field description Jätä kenttä tyhjäksi käyttää kokonaista muistikorttia. - - Link - External link - External link menu title - Linkki - - - Open in browser - Open link in browser - Avaa selaimessa - - - Copy to clipboard - Copy link to clipboard - Kopioi leikepöydälle - diff --git a/app/translations/harbour-books-ru.ts b/app/translations/harbour-books-ru.ts index a05694a..b2c1a25 100644 --- a/app/translations/harbour-books-ru.ts +++ b/app/translations/harbour-books-ru.ts @@ -101,11 +101,31 @@ Import page placeholder Новых книг не найдено, вообще ни одной + + Link + External link menu title + Ссылка + + + Open in browser + Open link in browser + Открыть в браузере + + + Copy to clipboard + Copy link to clipboard + Скопировать + Books Settings page header Книги + + Display + Section header for display settings + Экран + Font size Slider label @@ -151,20 +171,35 @@ Settings field description Если оставить имя папки пустым, то можно будет найти книгу в любой папке на карте памяти. Особого смысла в этой настройке нет, просто так исторически сложилось, что по умолчанию книги искались только в папке Books, а теперь можно вообще где угодно. - - Link - External link menu title - Ссылка + + Media keys + Section header for media keys + Кнопки - - Open in browser - Open link in browser - Открыть в браузере + + No action + Combo box value for no action + Ничего не делать - - Copy to clipboard - Copy link to clipboard - Скопировать + + Previous page + Combo box value for previous page action + Предыдущая страница + + + Next page + Combo box value for next page action + Следующая страница + + + Volume up + Combo box label + Громкость вверх + + + Volume down + Combo box label + Громкость вниз diff --git a/app/translations/harbour-books-sv.ts b/app/translations/harbour-books-sv.ts index eec160f..eb5c65f 100644 --- a/app/translations/harbour-books-sv.ts +++ b/app/translations/harbour-books-sv.ts @@ -99,11 +99,31 @@ Import page placeholder Inga nya böcker hittades + + Link + External link menu title + Extern länk + + + Open in browser + Open link in browser + Öppna i webbläsaren + + + Copy to clipboard + Copy link to clipboard + Kopiera till urklipp + Books Settings page header Böcker + + Display + Section header for display settings + Skärm + Font size Slider label @@ -134,6 +154,36 @@ Combo box value for landscape orientation Liggande + + No action + Combo box value for no action + Ingen action + + + Previous page + Combo box value for previous page action + Föregående sida + + + Next page + Combo box value for next page action + Nästa sida + + + Media keys + Section header for media keys + Mediaknappar + + + Volume up + Combo box label + Höj volymen + + + Volume down + Combo box label + Sänk volymen + Memory card Section header for memory card settings @@ -149,21 +199,5 @@ Settings field description Lämna mappnamnet tomt för att söka igenom hela minneskortet efter böcker. - - Link - External link - External link menu title - Extern länk - - - Open in browser - Open link in browser - Öppna i webbläsaren - - - Copy to clipboard - Copy link to clipboard - Kopiera till urklipp - diff --git a/app/translations/harbour-books.ts b/app/translations/harbour-books.ts index 7cb9454..d8ccf99 100644 --- a/app/translations/harbour-books.ts +++ b/app/translations/harbour-books.ts @@ -65,7 +65,7 @@ Settings Pulley menu item - + Settings Scan downloads @@ -99,11 +99,31 @@ Import page placeholder No new books found + + Link + External link menu title + Link + + + Open in browser + Open link in browser + Open in browser + + + Copy to clipboard + Copy link to clipboard + Copy to clipboard + Books Settings page header Books + + Display + Section header for display settings + Display + Font size Slider label @@ -134,6 +154,36 @@ Combo box value for landscape orientation Landscape + + Media keys + Section header for media keys + Media keys + + + Volume up + Combo box label + Volume up + + + Volume down + Combo box label + Volume down + + + No action + Combo box value for no action + No action + + + Previous page + Combo box value for previous page action + Previous page + + + Next page + Combo box value for next page action + Next page + Memory card Section header for memory card settings @@ -149,20 +199,5 @@ Settings field description Leave the folder name empty to scan the entire memory card for books. - - Link - External link menu title - Link - - - Open in browser - Open link in browser - Open in browser - - - Copy to clipboard - Copy link to clipboard - Copy to clipboard -