Skip to content

Commit

Permalink
[foilnotes] Show QR code for the current note
Browse files Browse the repository at this point in the history
Via "Show QR code" pulley menu item
  • Loading branch information
monich committed Apr 29, 2019
1 parent 3a407f3 commit e1b625b
Show file tree
Hide file tree
Showing 19 changed files with 534 additions and 6 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@
[submodule "libglibutil"]
path = libglibutil
url = https://github.com/monich/libglibutil.git
[submodule "libqrencode"]
path = libqrencode
url = https://github.com/fukuchi/libqrencode.git
17 changes: 13 additions & 4 deletions app.pro
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ LIBFOILMSG_DIR = $${FOIL_DIR}/libfoilmsg
LIBFOILMSG_INCLUDE = $${LIBFOILMSG_DIR}/include
LIBFOILMSG_SRC = $${LIBFOILMSG_DIR}/src

LIBQRENCODE_DIR = $${_PRO_FILE_PWD_}/libqrencode

# Libraries
LIBS += -ldl
LIBS += libqrencode.a -ldl

OTHER_FILES += \
*.desktop \
Expand All @@ -60,7 +62,8 @@ INCLUDEPATH += \
$${LIBFOIL_SRC} \
$${LIBFOIL_INCLUDE} \
$${LIBFOILMSG_INCLUDE} \
$${LIBGLIBUTIL_INCLUDE}
$${LIBGLIBUTIL_INCLUDE} \
$${LIBQRENCODE_DIR}

HEADERS += \
src/FoilNotes.h \
Expand All @@ -70,7 +73,9 @@ HEADERS += \
src/FoilNotesModel.h \
src/FoilNotesPlaintextModel.h \
src/FoilNotesSearchModel.h \
src/FoilNotesSettings.h
src/FoilNotesSettings.h \
src/QrCodeGenerator.h \
src/QrCodeImageProvider.h

SOURCES += \
src/FoilNotes.cpp \
Expand All @@ -80,7 +85,9 @@ SOURCES += \
src/FoilNotesPlaintextModel.cpp \
src/FoilNotesSearchModel.cpp \
src/FoilNotesSettings.cpp \
src/main.cpp
src/main.cpp \
src/QrCodeGenerator.cpp \
src/QrCodeImageProvider.cpp

