diff --git a/nixos/modules/services/desktop-managers/lomiri.nix b/nixos/modules/services/desktop-managers/lomiri.nix index 50080daaf7de1..bd43b4c1cfdae 100644 --- a/nixos/modules/services/desktop-managers/lomiri.nix +++ b/nixos/modules/services/desktop-managers/lomiri.nix @@ -22,6 +22,7 @@ in { libusermetrics lomiri lomiri-calculator-app + lomiri-camera-app lomiri-clock-app lomiri-download-manager lomiri-filemanager-app diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index f6392be29437e..f52b731ec2289 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -538,6 +538,7 @@ in { #logstash = handleTest ./logstash.nix {}; lomiri = handleTest ./lomiri.nix {}; lomiri-calculator-app = runTest ./lomiri-calculator-app.nix; + lomiri-camera-app = runTest ./lomiri-camera-app.nix; lomiri-clock-app = runTest ./lomiri-clock-app.nix; lomiri-filemanager-app = runTest ./lomiri-filemanager-app.nix; lomiri-system-settings = handleTest ./lomiri-system-settings.nix {}; diff --git a/nixos/tests/lomiri-camera-app.nix b/nixos/tests/lomiri-camera-app.nix new file mode 100644 index 0000000000000..ccd53a37135b2 --- /dev/null +++ b/nixos/tests/lomiri-camera-app.nix @@ -0,0 +1,135 @@ +{ lib, ... }: +{ + name = "lomiri-camera-app-standalone"; + meta.maintainers = lib.teams.lomiri.members; + + nodes.machine = + { config, pkgs, ... }: + { + imports = [ ./common/x11.nix ]; + + services.xserver.enable = true; + + environment = { + systemPackages = + with pkgs; + [ + feh # view photo result + ffmpeg # fake webcam stream + gnome-text-editor # somewhere to paste QR result + (imagemagick.override { ghostscriptSupport = true; }) # add label for OCR + qrtool # generate QR code + xdotool # clicking on QR button + ] + ++ (with pkgs.lomiri; [ + suru-icon-theme + lomiri-camera-app + ]); + variables = { + UITK_ICON_THEME = "suru"; + }; + }; + + i18n.supportedLocales = [ "all" ]; + + fonts = { + packages = with pkgs; [ + # Intended font & helps with OCR + ubuntu-classic + ]; + }; + + # Fake camera + boot.extraModulePackages = with config.boot.kernelPackages; [ v4l2loopback ]; + }; + + enableOCR = true; + + testScript = + let + qrLabel = "Image"; + qrContent = "Test"; + in + '' + machine.wait_for_x() + + with subtest("lomiri camera launches"): + machine.succeed("lomiri-camera-app >&2 &") + machine.wait_for_text("Cannot access") + machine.screenshot("lomiri-camera_open") + + machine.succeed("pkill -f lomiri-camera-app") + + # Setup fake v4l2 camera + machine.succeed("modprobe v4l2loopback video_nr=10 card_label=Video-Loopback exclusive_caps=1") + machine.succeed("qrtool encode '${qrContent}' -s 20 -m 10 > qr.png") + # Horizontal flip, add text, flip back. Camera displays image mirrored, so need reversed text for OCR + machine.succeed("magick qr.png -flop -pointsize 70 -fill black -annotate +100+100 '${qrLabel}' -flop output.png") + machine.succeed("ffmpeg -re -loop 1 -i output.png -vf format=yuv420p -f v4l2 /dev/video10 -loglevel fatal >&2 &") + + with subtest("lomiri camera uses camera"): + machine.succeed("lomiri-camera-app >&2 &") + machine.wait_for_text("${qrLabel}") + machine.screenshot("lomiri-camera_feed") + + machine.succeed("xdotool mousemove 320 610 click 1") # take photo + machine.wait_until_succeeds("find /root/Pictures/camera.ubports -name '*.jpg'") + + # Check that the image is correct + machine.send_key("ctrl-alt-right") + machine.succeed("magick /root/Pictures/camera.ubports/IMG_00000001.jpg -flop photo_flip.png") + machine.succeed("feh photo_flip.png >&2 &") + machine.wait_for_text("${qrLabel}") + machine.screenshot("lomiri-camera_photo") + + machine.succeed("pkill -f feh") + machine.send_key("ctrl-alt-left") + machine.succeed("pkill -f lomiri-camera-app") + + with subtest("lomiri barcode scanner uses camera"): + machine.succeed("lomiri-camera-app --mode=barcode-reader >&2 &") + machine.wait_for_text("${qrLabel}") + machine.succeed("xdotool mousemove 320 610 click 1") # open up QR decode result + + # OCR is struggling to recognise the text. Click the clipboard button and paste the result somewhere else + machine.sleep(5) + machine.screenshot("lomiri-barcode_decode") + machine.succeed("xdotool mousemove 350 530 click 1") + machine.sleep(5) + + # Need to make a new window without closing camera app, otherwise clipboard content gets lost? + machine.send_key("ctrl-alt-right") + machine.succeed("gnome-text-editor >&2 &") + machine.wait_for_text("New") + + # Font size up to help with OCR + machine.send_key("ctrl-kp_add") + machine.send_key("ctrl-kp_add") + machine.send_key("ctrl-kp_add") + machine.send_key("ctrl-kp_add") + machine.send_key("ctrl-kp_add") + machine.send_key("ctrl-kp_add") + machine.send_key("ctrl-kp_add") + machine.send_key("ctrl-kp_add") + machine.send_key("ctrl-kp_add") + machine.send_key("ctrl-kp_add") + machine.send_key("ctrl-kp_add") + machine.send_key("ctrl-kp_add") + machine.send_key("ctrl-kp_add") + machine.send_key("ctrl-kp_add") + machine.send_key("ctrl-kp_add") + machine.send_key("ctrl-kp_add") + + machine.send_key("ctrl-v") + machine.wait_for_text("${qrContent}") + + machine.succeed("pkill -f gnome-text-editor") + machine.send_key("ctrl-alt-left") + machine.succeed("pkill -f lomiri-camera-app") + + with subtest("lomiri camera localisation works"): + machine.succeed("env LANG=de_DE.UTF-8 lomiri-camera-app >&2 &") + machine.wait_for_text("Kamera") + machine.screenshot("lomiri-camera_localised") + ''; +} diff --git a/nixos/tests/lomiri.nix b/nixos/tests/lomiri.nix index 912f4564ef7b2..5236a5dafbe51 100644 --- a/nixos/tests/lomiri.nix +++ b/nixos/tests/lomiri.nix @@ -174,9 +174,6 @@ in { # Using the keybind has a chance of instantly closing the menu again? Just click the button mouse_click(20, 30) - # Look for Search box & GUI-less content-hub examples, highest chances of avoiding false positives - machine.wait_for_text(r"(Search|Export|Import|Share)") - start_all() machine.wait_for_unit("multi-user.target") diff --git a/pkgs/desktops/lomiri/applications/lomiri-camera-app/default.nix b/pkgs/desktops/lomiri/applications/lomiri-camera-app/default.nix new file mode 100644 index 0000000000000..34abc5d808eec --- /dev/null +++ b/pkgs/desktops/lomiri/applications/lomiri-camera-app/default.nix @@ -0,0 +1,234 @@ +{ + stdenv, + lib, + fetchFromGitLab, + fetchpatch, + gitUpdater, + nixosTests, + cmake, + content-hub, + exiv2, + gettext, + gst_all_1, + libusermetrics, + lomiri-action-api, + lomiri-ui-toolkit, + lomiri-thumbnailer, + pkg-config, + qtbase, + qtdeclarative, + qtmultimedia, + qtpositioning, + qtquickcontrols2, + qtsensors, + qzxing, + wrapGAppsHook3, + wrapQtAppsHook, + xvfb-run, +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "lomiri-camera-app"; + version = "4.0.6"; + + src = fetchFromGitLab { + owner = "ubports"; + repo = "development/apps/lomiri-camera-app"; + rev = "refs/tags/v${finalAttrs.version}"; + hash = "sha256-93skB614T9RcMhYfeCDjV+JLYoJocylk32uzdcQ4I8Q="; + }; + + patches = [ + # Remove when version > 4.0.6 + (fetchpatch { + name = "0001-lomiri-camera-app-Stop using qt5_use_modules.patch"; + url = "https://gitlab.com/ubports/development/apps/lomiri-camera-app/-/commit/567f983e59cc412c9e1951f78f0809c6faebd3a6.patch"; + hash = "sha256-peP3c7XqpjGcdVG5zLKTcZPUPVz9Tu8tVBPaLVc5vWE="; + }) + + # Fix GNUInstallDirs usage + # Remove when https://gitlab.com/ubports/development/apps/lomiri-camera-app/-/merge_requests/205 merged & in release + (fetchpatch { + name = "0002-lomiri-camera-app-GNUInstallDirs.patch"; + url = "https://gitlab.com/ubports/development/apps/lomiri-camera-app/-/commit/76fbccd627bdbf30e4f3a736d1821e25f1cf45a7.patch"; + hash = "sha256-qz/2Df84e5+T8zQANb2Bl4dwoI10Z3blAlNI9ODavSw="; + }) + + # Call i18n.bindtextdomain with correct locale path + # Remove when https://gitlab.com/ubports/development/apps/lomiri-camera-app/-/merge_requests/206 merged & in release + (fetchpatch { + name = "0003-lomiri-camera-app-bindtextdomain.patch"; + url = "https://gitlab.com/ubports/development/apps/lomiri-camera-app/-/commit/9250b79f85218b561dce07030a2920d5443ac4ba.patch"; + hash = "sha256-vCE64sxpin68Ks/hu1LWuOT5eZWozPPKqYR2GcsriPg="; + }) + + # Fix doubled DESTINATION + # Remove when https://gitlab.com/ubports/development/apps/lomiri-camera-app/-/merge_requests/207 merged & in release + (fetchpatch { + name = "0004-lomiri-camera-app-bindtextdomain.patch"; + url = "https://gitlab.com/ubports/development/apps/lomiri-camera-app/-/commit/4af85daccac0904cbb0cfb08e592d9ab1d745d6d.patch"; + hash = "sha256-PCGwQ6rAyrBeAefTe1ciod+R4tbJk+D76g9fH4PoTlg="; + }) + + # Use pkg-config to find QZXing + # Remove when https://gitlab.com/ubports/development/apps/lomiri-camera-app/-/merge_requests/208 merged & in release + (fetchpatch { + name = "0005-lomiri-camera-app-QZXing-pkg-config.patch"; + url = "https://gitlab.com/ubports/development/apps/lomiri-camera-app/-/commit/e79a10ca236ef5ed0af328786dbaef281e2c120b.patch"; + hash = "sha256-dC6a6IjpPez+asKdTB885rAEN+mqtP7uYpicz/4hRSM="; + }) + + # Make testing optional + # Remove when https://gitlab.com/ubports/development/apps/lomiri-camera-app/-/merge_requests/209 merged & in release + (fetchpatch { + name = "0006-lomiri-camera-app-BUILD_TESTING.patch"; + url = "https://gitlab.com/ubports/development/apps/lomiri-camera-app/-/commit/e3ec58327ffc25c565cf8c28d09adc09c4067b23.patch"; + hash = "sha256-U5r3+218Cx4T0iF7nm2Mfhlr+4dn7ptPfgsxZrIUJHQ="; + }) + + # Fix translation of window title + # Remove when https://gitlab.com/ubports/development/apps/lomiri-camera-app/-/merge_requests/211 merged & in release + (fetchpatch { + name = "0007-lomiri-camera-app-title-translation.patch"; + url = "https://gitlab.com/ubports/development/apps/lomiri-camera-app/-/commit/43f0018158f65fe81f50e7860d8af2e469785434.patch"; + hash = "sha256-7qFqps488B2d1wp79kFyUDR1FzE1Q9QMIOFFa/astHU="; + }) + + # Make barcode reader's icons SVGs and fix icon installations + # Remove when https://gitlab.com/ubports/development/apps/lomiri-camera-app/-/merge_requests/210 merged & in release + (fetchpatch { + name = "0011-lomiri-camera-app-camera-icon-installation-fix.patch"; + url = "https://gitlab.com/ubports/development/apps/lomiri-camera-app/-/commit/48ebaffc1f589569387127e953b0995451580cc1.patch"; + hash = "sha256-nq5iCTHCUzEj/38hCIaqhzUX7ABVkSAeB5hEzZfIX7A="; + }) + (fetchpatch { + name = "0012-lomiri-camera-app-splash-icon-location-fix.patch"; + url = "https://gitlab.com/ubports/development/apps/lomiri-camera-app/-/commit/6c96eade82d6d812aa605bc45a5ff06ed3a2aeff.patch"; + hash = "sha256-8QusJPyNO8ADx3Ce1y/thQAaXQa8XnnMvPrxyzx8oRk="; + }) + (fetchpatch { + name = "0013-lomiri-camera-app-Vectorise-barcode-icons.patch"; + url = "https://gitlab.com/ubports/development/apps/lomiri-camera-app/-/commit/d5232590a02b535d24d9765d24ce5a066cc57724.patch"; + hash = "sha256-sfSdzFFLof1dN/7KnerZOBoarubGcTxp7h9Ab6rGoV0="; + }) + (fetchpatch { + name = "0014-lomiri-camera-app-barcode-icon-installation-fix.patch"; + url = "https://gitlab.com/ubports/development/apps/lomiri-camera-app/-/commit/a8718d6621a34aaf19aaaaea5dd31f401a652953.patch"; + hash = "sha256-eiBliqk71aDmIMY6cn1J5cxmzlHMTtiYKeQ0cJuCNYA="; + }) + ]; + + # We don't want absolute paths in dekstop files + postPatch = '' + substituteInPlace CMakeLists.txt \ + --replace-fail 'CAMERA_SPLASH ''${CAMERA_APP_DIR}/assets/lomiri-camera-app-splash.svg' 'CAMERA_SPLASH lomiri-app-launch/splash/lomiri-camera-app.svg' \ + --replace-fail 'READER_SPLASH "''${CAMERA_APP_DIR}/assets/lomiri-barcode-reader-app-splash.svg"' 'READER_SPLASH lomiri-app-launch/splash/lomiri-barcode-reader-app.svg' + ''; + + strictDeps = true; + + nativeBuildInputs = [ + cmake + gettext + pkg-config + wrapGAppsHook3 + wrapQtAppsHook + ]; + + buildInputs = + [ + exiv2 + qtbase + qtdeclarative + qtmultimedia + qtquickcontrols2 + qzxing + + # QML + content-hub + libusermetrics + lomiri-action-api + lomiri-ui-toolkit + lomiri-thumbnailer + qtpositioning + qtsensors + ] + ++ (with gst_all_1; [ + # cannot create camera service, the 'camerabin' plugin is missing for GStreamer + gstreamer + gst-plugins-base + gst-plugins-good + gst-plugins-bad + gst-plugins-ugly + ]); + + nativeCheckInputs = [ xvfb-run ]; + + cmakeFlags = [ + (lib.cmakeBool "INSTALL_TESTS" false) + (lib.cmakeBool "CLICK_MODE" false) + (lib.cmakeFeature "CMAKE_CTEST_ARGUMENTS" ( + lib.concatStringsSep ";" [ + # Exclude tests + "-E" + (lib.strings.escapeShellArg "(${ + lib.concatStringsSep "|" [ + # Don't care about linter failures + "^flake8" + ] + })") + ] + )) + ]; + + doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform; + + preCheck = + let + listToQtVar = suffix: lib.makeSearchPathOutput "bin" suffix; + in + '' + export QT_PLUGIN_PATH=${listToQtVar qtbase.qtPluginPrefix [ qtbase ]} + export QML2_IMPORT_PATH=${ + listToQtVar qtbase.qtQmlPrefix [ + lomiri-ui-toolkit + content-hub + lomiri-thumbnailer + ] + } + ''; + + postInstall = '' + mkdir -p $out/share/lomiri-app-launch/splash + ln -s $out/share/lomiri-camera-app/assets/lomiri-camera-app-splash.svg $out/share/lomiri-app-launch/splash/lomiri-camera-app.svg + ln -s $out/share/lomiri-camera-app/assets/lomiri-barcode-reader-app-splash.svg $out/share/lomiri-app-launch/splash/lomiri-barcode-reader-app.svg + + install -Dm644 ../camera-contenthub.json $out/share/content-hub/peers/lomiri-camera-app + ''; + + dontWrapGApps = true; + + preFixup = '' + qtWrapperArgs+=( + "''${gappsWrapperArgs[@]}" + ) + ''; + + passthru = { + tests.vm = nixosTests.lomiri-camera-app; + updateScript = gitUpdater { rev-prefix = "v"; }; + }; + + meta = { + description = "Camera application for Ubuntu Touch devices"; + homepage = "https://gitlab.com/ubports/development/apps/lomiri-camera-app"; + changelog = "https://gitlab.com/ubports/development/apps/lomiri-camera-app/-/blob/v${finalAttrs.version}/ChangeLog"; + license = with lib.licenses; [ + gpl3Only # code + cc-by-sa-30 # extra graphics + ]; + mainProgram = "lomiri-camera-app"; + maintainers = lib.teams.lomiri.members; + platforms = lib.platforms.linux; + }; +}) diff --git a/pkgs/desktops/lomiri/default.nix b/pkgs/desktops/lomiri/default.nix index 98cfe068086bd..59cd0d9d2d9c6 100644 --- a/pkgs/desktops/lomiri/default.nix +++ b/pkgs/desktops/lomiri/default.nix @@ -10,6 +10,7 @@ let #### Core Apps lomiri = callPackage ./applications/lomiri { }; lomiri-calculator-app = callPackage ./applications/lomiri-calculator-app { }; + lomiri-camera-app = callPackage ./applications/lomiri-camera-app { }; lomiri-clock-app = callPackage ./applications/lomiri-clock-app { }; lomiri-filemanager-app = callPackage ./applications/lomiri-filemanager-app { }; lomiri-system-settings-unwrapped = callPackage ./applications/lomiri-system-settings { };