From ab889e44eb404838149342ab365735b1497f67fa Mon Sep 17 00:00:00 2001 From: TomZ Date: Wed, 4 Mar 2026 18:52:35 +0100 Subject: [PATCH] Update to version of March 2026 --- .SRCINFO | 10 +- 0001-Fix-off-by-one-in-unit-test.patch | 25 - 0001-Port-to-new-ZXing-version-3.patch | 1156 ------------------------ PKGBUILD | 10 +- 4 files changed, 5 insertions(+), 1196 deletions(-) delete mode 100644 0001-Fix-off-by-one-in-unit-test.patch delete mode 100644 0001-Port-to-new-ZXing-version-3.patch diff --git a/.SRCINFO b/.SRCINFO index 2f3e21b..100b9be 100644 --- a/.SRCINFO +++ b/.SRCINFO @@ -1,6 +1,6 @@ pkgbase = flowee-pay pkgdesc = Flowee Payment solution - pkgver = 2026.02.1 + pkgver = 2026.03.0 pkgrel = 1 url = http://flowee.org/pay/ install = flowee-pay.install @@ -20,13 +20,9 @@ pkgbase = flowee-pay depends = qt6-multimedia provides = flowee-pay options = !lto - source = https://codeberg.org/Flowee/pay/archive/2026.02.1.tar.gz - source = 0001-Fix-off-by-one-in-unit-test.patch - source = 0001-Port-to-new-ZXing-version-3.patch + source = https://codeberg.org/Flowee/pay/archive/2026.03.0.tar.gz source = https://flowee.org/products/pay/blockheaders-850000 - sha256sums = a3a8443e6236498fa384478366c8b35dea5c7cec3b8b9b06d5b0ba9a835d2b95 - sha256sums = f7e4bf13406b1836fb0e80b97f01d8f5098b3c4c9de230ac5463c009a5019316 - sha256sums = 2a31e641e19432c77b467876fce30517378fd1dd646ad05e1d53d1476cf99ebf + sha256sums = 167b020d17b427f0e0ee0a1af754f5dbc89084a546610a0f68ce35ff18d36057 sha256sums = 4a98c3b655cfd7520b4d4f682d95e3a82e0f03fda4fa687d28f2127205d66047 pkgname = flowee-pay diff --git a/0001-Fix-off-by-one-in-unit-test.patch b/0001-Fix-off-by-one-in-unit-test.patch deleted file mode 100644 index 84ee08d..0000000 --- a/0001-Fix-off-by-one-in-unit-test.patch +++ /dev/null @@ -1,25 +0,0 @@ -From e676015393ad1c59b3b7261bf54ce64e321e8ee7 Mon Sep 17 00:00:00 2001 -From: TomZ -Date: Sat, 14 Feb 2026 16:55:23 +0100 -Subject: [PATCH] Fix off by one in unit test. - ---- - testing/walletHistoryModel/TestWalletHistoryModel.cpp | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/testing/walletHistoryModel/TestWalletHistoryModel.cpp b/testing/walletHistoryModel/TestWalletHistoryModel.cpp -index 6cb9077..3f92ca8 100644 ---- a/testing/walletHistoryModel/TestWalletHistoryModel.cpp -+++ b/testing/walletHistoryModel/TestWalletHistoryModel.cpp -@@ -88,7 +88,7 @@ void TestWalletHistoryModel::basic() - QCOMPARE(model->rowCount(), 0); - wallet->createTransactions1(); - model->notifyNewTransactions(1, 6000); // wallet starts counting at 1 -- QCOMPARE(model->rowCount(), 6001); // The model auto-inserts one 'since last seen' row. -+ QCOMPARE(model->rowCount(), 6000); // The model auto-inserts one 'since last seen' row. - - auto first = model->data(model->index(0, 0), WalletHistoryModel::MinedHeight); - QVERIFY(first.isValid()); --- -2.52.0 - diff --git a/0001-Port-to-new-ZXing-version-3.patch b/0001-Port-to-new-ZXing-version-3.patch deleted file mode 100644 index 8aa4be2..0000000 --- a/0001-Port-to-new-ZXing-version-3.patch +++ /dev/null @@ -1,1156 +0,0 @@ -From 3d2911eb08a34f5df202ef1d9edee575ad89abaf Mon Sep 17 00:00:00 2001 -From: TomZ -Date: Mon, 16 Feb 2026 14:34:28 +0100 -Subject: [PATCH] Port to new ZXing version 3 - -The new ZXingCpp release is out, it is a major version (v3) and -it has broken source compatibility towards version 2. - -The good news is that we can actually cut out quite a lot of -boring code which is now done in the upstream project. - -But to actually benefit from better readability I think the best -approach is the "isolate the old" idea. So this copies the v2 -compatible file to CameraController_zxing2.cpp QRCreator_zxing2.cpp -We'll have code duplication that way, but it will never be compiled -into the same binary and indeed we'll just be cleanly able to -delete the old support when that time comes. ---- - CMakeLists.txt | 4 +- - src/CMakeLists.txt | 23 +- - src/CameraController.cpp | 129 +----- - src/CameraController_zxing2.cpp | 725 ++++++++++++++++++++++++++++++++ - src/QRCreator.cpp | 35 +- - src/QRCreator_zxing2.cpp | 71 ++++ - 6 files changed, 835 insertions(+), 152 deletions(-) - create mode 100644 src/CameraController_zxing2.cpp - create mode 100644 src/QRCreator_zxing2.cpp - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 3ffa53e..a0709dc 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -60,6 +60,7 @@ if (ANDROID) - set_property(TARGET ZXing::ZXing PROPERTY IMPORTED_LINK_INTERFACE_LIBRARIES - "/opt/android-zxing/lib/libZXing.a") - set (ZXing_FOUND TRUE) -+ set (ZXing_VERSION_MAJOR 2) - else () - find_package(ZXing REQUIRED) - endif() -@@ -67,6 +68,7 @@ else () - find_package(Qt6 COMPONENTS DBus LinguistTools) - find_package(ZXing REQUIRED) - endif() -+ - if (CMAKE_VERSION VERSION_GREATER "3.29.9") - # use the upstream boost info instead of the cmake-shipped one for finding - # this policy was introduced in cmake 3.30 -@@ -261,7 +263,7 @@ if (build_desktop_pay) - ) - add_executable(pay ${SOURCES_PAY}) - set_target_properties(pay PROPERTIES COMPILE_DEFINITIONS "${COMPILE_DEFINITIONS} DESKTOP") -- target_link_libraries(pay PRIVATE pay_lib Qt6::Svg ${PAY_MODULES_LIBS}) -+ target_link_libraries(pay PRIVATE Qt6::Svg ${PAY_MODULES_LIBS}) - install(TARGETS pay DESTINATION bin) - endif() - -diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt -index 78e7db6..822794f 100644 ---- a/src/CMakeLists.txt -+++ b/src/CMakeLists.txt -@@ -1,5 +1,5 @@ - # This file is part of the Flowee project --# Copyright (C) 2020-2025 Tom Zander -+# Copyright (C) 2020-2026 Tom Zander - # - # This program is free software: you can redistribute it and/or modify - # it under the terms of the GNU General Public License as published by -@@ -43,7 +43,6 @@ set (PAY_SOURCES - PriceHistoryDataProvider.cpp - QMLClipboardHelper.cpp - QMLImportHelper.cpp -- QRCreator.cpp - QRScanner.cpp - RepeatPaymentDetails.cpp - RepeatPaymentsModel.cpp -@@ -91,15 +90,29 @@ else () - ) - endif () - --if (NetworkLogClient) -- list(APPEND PAY_SOURCES NetworkLogClient.cpp) -+if (ZXing_VERSION_MAJOR EQUAL 2) -+ message(STATUS "Using ZXing 2.x") -+ list(APPEND PAY_SOURCES QRCreator_zxing2.cpp) -+elseif (ZXing_VERSION_MAJOR EQUAL 3) -+ message(STATUS "Using ZXing 3.x") -+ list(APPEND PAY_SOURCES QRCreator.cpp) -+else () -+ message(FATAL_ERROR "Unsupported ZXing version: ${ZXing_VERSION}") - endif () - - if (${Qt6Multimedia_FOUND}) -- list(APPEND PAY_SOURCES CameraController.cpp) -+ if (ZXing_VERSION_MAJOR EQUAL 2) -+ list(APPEND PAY_SOURCES CameraController_zxing2.cpp) -+ else () -+ list(APPEND PAY_SOURCES CameraController.cpp) -+ endif () - list(APPEND PayLib_PRIVATE_LIBS Qt6::Multimedia) - endif () - -+if (NetworkLogClient) -+ list(APPEND PAY_SOURCES NetworkLogClient.cpp) -+endif () -+ - add_library(pay_lib STATIC ${PAY_SOURCES}) - - target_link_libraries(pay_lib -diff --git a/src/CameraController.cpp b/src/CameraController.cpp -index 9d69952..7ec27dc 100644 ---- a/src/CameraController.cpp -+++ b/src/CameraController.cpp -@@ -1,7 +1,6 @@ - /* - * This file is part of the Flowee project -- * Copyright (C) 2022-2025 Tom Zander -- * Copyright (C) 2020 Axel Waggershauser -+ * Copyright (C) 2022-2026 Tom Zander - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -21,8 +20,6 @@ - #include "base58.h" - #include - --#include -- - #include - #include - #include -@@ -34,6 +31,10 @@ - #include - #include - -+#include -+// force Qt to moc this external header file. -+#include "ZXing/moc_ZXingQt.cpp" -+ - enum AskingState { - NotAsked, - Denied, -@@ -85,14 +86,13 @@ public: - protected: - void run(); - private: -+#if ZXING_VERSION_MAJOR < 3 - std::vector readBarcodes(const QImage &img) const; - std::vector readBarcodes(QVideoFrame &frame) const; -+#endif - - CameraControllerPrivate *m_parent; -- // notice that since ZXIng 2.2.0 this is renamed to 'ReaderOptions'. -- // this was released in December 2023, so we'll be using the old stuff -- // for quite a bit longer to keep stuff compiling on older systems. -- ZXing::DecodeHints m_decodeHints; -+ ZXing::ReaderOptions m_decodeHints; - }; - - -@@ -278,7 +278,8 @@ void QRScanningThread::run() - return; - - lastFrameScanned = time(nullptr); -- auto results = readBarcodes(frame); -+ -+ const auto results = ZXingQt::ReadBarcodes(frame); - for (const auto &result : results) { - const auto &bytes = result.bytes(); - // logInfo(10005) << "result:" << QString::fromUtf8(reinterpret_cast(bytes.data()), bytes.size()); -@@ -288,7 +289,7 @@ void QRScanningThread::run() - // first, when it starts with 'bch-wif:' this helps, but needs to be cut off. - const bool wifPrefix = bytes.size() >= 58 && bytes.size() < 63 - && (bytes[8] == 'K' || bytes[8] == 'L') -- && 0 == memcmp(&bytes[0], "bch-wif:", 8); -+ && 0 == memcmp(bytes.constData(), "bch-wif:", 8); - - if (wifPrefix || (bytes.size() >= 50 && bytes.size() < 55 && (bytes[0] == 'K' || bytes[0] == 'L'))) { - // might be one!! -@@ -378,114 +379,6 @@ void QRScanningThread::run() - } - } - --std::vector QRScanningThread::readBarcodes(const QImage &img) const --{ -- auto imageFormat = img.format(); -- if (imageFormat == QImage::Format_Invalid) // likely a damaged frame in the feed -- return {}; -- auto zxImageFormat = ZXing::ImageFormat::None; -- switch (imageFormat) { -- case QImage::Format_ARGB32: -- case QImage::Format_RGB32: --#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN -- zxImageFormat = ZXing::ImageFormat::BGRX; --#else -- zxImageFormat = ImageFormat::XRGB; --#endif -- break; -- case QImage::Format_RGB888: zxImageFormat = ZXing::ImageFormat::RGB; break; -- case QImage::Format_RGBX8888: -- case QImage::Format_RGBA8888: zxImageFormat = ZXing::ImageFormat::RGBX; break; -- case QImage::Format_Grayscale8: zxImageFormat = ZXing::ImageFormat::Lum; break; -- default: break; -- } -- -- if (zxImageFormat == ZXing::ImageFormat::None) { -- QImage gray = img.convertToFormat(QImage::Format_Grayscale8) ; -- return ZXing::ReadBarcodes({gray.bits(), gray.width(), gray.height(), ZXing::ImageFormat::Lum, static_cast(gray.bytesPerLine())}, m_decodeHints); -- } -- -- ZXing::ImageView buf(img.bits(), img.width(), img.height(), zxImageFormat, static_cast(img.bytesPerLine())); -- return ZXing::ReadBarcodes(buf, m_decodeHints); --} -- --std::vector QRScanningThread::readBarcodes(QVideoFrame &frame) const --{ -- ZXing::ImageFormat fmt = ZXing::ImageFormat::None; -- int pixStride = 0; -- int pixOffset = 0; -- -- // note that the comments behind the values are the Qt5 formats. -- switch (frame.pixelFormat()) { -- case QVideoFrameFormat::Format_ARGB8888: // ARGB32 -- case QVideoFrameFormat::Format_ARGB8888_Premultiplied: // ARGB32_Premultiplied -- case QVideoFrameFormat::Format_RGBX8888: // RGB32 -- fmt = ZXing::ImageFormat::BGRX; -- break; -- case QVideoFrameFormat::Format_BGRA8888: // BGRA32 -- case QVideoFrameFormat::Format_BGRA8888_Premultiplied: // BGRA32_Premultiplied -- case QVideoFrameFormat::Format_BGRX8888: // BGR32 --#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN -- fmt = ZXing::ImageFormat::RGBX; --#else -- fmt = ImageFormat::XBGR; --#endif -- break; -- case QVideoFrameFormat::Format_P010: -- case QVideoFrameFormat::Format_P016: -- fmt = ZXing::ImageFormat::Lum, pixStride = 1; break; -- case QVideoFrameFormat::Format_AYUV: // AYUV444 -- case QVideoFrameFormat::Format_AYUV_Premultiplied: // AYUV444_Premultiplied --#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN -- fmt = ZXing::ImageFormat::Lum, pixStride = 4, pixOffset = 3; --#else -- fmt = ImageFormat::Lum, pixStride = 4, pixOffset = 2; --#endif -- break; -- case QVideoFrameFormat::Format_YUV420P: // YUV420P -- case QVideoFrameFormat::Format_NV12: // NV12 -- case QVideoFrameFormat::Format_NV21: // NV21 -- case QVideoFrameFormat::Format_IMC1: // IMC1 -- case QVideoFrameFormat::Format_IMC2: // IMC2 -- case QVideoFrameFormat::Format_IMC3: // IMC3 -- case QVideoFrameFormat::Format_IMC4: // IMC4 -- case QVideoFrameFormat::Format_YV12: // YV12 -- case QVideoFrameFormat::Format_Y8: // Y8 -- case QVideoFrameFormat::Format_YUV422P: // YUV422P -- fmt = ZXing::ImageFormat::Lum; break; -- case QVideoFrameFormat::Format_UYVY: // UYVY -- fmt = ZXing::ImageFormat::Lum, pixStride = 2, pixOffset = 1; break; -- case QVideoFrameFormat::Format_YUYV: // YUYV -- fmt = ZXing::ImageFormat::Lum, pixStride = 2; break; -- case QVideoFrameFormat::Format_Y16: // Y16 -- fmt = ZXing::ImageFormat::Lum, pixStride = 2, pixOffset = 1; break; -- -- case QVideoFrameFormat::Format_ABGR8888: // ABGR32 --#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN -- fmt = ZXing::ImageFormat::RGBX; --#else -- fmt = ZXing::ImageFormat::XBGR; --#endif -- break; -- default: break; -- } -- -- if (fmt != ZXing::ImageFormat::None) { -- if (!frame.isValid() || !frame.map(QVideoFrame::ReadOnly)){ -- logDebug(10005) << "invalid QVideoFrame: could not map memory"; -- return {}; -- } -- QScopeGuard unmap([&] { frame.unmap(); }); -- -- constexpr int FirstPlane = 0; -- return ZXing::ReadBarcodes( -- {frame.bits(FirstPlane) + pixOffset, frame.width(), frame.height(), fmt, frame.bytesPerLine(FirstPlane), pixStride}, m_decodeHints); -- } else { -- return readBarcodes(frame.toImage()); -- } --} -- -- - // -------------------------------------------------------------------- - - CameraController::CameraController(QObject *parent) -diff --git a/src/CameraController_zxing2.cpp b/src/CameraController_zxing2.cpp -new file mode 100644 -index 0000000..1ee6ad3 ---- /dev/null -+++ b/src/CameraController_zxing2.cpp -@@ -0,0 +1,725 @@ -+/* -+ * This file is part of the Flowee project -+ * Copyright (C) 2022-2025 Tom Zander -+ * Copyright (C) 2020 Axel Waggershauser -+ * -+ * This program is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program. If not, see . -+ */ -+#include "CameraController.h" -+#include "QRScanner.h" -+#include "base58.h" -+#include -+ -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+enum AskingState { -+ NotAsked, -+ Denied, -+ Authorized -+}; -+ -+class QRScanningThread; -+ -+class CameraControllerPrivate -+{ -+public: -+ explicit CameraControllerPrivate(CameraController *qq); -+ // Configure the camera -+ void initCamera(); -+ // check if we need to load the camera. -+ void checkState(); -+ -+ AskingState state; -+ QObject *camera = nullptr; -+ QObject *videoSink = nullptr; -+ QString helpText; -+ -+ QPointer scanRequest; -+ -+ mutable QMutex lock; -+ QVideoFrame currentFrame; -+ QCameraFormat preferredFormat; -+ -+ bool cameraLoaded = false; -+ bool cameraStarted = false; -+ bool visible = false; -+ bool torchEnabled = false; -+ int streamWidth = -1; -+ int streamHeight = -1; -+ -+ QRScanningThread *scanningThread = nullptr; -+ -+ CameraController *q; -+}; -+ -+class QRScanningThread : public QThread -+{ -+public: -+ explicit QRScanningThread(CameraControllerPrivate *parent); -+ -+ QString text; -+ QRScanner::ScanType scanType; -+ -+protected: -+ void run(); -+private: -+ std::vector readBarcodes(const QImage &img) const; -+ std::vector readBarcodes(QVideoFrame &frame) const; -+ -+ CameraControllerPrivate *m_parent; -+ // notice that since ZXIng 2.2.0 this is renamed to 'ReaderOptions'. -+ // this was released in December 2023, so we'll be using the old stuff -+ // for quite a bit longer to keep stuff compiling on older systems. -+ ZXing::DecodeHints m_decodeHints; -+}; -+ -+ -+// -------------------------------------------------------------------- -+ -+CameraControllerPrivate::CameraControllerPrivate(CameraController *qq) -+ : state(NotAsked), -+ q(qq) -+{ -+#ifdef TARGET_OS_Android -+ auto guiApp = qobject_cast(QCoreApplication::instance()); -+ assert(guiApp); -+ QObject::connect(guiApp, &QGuiApplication::applicationStateChanged, qq, [=](Qt::ApplicationState appState) { -+ // the application state will turn to "Inactive" when the Android dialog -+ // asking permissions is put on top, and when the user enters data, we are -+ // turned into active again. -+ // So check if we are already authorized as that avoid us turning off -+ // the camera just after turning it on the first time. -+ if (state == Authorized && appState == Qt::ApplicationInactive) { -+ logInfo(10005) << "App state inactive, turning off camera"; -+ // when the user leaves the app screen, the permissions granted to us -+ // may have changed, so we need to re-ask. -+ state = NotAsked; -+ if (cameraStarted) { -+ // QtMultimedia doesn't like us not turning off the camera when we get small. -+ // so make sure we do, we also cancel the scan request. -+ lock.lock(); -+ cameraStarted = false; -+ lock.unlock(); -+ emit q->cameraActiveChanged(); -+ } -+ } -+ }); -+#endif -+} -+ -+void CameraControllerPrivate::initCamera() -+{ -+ QCamera *cam = qobject_cast(camera); -+ if (!cam) -+ return; -+ QCameraFormat preferred; -+ bool preferredIsCheap = false; -+ for (const auto &format : cam->cameraDevice().videoFormats()) { -+ bool formatIsCheap; // if true, we don't need to go via QImage (we avoid double conversion) -+ switch (format.pixelFormat()) { -+ case QVideoFrameFormat::Format_Invalid: -+ case QVideoFrameFormat::Format_XRGB8888: -+ case QVideoFrameFormat::Format_XBGR8888: -+ case QVideoFrameFormat::Format_RGBA8888: -+ case QVideoFrameFormat::Format_SamplerExternalOES: -+ case QVideoFrameFormat::Format_Jpeg: -+ case QVideoFrameFormat::Format_SamplerRect: -+ case QVideoFrameFormat::Format_YUV420P10: -+ formatIsCheap = false; -+ break; -+ default: -+ formatIsCheap = true; -+ break; -+ } -+ -+ logInfo(10005) << " + " << format.resolution().width() << "x" << format.resolution().height() -+ << "::" << format.pixelFormat() << formatIsCheap << "framerate:" -+ << format.minFrameRate() << "-" << format.maxFrameRate(); -+ -+ if (preferred.isNull()) { -+ preferred = format; -+ preferredIsCheap = formatIsCheap; -+ logInfo(10005) << "picked"; -+ } -+ else { -+ auto size = format.resolution(); -+ auto oldSize = preferred.resolution(); -+ if (preferredIsCheap && !formatIsCheap) -+ continue; -+ // avoid going for the biggest feed, but not too small either. -+ if (oldSize.width() < 800 || (size.width() < oldSize.width() && size.width() >= 800) -+ || (size.width() == oldSize.width() && size.height() > oldSize.height() && size.height() < 1000)) { -+ preferred = format; -+ logInfo(10005) << "picked"; -+ } -+ else if (size == oldSize && format.maxFrameRate() < preferred.maxFrameRate()) { -+ preferred = format; -+ logInfo(10005) << "picked"; -+ } -+ } -+ } -+ logCritical(10005).nospace() << "Selected camera resolution: " << preferred.resolution().width() << "x" << preferred.resolution().height(); -+ preferredFormat = preferred; -+} -+ -+void CameraControllerPrivate::checkState() -+{ -+ if (state != Authorized) -+ return; -+ if (!cameraLoaded || !visible) { -+ cameraLoaded = true; -+ visible = true; -+ emit q->visibleChanged(); -+ emit q->loadCameraChanged(); -+ -+ // then wait an event before turning on the actual camera -+ QTimer::singleShot(30, q, SLOT(checkState())); -+ return; -+ } -+ if (camera && videoSink && !cameraStarted && scanRequest.get()) { -+ QCamera *cam = qobject_cast(camera); -+ auto sink = qobject_cast(videoSink); -+ if (!cam || !sink) { // here to detect bug in QML -+ logFatal(10005) << "invalid or no camera or sink object set"; -+ return; -+ } -+ if (cam->error() != QCamera::NoError) -+ logFatal(10005) << "CameraController found cam error:" << cam->errorString(); -+ -+ if (!preferredFormat.isNull()) -+ cam->setCameraFormat(preferredFormat); -+ // best too least-acceptable focus mode. -+ constexpr QCamera::FocusMode f_modes[] = { QCamera::FocusModeAutoNear, QCamera::FocusModeAuto, -+ QCamera::FocusModeHyperfocal, QCamera::FocusModeInfinity }; -+ for (auto m : f_modes) { -+ if (cam->isFocusModeSupported(m)) { -+ cam->setFocusMode(m); -+ break; -+ } -+ } -+ constexpr QCamera::WhiteBalanceMode w_modess[] = { QCamera::WhiteBalanceShade, QCamera::WhiteBalanceAuto }; -+ for (auto m : w_modess) { -+ if (cam->isWhiteBalanceModeSupported(m)) { -+ cam->setWhiteBalanceMode(QCamera::WhiteBalanceAuto); -+ break; -+ } -+ } -+ constexpr QCamera::ExposureMode e_modes[] = { QCamera::ExposureBarcode, -+ QCamera::ExposurePortrait, QCamera::ExposureAuto }; -+ for (auto m : e_modes) { -+ if (cam->isExposureModeSupported(m)) { -+ cam->setExposureMode(m); -+ break; -+ } -+ } -+ cameraStarted = true; -+ QObject::connect(sink, &QVideoSink::videoFrameChanged, q, [=](const QVideoFrame &frame) { -+ currentFrame = frame; -+ }); -+ -+ assert(scanningThread == nullptr); -+ scanningThread = new QRScanningThread(this); -+ QObject::connect (scanningThread, SIGNAL(finished()), q, SLOT(qrScanFinished()), Qt::QueuedConnection); -+ scanningThread->start(); -+ -+ logDebug(10005) << "Camera active is now true"; -+ emit q->cameraActiveChanged(); // this emit makes QML activate the camera -+ } -+} -+ -+// -------------------------------------------------------------------- -+ -+QRScanningThread::QRScanningThread(CameraControllerPrivate *parent) -+ : scanType(QRScanner::InvalidType), -+ m_parent(parent) -+{ -+ m_decodeHints.setFormats(ZXing::BarcodeFormat::QRCode); -+ m_decodeHints.setTryHarder(true); -+} -+ -+void QRScanningThread::run() -+{ -+ auto lastFrameScanned = 0; -+ while (true) { -+ const auto now = time(nullptr); -+ auto sleep = 34 - (now - lastFrameScanned); // assume 30 - FPS -+ // Sleep if we are too fast and (assuming 33.3 ms per frame) we would end up -+ // parsing the same frame twice. -+ if (sleep > 0) -+ QThread::msleep(sleep); -+ -+ m_parent->lock.lock(); -+ bool exit = !m_parent->cameraStarted; -+ QVideoFrame frame = m_parent->currentFrame; -+ m_parent->lock.unlock(); -+ if (exit) -+ return; -+ -+ lastFrameScanned = time(nullptr); -+ auto results = readBarcodes(frame); -+ for (const auto &result : results) { -+ const auto &bytes = result.bytes(); -+ // logInfo(10005) << "result:" << QString::fromUtf8(reinterpret_cast(bytes.data()), bytes.size()); -+ -+ // Test if the QR held a Private key -+ // We support WIF encoded private keys. -+ // first, when it starts with 'bch-wif:' this helps, but needs to be cut off. -+ const bool wifPrefix = bytes.size() >= 58 && bytes.size() < 63 -+ && (bytes[8] == 'K' || bytes[8] == 'L') -+ && 0 == memcmp(&bytes[0], "bch-wif:", 8); -+ -+ if (wifPrefix || (bytes.size() >= 50 && bytes.size() < 55 && (bytes[0] == 'K' || bytes[0] == 'L'))) { -+ // might be one!! -+ const size_t prefixSize = wifPrefix ? 8 : 0; -+ const std::string str(reinterpret_cast(bytes.data() + prefixSize), bytes.size() - prefixSize); -+ std::vector dummy; -+ if (Base58::decodeCheck(str, dummy)) { -+ // good enough for me. Further checking is done by the app, we just exit scanning now. -+ scanType = QRScanner::PrivateKeyWIF; -+ text = QString::fromUtf8(str); -+ return; -+ } -+ } -+ -+ // Ok, what about a bip21 style url, or a plain address? -+ // -> starts with bitcoincash: (which is 12 chars, including that colon) -+ if (bytes.size() > 12 + 40 && memcmp("bitcoincash:", bytes.data(), 12) == 0) { -+ text = QString::fromUtf8(reinterpret_cast(bytes.data()), bytes.size()); -+ scanType = QRScanner::PaymentDetails; -+ return; -+ } -+ if (bytes.size() > 40 && bytes.size() < 45 && (bytes[0] == 'q' || bytes[0] == 'p')) { -+ // possibly a raw bitcoin cash address. -+ text = QString::fromUtf8(reinterpret_cast(bytes.data()), bytes.size()); -+ scanType = QRScanner::PaymentDetails; -+ return; -+ } -+ if (bytes.size() > 8 + 40 && memcmp("bchtest:", bytes.data(), 8) == 0) { -+ text = QString::fromUtf8(reinterpret_cast(bytes.data()), bytes.size()); -+ scanType = QRScanner::PaymentDetailsTestnet; -+ return; -+ } -+ -+ // not those then, ok. Then check if its a seed :-) -+ /* -+ * The Seed QR would obviously just use the 12 or 24 words sentence in a QR. -+ * Simple. -+ * -+ * But a pretty big wallet has instead put a bit more in the QR which ends up having -+ * the following content: -+ * -+ * 1|this holds twelve words|livenet|m/44'/0'/0'|false -+ * -+ * No clue what the leading 1 and the trailing false are about. All wallets I tried -+ * have those :shrug: -+ * -+ * Lets try to recognize those two types of QR. -+ * ------ -+ * While seeds can be verified with their checksum, here we just check if the general -+ * pattern fits. -+ * Only normal characters and spaces are allowed in the basic seed, and 12 words or 24 words. -+ */ -+ if (bytes.size() > 12 * 3 + 11) { // at least enough chars for a seed. -+ QString possibleSeed = QString::fromUtf8(reinterpret_cast(bytes.data()), bytes.size()); -+ if (possibleSeed.startsWith("1|") && possibleSeed.endsWith("|livenet|m/44'/0'/0'|false")) -+ possibleSeed = possibleSeed.mid(2, possibleSeed.length() - 28); -+ -+ int wordCount = 0; -+ bool seenSpace = false; -+ bool failedChecks = false; -+ for (auto i = 0; i < possibleSeed.size(); ++i) { -+ auto c = possibleSeed.at(i); -+ if (c.isDigit() || c.isSymbol()) { -+ failedChecks = true; -+ } -+ else if (c.isSpace()) { -+ if (seenSpace || i == 0) -+ failedChecks = true; // double space or leading space -+ seenSpace = true; -+ ++wordCount; -+ } -+ else if (c.isLetter()) { -+ seenSpace = false; -+ } -+ if (failedChecks) -+ break; -+ } -+ if (seenSpace == false && wordCount > 0) -+ ++wordCount; // one more word not registered due to lack of space after. -+ if (!failedChecks && (wordCount == 12 || wordCount == 24)) { -+ scanType = QRScanner::Seed; -+ text = possibleSeed; -+ return; -+ } -+ } -+ } -+ } -+} -+ -+std::vector QRScanningThread::readBarcodes(const QImage &img) const -+{ -+ auto imageFormat = img.format(); -+ if (imageFormat == QImage::Format_Invalid) // likely a damaged frame in the feed -+ return {}; -+ auto zxImageFormat = ZXing::ImageFormat::None; -+ switch (imageFormat) { -+ case QImage::Format_ARGB32: -+ case QImage::Format_RGB32: -+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN -+ zxImageFormat = ZXing::ImageFormat::BGRX; -+#else -+ zxImageFormat = ImageFormat::XRGB; -+#endif -+ break; -+ case QImage::Format_RGB888: zxImageFormat = ZXing::ImageFormat::RGB; break; -+ case QImage::Format_RGBX8888: -+ case QImage::Format_RGBA8888: zxImageFormat = ZXing::ImageFormat::RGBX; break; -+ case QImage::Format_Grayscale8: zxImageFormat = ZXing::ImageFormat::Lum; break; -+ default: break; -+ } -+ -+ if (zxImageFormat == ZXing::ImageFormat::None) { -+ QImage gray = img.convertToFormat(QImage::Format_Grayscale8) ; -+ return ZXing::ReadBarcodes({gray.bits(), gray.width(), gray.height(), ZXing::ImageFormat::Lum, static_cast(gray.bytesPerLine())}, m_decodeHints); -+ } -+ -+ ZXing::ImageView buf(img.bits(), img.width(), img.height(), zxImageFormat, static_cast(img.bytesPerLine())); -+ return ZXing::ReadBarcodes(buf, m_decodeHints); -+} -+ -+std::vector QRScanningThread::readBarcodes(QVideoFrame &frame) const -+{ -+ ZXing::ImageFormat fmt = ZXing::ImageFormat::None; -+ int pixStride = 0; -+ int pixOffset = 0; -+ -+ // note that the comments behind the values are the Qt5 formats. -+ switch (frame.pixelFormat()) { -+ case QVideoFrameFormat::Format_ARGB8888: // ARGB32 -+ case QVideoFrameFormat::Format_ARGB8888_Premultiplied: // ARGB32_Premultiplied -+ case QVideoFrameFormat::Format_RGBX8888: // RGB32 -+ fmt = ZXing::ImageFormat::BGRX; -+ break; -+ case QVideoFrameFormat::Format_BGRA8888: // BGRA32 -+ case QVideoFrameFormat::Format_BGRA8888_Premultiplied: // BGRA32_Premultiplied -+ case QVideoFrameFormat::Format_BGRX8888: // BGR32 -+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN -+ fmt = ZXing::ImageFormat::RGBX; -+#else -+ fmt = ImageFormat::XBGR; -+#endif -+ break; -+ case QVideoFrameFormat::Format_P010: -+ case QVideoFrameFormat::Format_P016: -+ fmt = ZXing::ImageFormat::Lum, pixStride = 1; break; -+ case QVideoFrameFormat::Format_AYUV: // AYUV444 -+ case QVideoFrameFormat::Format_AYUV_Premultiplied: // AYUV444_Premultiplied -+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN -+ fmt = ZXing::ImageFormat::Lum, pixStride = 4, pixOffset = 3; -+#else -+ fmt = ImageFormat::Lum, pixStride = 4, pixOffset = 2; -+#endif -+ break; -+ case QVideoFrameFormat::Format_YUV420P: // YUV420P -+ case QVideoFrameFormat::Format_NV12: // NV12 -+ case QVideoFrameFormat::Format_NV21: // NV21 -+ case QVideoFrameFormat::Format_IMC1: // IMC1 -+ case QVideoFrameFormat::Format_IMC2: // IMC2 -+ case QVideoFrameFormat::Format_IMC3: // IMC3 -+ case QVideoFrameFormat::Format_IMC4: // IMC4 -+ case QVideoFrameFormat::Format_YV12: // YV12 -+ case QVideoFrameFormat::Format_Y8: // Y8 -+ case QVideoFrameFormat::Format_YUV422P: // YUV422P -+ fmt = ZXing::ImageFormat::Lum; break; -+ case QVideoFrameFormat::Format_UYVY: // UYVY -+ fmt = ZXing::ImageFormat::Lum, pixStride = 2, pixOffset = 1; break; -+ case QVideoFrameFormat::Format_YUYV: // YUYV -+ fmt = ZXing::ImageFormat::Lum, pixStride = 2; break; -+ case QVideoFrameFormat::Format_Y16: // Y16 -+ fmt = ZXing::ImageFormat::Lum, pixStride = 2, pixOffset = 1; break; -+ -+ case QVideoFrameFormat::Format_ABGR8888: // ABGR32 -+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN -+ fmt = ZXing::ImageFormat::RGBX; -+#else -+ fmt = ZXing::ImageFormat::XBGR; -+#endif -+ break; -+ default: break; -+ } -+ -+ if (fmt != ZXing::ImageFormat::None) { -+ if (!frame.isValid() || !frame.map(QVideoFrame::ReadOnly)){ -+ logDebug(10005) << "invalid QVideoFrame: could not map memory"; -+ return {}; -+ } -+ QScopeGuard unmap([&] { frame.unmap(); }); -+ -+ constexpr int FirstPlane = 0; -+ return ZXing::ReadBarcodes( -+ {frame.bits(FirstPlane) + pixOffset, frame.width(), frame.height(), fmt, frame.bytesPerLine(FirstPlane), pixStride}, m_decodeHints); -+ } else { -+ return readBarcodes(frame.toImage()); -+ } -+} -+ -+ -+// -------------------------------------------------------------------- -+ -+CameraController::CameraController(QObject *parent) -+ : QObject(parent), -+ d(new CameraControllerPrivate(this)) -+{ -+ // The Android permissions requesting stuff returns results in a different thread, -+ // allow an easy way to move back to the main thread using a connection. -+ QObject::connect(this, SIGNAL(startCheckState()), this, SLOT(checkState()), Qt::QueuedConnection); -+ QObject::connect(this, SIGNAL(cameraPermissionReceived()), this, SLOT(handleCameraPermission()), Qt::QueuedConnection); -+} -+ -+void CameraController::startRequest(QRScanner *request) -+{ -+ assert(request); -+ d->scanRequest = request; -+ setHelpText(request->helpText()); -+ emit isScanTypeChanged(); -+ -+ if (!d->visible) { -+ d->visible = true; -+ emit visibleChanged(); -+ } -+ -+ if (d->state == NotAsked || d->state == Denied) { -+#if TARGET_OS_Android -+ auto me = QJniObject(QNativeInterface::QAndroidApplication::context()); -+ me.callObjectMethod("canUseCamera", "()V"); -+#else -+ setCameraPermission(true); -+#endif -+ return; -+ } -+ // give the overlay screen time to appear before -+ // activating the camera. -+ // This avoids waiting with the overlay screen until the camera -+ // is ready to stream which (depending on drivers) may take half a second. -+ QTimer::singleShot(1, this, SLOT(checkState())); -+} -+ -+void CameraController::abortRequest(QRScanner *request) -+{ -+ if (request && d->scanRequest == request) { -+ // The scanning thread will abort and nicely shutdown on change of this variable -+ d->lock.lock(); -+ d->cameraStarted = false; -+ d->lock.unlock(); -+ emit cameraActiveChanged(); -+ -+ if (d->scanningThread == nullptr) { -+ // then the above would have no effect; -+ qrScanFinished(); -+ } -+ } -+} -+ -+void CameraController::abort() -+{ -+ abortRequest(d->scanRequest); -+} -+ -+bool CameraController::isPayment() const -+{ -+ if (d->scanRequest == nullptr) -+ return false; -+ return d->scanRequest->isPayment(); -+} -+ -+bool CameraController::torchEnabled() const -+{ -+ return d->torchEnabled; -+} -+ -+void CameraController::setTorchEnabled(bool on) -+{ -+ if (d->torchEnabled == on) -+ return; -+ if (!d->cameraStarted) { -+ assert(d->torchEnabled == false); -+ return; -+ } -+ QCamera *cam = qobject_cast(d->camera); -+ if (cam == nullptr) -+ return; -+ if (cam->isTorchModeSupported(on ? QCamera::TorchOn : QCamera::TorchOff) == false) { -+ logWarning(10005) << "Trying to toggle torch, but the camera does not support that"; -+ return; -+ } -+ d->torchEnabled = on; -+ cam->setTorchMode(on ? QCamera::TorchOn : QCamera::TorchOff); -+ logFatal(10005) << "toggling the torch"; -+ -+ if (on) { -+ if (cam->isWhiteBalanceModeSupported(QCamera::WhiteBalanceFlash)) -+ cam->setWhiteBalanceMode(QCamera::WhiteBalanceFlash); -+ } else if (cam->whiteBalanceMode() == QCamera::WhiteBalanceFlash) { -+ // we should not just turn it off but also set it to the most appropriate normal mode. -+ constexpr QCamera::WhiteBalanceMode w_modess[] = { QCamera::WhiteBalanceShade, QCamera::WhiteBalanceAuto }; -+ for (auto m : w_modess) { -+ if (cam->isWhiteBalanceModeSupported(m)) { -+ cam->setWhiteBalanceMode(QCamera::WhiteBalanceAuto); -+ break; -+ } -+ } -+ } -+ emit torchEnabledChanged(); -+} -+ -+void CameraController::setCamera(QObject *object) -+{ -+ if (object == d->camera) -+ return; -+ d->camera = object; -+ emit cameraChanged(); -+ QTimer::singleShot(10, this, SLOT(initCamera())); -+} -+ -+QObject *CameraController::camera() const -+{ -+ return d->camera; -+} -+ -+void CameraController::setVideoSink(QObject *object) -+{ -+ if (d->videoSink == object) -+ return; -+ auto old = qobject_cast(d->videoSink); -+ if (old) -+ QObject::disconnect(old, nullptr, this, nullptr); -+ d->videoSink = object; -+ emit videoSinkChanged(); -+} -+ -+QObject *CameraController::videoSink() const -+{ -+ return d->videoSink; -+} -+ -+bool CameraController::loadCamera() const -+{ -+ return d->cameraLoaded; -+} -+ -+bool CameraController::cameraActive() const -+{ -+ return d->cameraStarted; -+} -+ -+bool CameraController::visible() const -+{ -+ return d->visible; -+} -+ -+void CameraController::qrScanFinished() -+{ -+ QString resultText; -+ QRScanner::ScanType scanType = QRScanner::InvalidType; -+ if (d->scanningThread) { -+ resultText = d->scanningThread->text; -+ scanType = d->scanningThread->scanType; -+ d->scanningThread->deleteLater(); -+ d->scanningThread = nullptr; -+ d->currentFrame = QVideoFrame(); -+ } -+ // stop copying video frames -+ assert(d->videoSink); -+ QObject::disconnect(d->videoSink, nullptr, this, nullptr); -+ -+ d->visible = false; -+ emit visibleChanged(); -+ setHelpText(QString()); -+ if (d->scanRequest) { -+ d->scanRequest->finishedScan(resultText, scanType); -+ d->scanRequest = nullptr; -+ } -+ -+ QCamera *cam = qobject_cast(d->camera); -+ if (cam) -+ cam->setTorchMode(QCamera::TorchOff); -+ if (d->torchEnabled) { -+ // don't use the simple setter as that one is doing much more. -+ d->torchEnabled = false; -+ emit torchEnabledChanged(); -+ } -+ // Have a bit of delay with actually turning off the camera. -+ QTimer::singleShot(100, this, [=]() { -+ d->cameraStarted = false; -+ emit cameraActiveChanged(); // makes the QML 'stop()' the camera. -+ }); -+} -+ -+void CameraController::checkState() -+{ -+ d->checkState(); -+} -+ -+void CameraController::initCamera() -+{ -+ d->initCamera(); -+} -+ -+void CameraController::handleCameraPermission() -+{ -+ if (d->state == Denied) -+ abort(); -+ else -+ QTimer::singleShot(100, this, SLOT(checkState())); -+} -+ -+QString CameraController::helpText() const -+{ -+ return d->helpText; -+} -+ -+QRScanner::ScanType CameraController::scanType() const -+{ -+ if (d->scanRequest == nullptr) -+ return QRScanner::InvalidType; -+ return d->scanRequest->scanType(); -+} -+ -+void CameraController::setCameraPermission(bool allowed) -+{ -+ // lets assume the native OS called this in a thread that is not us. -+ d->state = allowed ? Authorized : Denied; -+ emit cameraPermissionReceived(); -+} -+ -+void CameraController::setHelpText(const QString &text) -+{ -+ if (d->helpText == text) -+ return; -+ d->helpText = text; -+ emit helpTextChanged(); -+} -+ -+#include "moc_CameraController.cpp" -diff --git a/src/QRCreator.cpp b/src/QRCreator.cpp -index 361ee18..67eee9c 100644 ---- a/src/QRCreator.cpp -+++ b/src/QRCreator.cpp -@@ -19,9 +19,9 @@ - - #include - // cmake ensures the presence of the ZXing lib. --#include --#include --#include -+#include -+#include -+#include - - #include - #include -@@ -43,29 +43,8 @@ QImage QRCreator::requestImage(const QString &id, QSize *size, const QSize &requ - } else if (m_type == RawString) { - data = id.toUtf8(); - } -- -- auto writer = ZXing::MultiFormatWriter(ZXing::BarcodeFormat::QRCode).setMargin(16); -- /* -- * In newer versions of zxing there is a direct std::string version of the encode() -- * call which is nice to avoid the extra coversion. -- * For now we leave this extra code here as long as we are still able to compile and -- * run on Ubuntu 2022.04 (jammy) which doesn't have this new call. -- * -- * Ironically, the codecvt below code is deprecated in C++17, so you get warnings now. -- * Can't win this one, I guess... -- * But the promise is that it will be part of C++ till the 2026 release, -- * and I prefer it actually compiling on older zxing. So maybe lets just -- * plan to remove the wstring conversion in a year or so (TZ: Feb 2024) -- */ -- std::wstring wdata = std::wstring_convert>().from_bytes(data); -- ZXing::BitMatrix matrix = writer.encode(wdata, 250, 250); -- -- QImage result = QImage(matrix.height(), matrix.width(), QImage::Format_RGB32); -- constexpr uint black = 0xFF000000; -- constexpr uint white = 0xFFFFFFFF; -- for (int y = 0; y < matrix.height(); ++y) -- for (int x = 0; x < matrix.width(); ++x) -- result.setPixel(x, y, matrix.get(x, y) ? black : white); -- -- return result; -+ auto barcode = ZXing::CreateBarcodeFromText(data, ZXing::BarcodeFormat::QRCode); -+ auto image = ZXing::WriteBarcodeToImage(barcode); -+ QImage result(image.data(), image.width(), image.height(), image.width(), QImage::Format_Grayscale8); -+ return result.copy(); - } -diff --git a/src/QRCreator_zxing2.cpp b/src/QRCreator_zxing2.cpp -new file mode 100644 -index 0000000..361ee18 ---- /dev/null -+++ b/src/QRCreator_zxing2.cpp -@@ -0,0 +1,71 @@ -+/* -+ * This file is part of the Flowee project -+ * Copyright (C) 2018-2024 Tom Zander -+ * -+ * This program is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program. If not, see . -+ */ -+#include "QRCreator.h" -+ -+#include -+// cmake ensures the presence of the ZXing lib. -+#include -+#include -+#include -+ -+#include -+#include -+ -+QRCreator::QRCreator(QRType type) -+ : QQuickImageProvider(QQmlImageProviderBase::Image), -+ m_type(type) -+{ -+} -+ -+QImage QRCreator::requestImage(const QString &id, QSize *size, const QSize &requestedSize) -+{ -+ Q_UNUSED(size); -+ Q_UNUSED(requestedSize); -+ std::string data; // assumed utf8 -+ if (m_type == URLEncoded) { -+ QUrl url(id); // go via URL to encode spaces and special chars -+ data = url.toEncoded(QUrl::EncodeSpaces); -+ } else if (m_type == RawString) { -+ data = id.toUtf8(); -+ } -+ -+ auto writer = ZXing::MultiFormatWriter(ZXing::BarcodeFormat::QRCode).setMargin(16); -+ /* -+ * In newer versions of zxing there is a direct std::string version of the encode() -+ * call which is nice to avoid the extra coversion. -+ * For now we leave this extra code here as long as we are still able to compile and -+ * run on Ubuntu 2022.04 (jammy) which doesn't have this new call. -+ * -+ * Ironically, the codecvt below code is deprecated in C++17, so you get warnings now. -+ * Can't win this one, I guess... -+ * But the promise is that it will be part of C++ till the 2026 release, -+ * and I prefer it actually compiling on older zxing. So maybe lets just -+ * plan to remove the wstring conversion in a year or so (TZ: Feb 2024) -+ */ -+ std::wstring wdata = std::wstring_convert>().from_bytes(data); -+ ZXing::BitMatrix matrix = writer.encode(wdata, 250, 250); -+ -+ QImage result = QImage(matrix.height(), matrix.width(), QImage::Format_RGB32); -+ constexpr uint black = 0xFF000000; -+ constexpr uint white = 0xFFFFFFFF; -+ for (int y = 0; y < matrix.height(); ++y) -+ for (int x = 0; x < matrix.width(); ++x) -+ result.setPixel(x, y, matrix.get(x, y) ? black : white); -+ -+ return result; -+} --- -2.53.0 - diff --git a/PKGBUILD b/PKGBUILD index 8d89b51..da08f72 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -1,7 +1,7 @@ # Maintainer: Tom Zander pkgname=flowee-pay -pkgver=2026.02.1 +pkgver=2026.03.0 options=(!lto) pkgrel=1 pkgdesc="Flowee Payment solution" @@ -13,12 +13,8 @@ makedepends=('boost' 'cmake' 'flowee>=2026.02.0' 'qt6-tools') provides=('flowee-pay') install=flowee-pay.install source=("https://codeberg.org/Flowee/pay/archive/$pkgver.tar.gz" - "0001-Fix-off-by-one-in-unit-test.patch" - "0001-Port-to-new-ZXing-version-3.patch" "https://flowee.org/products/pay/blockheaders-850000") -sha256sums=('a3a8443e6236498fa384478366c8b35dea5c7cec3b8b9b06d5b0ba9a835d2b95' - 'f7e4bf13406b1836fb0e80b97f01d8f5098b3c4c9de230ac5463c009a5019316' - '2a31e641e19432c77b467876fce30517378fd1dd646ad05e1d53d1476cf99ebf' +sha256sums=('167b020d17b427f0e0ee0a1af754f5dbc89084a546610a0f68ce35ff18d36057' '4a98c3b655cfd7520b4d4f682d95e3a82e0f03fda4fa687d28f2127205d66047') build() { @@ -31,8 +27,6 @@ build() { prepare() { cd "$srcdir/pay" - patch -Np1 -i ../0001-Fix-off-by-one-in-unit-test.patch - patch -Np1 -i ../0001-Port-to-new-ZXing-version-3.patch } check() {