SOURCES += \
$${LIBFOIL_SRC}/*.c \
Expand All @@ -99,6 +106,7 @@ INCLUDEPATH += \
$${HARBOUR_LIB_DIR}/include

HEADERS += \
$${HARBOUR_LIB_INCLUDE}/HarbourBase32.h \
$${HARBOUR_LIB_INCLUDE}/HarbourDebug.h \
$${HARBOUR_LIB_INCLUDE}/HarbourImageProvider.h \
$${HARBOUR_LIB_INCLUDE}/HarbourOrganizeListModel.h \
Expand All @@ -108,6 +116,7 @@ HEADERS += \
$${HARBOUR_LIB_SRC}/HarbourMce.h

SOURCES += \
$${HARBOUR_LIB_SRC}/HarbourBase32.cpp \
$${HARBOUR_LIB_SRC}/HarbourImageProvider.cpp \
$${HARBOUR_LIB_SRC}/HarbourMce.cpp \
$${HARBOUR_LIB_SRC}/HarbourOrganizeListModel.cpp \
Expand Down
6 changes: 5 additions & 1 deletion harbour-foilnotes.pro
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
TEMPLATE = subdirs
SUBDIRS = app
SUBDIRS = app qrencode

app.file = app.pro
app.depends = qrencode-target

qrencode.file = qrencode.pro
qrencode.target = qrencode-target

OTHER_FILES += README.md LICENSE rpm/*.spec
1 change: 1 addition & 0 deletions libqrencode
Submodule libqrencode added at 59ee59
18 changes: 17 additions & 1 deletion qml/NotePage.qml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import QtQuick 2.2
import QtQuick 2.0
import Sailfish.Silica 1.0
import harbour.foilnotes 1.0

Expand Down Expand Up @@ -47,6 +47,12 @@ Page {
saveBody(body)
}

QrCodeGenerator {
id: generator

text: page.body
}

SilicaFlickable {
id: noteview

Expand All @@ -61,6 +67,16 @@ Page {
visible: enabled
onClicked: page.performAction()
}
MenuItem {
//: Show QR code for the current note
//% "Show QR code"
text: qsTrId("foilnotes-menu-show_qrcode")
visible: generator.qrcode !== ""
onClicked: pageStack.push("QrCodePage.qml", {
qrcode: generator.qrcode,
allowedOrientations: page.allowedOrientations
})
}
MenuItem {
//: Select note color
//% "Select color"
Expand Down
33 changes: 33 additions & 0 deletions qml/QrCodePage.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
import harbour.foilnotes 1.0

Page {
id: page

property string qrcode
readonly property int actualWidth: isPortrait ? Screen.width : Screen.height
readonly property int actualHeight: isPortrait ? Screen.height : Screen.width

Rectangle {
color: "white"
x: (actualWidth - width)/2
y: (actualHeight - height)/2
width: qrcodeImage.width + 2 * Theme.horizontalPageMargin
height: qrcodeImage.height + 2 * Theme.horizontalPageMargin

Image {
id: qrcodeImage

asynchronous: true
anchors.centerIn: parent
source: page.qrcode ? "image://qrcode/" + page.qrcode : ""
readonly property int maxDisplaySize: Math.min(Screen.width, Screen.height) - 4 * Theme.horizontalPageMargin
readonly property int maxSourceSize: Math.max(sourceSize.width, sourceSize.height)
readonly property int n: Math.floor(maxDisplaySize/maxSourceSize)
width: sourceSize.width * n
height: sourceSize.height * n
smooth: false
}
}
}
28 changes: 28 additions & 0 deletions qrencode.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
TEMPLATE = lib
CONFIG += static
TARGET = qrencode
QT-= gui

SRC_DIR = $${_PRO_FILE_PWD_}/libqrencode

MAJOR_VERSION = 4
MINOR_VERSION = 0
MICRO_VERSION = 2

DEFINES += \
STATIC_IN_RELEASE=static \
MAJOR_VERSION=$${MAJOR_VERSION} \
MINOR_VERSION=$${MINOR_VERSION} \
MICRO_VERSION=$${MICRO_VERSION} \
VERSION=\\\"$${MAJOR_VERSION}.$${MINOR_VERSION}.$${MICRO_VERSION}\\\"

SOURCES += \
$${SRC_DIR}/bitstream.c \
$${SRC_DIR}/mask.c \
$${SRC_DIR}/mmask.c \
$${SRC_DIR}/mqrspec.c \
$${SRC_DIR}/rsecc.c \
$${SRC_DIR}/split.c \
$${SRC_DIR}/qrencode.c \
$${SRC_DIR}/qrinput.c \
$${SRC_DIR}/qrspec.c
210 changes: 210 additions & 0 deletions src/QrCodeGenerator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
/*
* Copyright (C) 2019 Jolla Ltd.
* Copyright (C) 2019 Slava Monich <[email protected]>
*
* 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:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the names of the copyright holders 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 "QrCodeGenerator.h"

#include "HarbourBase32.h"
#include "HarbourTask.h"
#include "HarbourDebug.h"

#include <QThreadPool>

#include "qrencode.h"

// ==========================================================================
// QrCodeGenerator::Task
// ==========================================================================

class QrCodeGenerator::Task : public HarbourTask {
Q_OBJECT
public:
Task(QThreadPool* aPool, QString aText);
static QByteArray toQrCode(QString aText);
void performTask() Q_DECL_OVERRIDE;
public:
QString iText;
QString iQrCode;
};

QrCodeGenerator::Task::Task(QThreadPool* aPool, QString aText) :
HarbourTask(aPool),
iText(aText)
{
}

QByteArray QrCodeGenerator::Task::toQrCode(QString aText)
{
QByteArray in(aText.toUtf8()), out;
QRcode* code = QRcode_encodeString(in.constData(), 0, QR_ECLEVEL_M, QR_MODE_8, true);
if (code) {
const int bytesPerRow = (code->width + 7) / 8;
if (bytesPerRow > 0) {
out.reserve(bytesPerRow * code->width);
for (int y = 0; y < code->width; y++) {
const unsigned char* row = code->data + (code->width * y);
char c = (row[0] & 1);
int x = 1;
for (; x < code->width; x++) {
if (!(x % 8)) {
out.append(&c, 1);
c = row[x] & 1;
} else {
c = (c << 1) | (row[x] & 1);
}
}
const int rem = x % 8;
if (rem) {
// Most significant bit first
c <<= (8 - rem);
}
out.append(&c, 1);
}
}
QRcode_free(code);
}
return out;
}

void QrCodeGenerator::Task::performTask()
{
QByteArray bytes(toQrCode(iText));
if (!bytes.isEmpty()) {
iQrCode = HarbourBase32::toBase32(bytes);
}
}

// ==========================================================================
// QrCodeGenerator::Private
// ==========================================================================

class QrCodeGenerator::Private : public QObject {
Q_OBJECT

public:
Private(QrCodeGenerator* aParent);
~Private();

QrCodeGenerator* parentObject() const;
void setText(QString aValue);

public Q_SLOTS:
void onTaskDone();

public:
QThreadPool* iThreadPool;
Task* iTask;
QString iText;
QString iQrCode;
};

QrCodeGenerator::Private::Private(QrCodeGenerator* aParent) :
QObject(aParent),
iThreadPool(new QThreadPool(this)),
iTask(Q_NULLPTR)
{
// Serialize the tasks:
iThreadPool->setMaxThreadCount(1);
}

QrCodeGenerator::Private::~Private()
{
iThreadPool->waitForDone();
}

inline QrCodeGenerator* QrCodeGenerator::Private::parentObject() const
{
return qobject_cast<QrCodeGenerator*>(parent());
}

void QrCodeGenerator::Private::setText(QString aText)
{
if (iText != aText) {
iText = aText;
QrCodeGenerator* obj = parentObject();
const bool wasRunning = (iTask != Q_NULLPTR);
if (iTask) iTask->release(this);
iTask = new Task(iThreadPool, aText);
iTask->submit(this, SLOT(onTaskDone()));
Q_EMIT obj->textChanged();
if (!wasRunning) {
Q_EMIT obj->runningChanged();
}
}
}

void QrCodeGenerator::Private::onTaskDone()
{
if (sender() == iTask) {
QrCodeGenerator* obj = parentObject();
const bool qrCodeChanged = (iQrCode != iTask->iQrCode);
iQrCode = iTask->iQrCode;
iTask->release();
iTask = NULL;
if (qrCodeChanged) {
Q_EMIT obj->qrcodeChanged();
}
Q_EMIT obj->runningChanged();
}
}

// ==========================================================================
// QrCodeGenerator
// ==========================================================================

QrCodeGenerator::QrCodeGenerator(QObject* aParent) :
QObject(aParent),
iPrivate(new Private(this))
{
}

QString QrCodeGenerator::text() const
{
return iPrivate->iText;
}

void QrCodeGenerator::setText(QString aValue)
{
iPrivate->setText(aValue);
}

QString QrCodeGenerator::qrcode() const
{
return iPrivate->iQrCode;
}

bool QrCodeGenerator::running() const
{
return iPrivate->iTask != Q_NULLPTR;
}

#include "QrCodeGenerator.moc"
Loading

0 comments on commit e1b625b

Please sign in to comment.