about summary refs log tree commit diff
path: root/nixpkgs/pkgs/desktops/lomiri
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/pkgs/desktops/lomiri')
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/applications/lomiri-system-settings/2000-Support-wrapping-for-Nixpkgs.patch160
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/applications/lomiri-system-settings/default.nix236
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/applications/lomiri-system-settings/plugins/lomiri-system-settings-security-privacy.nix89
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/applications/lomiri-system-settings/wrapper.nix70
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/applications/lomiri-terminal-app/default.nix104
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/applications/lomiri/9901-lomiri-Disable-Wizard.patch30
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/applications/lomiri/default.nix289
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/applications/morph-browser/default.nix148
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/data/lomiri-schemas/default.nix61
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/data/lomiri-session/default.nix198
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/data/lomiri-sounds/default.nix47
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/data/lomiri-wallpapers/default.nix48
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/data/suru-icon-theme/default.nix58
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/default.nix59
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/development/cmake-extras/default.nix49
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/development/deviceinfo/default.nix75
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/development/geonames/default.nix115
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/development/gmenuharness/default.nix96
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/development/libusermetrics/2001-Remove-custom-check-target.patch37
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/development/libusermetrics/2002-Launch-module-created-systemd-service.patch21
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/development/libusermetrics/default.nix134
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/development/lomiri-api/default.nix115
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/development/lomiri-app-launch/default.nix150
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/development/qtmir/default.nix160
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/development/trust-store/default.nix129
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/development/u1db-qt/default.nix117
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/qml/lomiri-action-api/default.nix88
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/qml/lomiri-notifications/default.nix92
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/qml/lomiri-push-qml/default.nix74
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/qml/lomiri-settings-components/default.nix66
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/qml/lomiri-ui-extras/default.nix103
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/qml/lomiri-ui-toolkit/2001-Mark-problematic-tests.patch155
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/qml/lomiri-ui-toolkit/2002-Nixpkgs-versioned-QML-path.patch.in29
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/qml/lomiri-ui-toolkit/default.nix231
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/qml/qqc2-suru-style/default.nix45
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/services/biometryd/default.nix120
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/services/content-hub/default.nix195
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/services/hfd-service/default.nix77
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/services/history-service/default.nix199
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/services/history-service/update_schema.sh.in34
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/services/lomiri-download-manager/default.nix144
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/services/lomiri-indicator-network/default.nix133
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/services/lomiri-thumbnailer/default.nix218
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/services/lomiri-url-dispatcher/default.nix169
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/services/mediascanner2/default.nix122
-rw-r--r--nixpkgs/pkgs/desktops/lomiri/services/telephony-service/default.nix201
46 files changed, 5290 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/desktops/lomiri/applications/lomiri-system-settings/2000-Support-wrapping-for-Nixpkgs.patch b/nixpkgs/pkgs/desktops/lomiri/applications/lomiri-system-settings/2000-Support-wrapping-for-Nixpkgs.patch
new file mode 100644
index 000000000000..8e39ea5fdfc0
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/applications/lomiri-system-settings/2000-Support-wrapping-for-Nixpkgs.patch
@@ -0,0 +1,160 @@
+From 8e21cf46551091c884014985d3e0dd9704d6dc04 Mon Sep 17 00:00:00 2001
+From: OPNA2608 <opna2608@protonmail.com>
+Date: Wed, 14 Feb 2024 16:00:24 +0100
+Subject: [PATCH] Support wrapping for Nixpkgs
+
+---
+ src/CMakeLists.txt   | 24 +++++++++++++++++++-----
+ src/main.cpp         |  8 +++++---
+ src/plugin.cpp       | 19 +++++++++++++++++--
+ tests/CMakeLists.txt | 18 ++++++++++++++----
+ 4 files changed, 55 insertions(+), 14 deletions(-)
+
+diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
+index cd3131d0..fcd78bdf 100644
+--- a/src/CMakeLists.txt
++++ b/src/CMakeLists.txt
+@@ -1,13 +1,27 @@
+ include_directories(${GLIB_INCLUDE_DIRS})
+ 
+-add_definitions(-DI18N_DIRECTORY="${CMAKE_INSTALL_FULL_LOCALEDIR}")
+ add_definitions(-DI18N_DOMAIN="lomiri-system-settings")
+-add_definitions(-DPLUGIN_PRIVATE_MODULE_DIR="${PLUGIN_PRIVATE_MODULE_DIR}")
++
++add_definitions(-DNIX_FALLBACK_PREFIX="${CMAKE_INSTALL_PREFIX}")
++
++set(I18N_DIRECTORY "${CMAKE_INSTALL_FULL_LOCALEDIR}")
++
++list(APPEND NIX_LOCATION_VARIABLES
++    I18N_DIRECTORY
++    PLUGIN_PRIVATE_MODULE_DIR
++    PLUGIN_MANIFEST_DIR
++    PLUGIN_QML_DIR
++    PLUGIN_MODULE_DIR
++)
++
++foreach(locvar IN LISTS NIX_LOCATION_VARIABLES)
++    string(REPLACE "${CMAKE_INSTALL_PREFIX}" "" NIX_${locvar}_RELATIVE "${${locvar}}")
++    add_definitions(-D${locvar}=do_not_use_me)
++    add_definitions(-DNIX_${locvar}_RELATIVE="${NIX_${locvar}_RELATIVE}")
++endforeach()
++
+ add_definitions(-DMANIFEST_DIR="${MANIFEST_DIR}")
+-add_definitions(-DPLUGIN_MANIFEST_DIR="${PLUGIN_MANIFEST_DIR}")
+ add_definitions(-DQML_DIR="${QML_DIR}")
+-add_definitions(-DPLUGIN_QML_DIR="${PLUGIN_QML_DIR}")
+-add_definitions(-DPLUGIN_MODULE_DIR="${PLUGIN_MODULE_DIR}")
+ 
+ add_subdirectory(SystemSettings)
+ 
+diff --git a/src/main.cpp b/src/main.cpp
+index 64441da3..cfcabe42 100644
+--- a/src/main.cpp
++++ b/src/main.cpp
+@@ -42,6 +42,8 @@ int main(int argc, char **argv)
+     QByteArray mountPoint = qEnvironmentVariableIsSet("SNAP") ? qgetenv("SNAP") : "";
+     bool isSnap = !mountPoint.isEmpty();
+ 
++    QByteArray dataPrefix = qEnvironmentVariableIsSet("NIX_LSS_PREFIX") ? qgetenv("NIX_LSS_PREFIX") : NIX_FALLBACK_PREFIX;
++
+     // Ensure printing environment is correct.
+     qputenv("QT_PRINTER_MODULE", "cupsprintersupport");
+ 
+@@ -78,12 +80,12 @@ int main(int argc, char **argv)
+     qmlRegisterType<LomiriSystemSettings::PluginManager>("SystemSettings", 1, 0, "PluginManager");
+     view.engine()->rootContext()->setContextProperty("Utilities", &utils);
+     view.setResizeMode(QQuickView::SizeRootObjectToView);
+-    view.engine()->addImportPath(mountPoint + PLUGIN_PRIVATE_MODULE_DIR);
+-    view.engine()->addImportPath(mountPoint + PLUGIN_QML_DIR);
++    view.engine()->addImportPath(mountPoint + dataPrefix + "/" + NIX_PLUGIN_PRIVATE_MODULE_DIR_RELATIVE);
++    view.engine()->addImportPath(mountPoint + dataPrefix + "/" + NIX_PLUGIN_QML_DIR_RELATIVE);
+     view.rootContext()->setContextProperty("defaultPlugin", defaultPlugin);
+     view.rootContext()->setContextProperty("mountPoint", mountPoint);
+     view.rootContext()->setContextProperty("isSnap", isSnap);
+-    view.rootContext()->setContextProperty("i18nDirectory", mountPoint + I18N_DIRECTORY);
++    view.rootContext()->setContextProperty("i18nDirectory", mountPoint + dataPrefix + "/" + NIX_I18N_DIRECTORY_RELATIVE);
+     view.rootContext()->setContextProperty("pluginOptions", pluginOptions);
+     view.rootContext()->setContextProperty("view", &view);
+     view.setSource(QUrl("qrc:/qml/MainWindow.qml"));
+diff --git a/src/plugin.cpp b/src/plugin.cpp
+index 133821af..6a1a152c 100644
+--- a/src/plugin.cpp
++++ b/src/plugin.cpp
+@@ -36,9 +36,16 @@
+ #include <LomiriSystemSettings/ItemBase>
+ #include <LomiriSystemSettings/PluginInterface>
+ 
++#include <libintl.h>
++
+ using namespace LomiriSystemSettings;
+ 
+-static const QLatin1String pluginModuleDir{PLUGIN_MODULE_DIR};
++const QLatin1String getWrapperPrefix()
++{
++    const QLatin1String pluginWrapperPrefix {qEnvironmentVariableIsSet("NIX_LSS_PREFIX") ? qgetenv("NIX_LSS_PREFIX") : NIX_FALLBACK_PREFIX};
++    return pluginWrapperPrefix;
++}
++static const QLatin1String pluginModuleDirRelative{NIX_PLUGIN_MODULE_DIR_RELATIVE};
+ static const QLatin1String pluginQmlDir{QML_DIR};
+ 
+ namespace LomiriSystemSettings {
+@@ -89,6 +96,11 @@ PluginPrivate::PluginPrivate(Plugin *q, const QFileInfo &manifest):
+ 
+     m_data = json.toVariant().toMap();
+     m_dataPath = manifest.absolutePath();
++
++    QString textDomain = m_data.value(keyTranslations).toString();
++    QString textDomainDir = QString("%1/%2")
++        .arg(getWrapperPrefix()).arg(NIX_I18N_DIRECTORY_RELATIVE);
++    bindtextdomain(qPrintable(textDomain), qPrintable(textDomainDir));
+ }
+ 
+ bool PluginPrivate::ensureLoaded() const
+@@ -110,8 +122,11 @@ bool PluginPrivate::ensureLoaded() const
+         ctx->contextProperty("mountPoint").value<QByteArray>() :
+         "";
+ 
++    QString wrapperModuleDir = QString("%1/%2")
++        .arg(getWrapperPrefix()).arg(pluginModuleDirRelative);
++
+     QString name = QString("%1%2/lib%3.so")
+-        .arg(mountPoint).arg(pluginModuleDir).arg(plugin);
++        .arg(mountPoint).arg(wrapperModuleDir).arg(plugin);
+ 
+     m_loader.setFileName(name);
+     if (Q_UNLIKELY(!m_loader.load())) {
+diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
+index c10b2e2d..a998b641 100644
+--- a/tests/CMakeLists.txt
++++ b/tests/CMakeLists.txt
+@@ -9,13 +9,23 @@ include_directories(
+ set(XVFB_CMD xvfb-run -a -s "-screen 0 640x480x24")
+ 
+ add_definitions(-DI18N_DOMAIN="lomiri-system-settings")
+-add_definitions(-DPLUGIN_PRIVATE_MODULE_DIR="${PLUGIN_PRIVATE_MODULE_DIR}")
+-add_definitions(-DPLUGIN_MODULE_DIR="${CMAKE_CURRENT_BINARY_DIR}")
++
++add_definitions(-DNIX_FALLBACK_PREFIX="${CMAKE_CURRENT_BINARY_DIR}")
++
++add_definitions(-DI18N_DIRECTORY=do_not_use_me)
++add_definitions(-DNIX_I18N_DIRECTORY_RELATIVE="")
++add_definitions(-DPLUGIN_PRIVATE_MODULE_DIR=do_not_use_me)
++add_definitions(-DNIX_PLUGIN_PRIVATE_MODULE_DIR_RELATIVE="")
++add_definitions(-DPLUGIN_MODULE_DIR=do_not_use_me)
++add_definitions(-DNIX_PLUGIN_MODULE_DIR_RELATIVE="")
++add_definitions(-DPLUGIN_MANIFEST_DIR=do_not_use_me)
++add_definitions(-DNIX_PLUGIN_MANIFEST_DIR_RELATIVE="../../tests/data")
++add_definitions(-DPLUGIN_QML_DIR=do_not_use_me)
++add_definitions(-DNIX_PLUGIN_QML_DIR_RELATIVE="")
++
+ add_definitions(-DMANIFEST_DIR="data")
+-add_definitions(-DPLUGIN_MANIFEST_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data")
+ add_definitions(-DQML_TEST_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
+ add_definitions(-DQML_DIR="${CMAKE_CURRENT_BINARY_DIR}")
+-add_definitions(-DPLUGIN_QML_DIR="${CMAKE_CURRENT_BINARY_DIR}")
+ add_definitions(-DSYSTEM_IMAGE_DBUS_TEMPLATE="${CMAKE_SOURCE_DIR}/tests/autopilot/lomiri_system_settings/tests/systemimage.py")
+ 
+ add_library(test-plugin SHARED test-plugin.cpp test-plugin.h)
+-- 
+2.42.0
+
diff --git a/nixpkgs/pkgs/desktops/lomiri/applications/lomiri-system-settings/default.nix b/nixpkgs/pkgs/desktops/lomiri/applications/lomiri-system-settings/default.nix
new file mode 100644
index 000000000000..5230e8541181
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/applications/lomiri-system-settings/default.nix
@@ -0,0 +1,236 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, fetchpatch
+, gitUpdater
+, testers
+, accountsservice
+, ayatana-indicator-datetime
+, cmake
+, cmake-extras
+, content-hub
+, dbus
+, deviceinfo
+, geonames
+, gettext
+, glib
+, gnome-desktop
+, gsettings-qt
+, gtk3
+, icu
+, intltool
+, json-glib
+, libqofono
+, libqtdbustest
+, libqtdbusmock
+, lomiri-indicator-network
+, lomiri-schemas
+, lomiri-settings-components
+, lomiri-ui-toolkit
+, maliit-keyboard
+, pkg-config
+, python3
+, qmenumodel
+, qtbase
+, qtdeclarative
+, qtmultimedia
+, ubports-click
+, upower
+, validatePkgConfig
+, wrapGAppsHook
+, wrapQtAppsHook
+, xvfb-run
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "lomiri-system-settings-unwrapped";
+  version = "1.1.0";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/lomiri-system-settings";
+    rev = finalAttrs.version;
+    hash = "sha256-Po5eArO7zyaGatTf6kqci3DdzFDJSZakeglbiMx9kR8=";
+  };
+
+  outputs = [
+    "out"
+    "dev"
+  ];
+
+  patches = [
+    # Remove when https://gitlab.com/ubports/development/core/lomiri-system-settings/-/merge_requests/433 merged & in release
+    (fetchpatch {
+      name = "0001-lomiri-system-settings-plugins-language-Fix-linking-against-accountsservice.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-system-settings/-/commit/75763ae2f9669f5f7f29aec3566606e6f6cb7478.patch";
+      hash = "sha256-2CE0yizkaz93kK82DhaaFjKmGnMoaikrwFj4k7RN534=";
+    })
+
+    # Remove when https://gitlab.com/ubports/development/core/lomiri-system-settings/-/merge_requests/434 merged & in release
+    (fetchpatch {
+      name = "0002-lomiri-system-settings-GNUInstallDirs-and-fix-absolute-path-handling.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-system-settings/-/commit/93ee84423f3677a608ef73addcd3ddcbe7dc1d32.patch";
+      hash = "sha256-lSKAhtE3oSSv7USvDbbcfBZWAtWMmuKneWawKQABIiM=";
+    })
+
+    # Fixes tests with very-recent python-dbusmock
+    # Remove when version > 1.1.0
+    (fetchpatch {
+      name = "0003-lomiri-system-settings-Revert-Pass-missing-parameter-to-dbusmock-bluez-PairDevice-function.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-system-settings/-/commit/67d9e28ebab8bdb9473d5bf8da2b7573e6848fa2.patch";
+      hash = "sha256-pFWNne2UH3R5Fz9ayHvIpDXDQbXPs0k4b/oRg0fzi+s=";
+    })
+  ] ++ [
+
+    ./2000-Support-wrapping-for-Nixpkgs.patch
+
+    # Make it work with regular accountsservice
+    # https://gitlab.com/ubports/development/core/lomiri-system-settings/-/issues/341
+    (fetchpatch {
+      name = "2001-lomiri-system-settings-disable-current-language-switching.patch";
+      url = "https://sources.debian.org/data/main/l/lomiri-system-settings/1.0.1-2/debian/patches/2001_disable-current-language-switching.patch";
+      hash = "sha256-ZOFYwxS8s6+qMFw8xDCBv3nLBOBm86m9d/VhbpOjamY=";
+    })
+  ];
+
+  postPatch = ''
+    substituteInPlace CMakeLists.txt \
+      --replace-fail "\''${CMAKE_INSTALL_LIBDIR}/qt5/qml" "\''${CMAKE_INSTALL_PREFIX}/${qtbase.qtQmlPrefix}" \
+
+    # Port from lomiri-keyboard to maliit-keyboard
+    substituteInPlace plugins/language/CMakeLists.txt \
+      --replace-fail 'LOMIRI_KEYBOARD_PLUGIN_PATH=\"''${CMAKE_INSTALL_FULL_LIBDIR}/lomiri-keyboard/plugins\"' 'LOMIRI_KEYBOARD_PLUGIN_PATH=\"${lib.getLib maliit-keyboard}/lib/maliit/keyboard2/languages\"'
+    substituteInPlace plugins/language/{PageComponent,SpellChecking,ThemeValues}.qml plugins/language/onscreenkeyboard-plugin.cpp plugins/sound/PageComponent.qml \
+      --replace-fail 'com.lomiri.keyboard.maliit' 'org.maliit.keyboard.maliit'
+
+    # Gets list of available localisations from current system, but later drops any language that doesn't cover LSS
+    # So just give it its own prefix
+    substituteInPlace plugins/language/language-plugin.cpp \
+      --replace-fail '/usr/share/locale' '${placeholder "out"}/share/locale'
+
+    # Decide which entries should be visible based on the current system
+    substituteInPlace plugins/*/*.settings \
+      --replace-warn '/etc' '/run/current-system/sw/etc'
+
+    # Don't use absolute paths in desktop file
+    substituteInPlace lomiri-system-settings.desktop.in.in \
+      --replace-fail 'Icon=@SETTINGS_SHARE_DIR@/system-settings.svg' 'Icon=lomiri-system-settings' \
+      --replace-fail 'X-Lomiri-Splash-Image=@SETTINGS_SHARE_DIR@/system-settings-app-splash.svg' 'X-Lomiri-Splash-Image=lomiri-app-launch/splash/lomiri-system-settings.svg' \
+      --replace-fail 'X-Screenshot=@SETTINGS_SHARE_DIR@/screenshot.png' 'X-Screenshot=lomiri-app-launch/screenshot/lomiri-system-settings.png'
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    gettext
+    glib # glib-compile-schemas
+    intltool
+    pkg-config
+    validatePkgConfig
+  ];
+
+  buildInputs = [
+    accountsservice
+    cmake-extras
+    deviceinfo
+    geonames
+    gnome-desktop
+    gsettings-qt
+    gtk3
+    icu
+    json-glib
+    qtbase
+    ubports-click
+    upower
+  ];
+
+  # QML components and schemas the wrapper needs
+  propagatedBuildInputs = [
+    ayatana-indicator-datetime
+    content-hub
+    libqofono
+    lomiri-indicator-network
+    lomiri-schemas
+    lomiri-settings-components
+    lomiri-ui-toolkit
+    maliit-keyboard
+    qmenumodel
+    qtdeclarative
+    qtmultimedia
+  ];
+
+  nativeCheckInputs = [
+    dbus
+    (python3.withPackages (ps: with ps; [
+      python-dbusmock
+    ]))
+    xvfb-run
+  ];
+
+  checkInputs = [
+    libqtdbustest
+    libqtdbusmock
+  ];
+
+  # Not wrapping in this derivation
+  dontWrapQtApps = true;
+
+  cmakeFlags = [
+    (lib.cmakeBool "ENABLE_LIBDEVICEINFO" true)
+    (lib.cmakeBool "ENABLE_TESTS" finalAttrs.finalPackage.doCheck)
+    (lib.cmakeFeature "CMAKE_CTEST_ARGUMENTS" (lib.concatStringsSep ";" [
+      # Exclude tests
+      "-E" (lib.strings.escapeShellArg "(${lib.concatStringsSep "|" [
+        # Hits OpenGL context issue inside lomiri-ui-toolkit, see derivation of that on details
+        "^testmouse"
+        "^tst_notifications"
+      ]})")
+    ]))
+  ];
+
+  # CMake option had to be excluded from earlier patchset
+  env.NIX_CFLAGS_COMPILE = lib.optionalString (lib.strings.versionOlder python3.pkgs.python-dbusmock.version "0.30.1") "-DMODERN_PYTHON_DBUSMOCK";
+
+  # The linking for this normally ignores missing symbols, which is inconvenient for figuring out why subpages may be
+  # failing to load their library modules. Force it to report them at linktime instead of runtime.
+  env.NIX_LDFLAGS = "--unresolved-symbols=report-all";
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  # Parallelism breaks D-Bus tests
+  enableParallelChecking = false;
+
+  preCheck = ''
+    export QT_PLUGIN_PATH=${lib.getBin qtbase}/${qtbase.qtPluginPrefix}
+    export QML2_IMPORT_PATH=${lib.makeSearchPathOutput "bin" qtbase.qtQmlPrefix ([ qtdeclarative lomiri-ui-toolkit lomiri-settings-components ] ++ lomiri-ui-toolkit.propagatedBuildInputs)}
+  '';
+
+  postInstall = ''
+    glib-compile-schemas $out/share/glib-2.0/schemas
+
+    mkdir -p $out/share/{icons/hicolor/scalable/apps,lomiri-app-launch/{splash,screenshot}}
+
+    ln -s $out/share/lomiri-system-settings/system-settings.svg $out/share/icons/hicolor/scalable/apps/lomiri-system-settings.svg
+    ln -s $out/share/lomiri-system-settings/system-settings-app-splash.svg $out/share/lomiri-app-launch/splash/lomiri-system-settings.svg
+    ln -s $out/share/lomiri-system-settings/screenshot.png $out/share/lomiri-app-launch/screenshot/lomiri-system-settings.png
+  '';
+
+  passthru = {
+    tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "System Settings application for Lomiri";
+    homepage = "https://gitlab.com/ubports/development/core/lomiri-system-settings";
+    changelog = "https://gitlab.com/ubports/development/core/lomiri-system-settings/-/blob/${finalAttrs.version}/ChangeLog";
+    license = licenses.gpl3Only;
+    mainProgram = "lomiri-system-settings";
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+    pkgConfigModules = [
+      "LomiriSystemSettings"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/applications/lomiri-system-settings/plugins/lomiri-system-settings-security-privacy.nix b/nixpkgs/pkgs/desktops/lomiri/applications/lomiri-system-settings/plugins/lomiri-system-settings-security-privacy.nix
new file mode 100644
index 000000000000..29a10f12a829
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/applications/lomiri-system-settings/plugins/lomiri-system-settings-security-privacy.nix
@@ -0,0 +1,89 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, biometryd
+, cmake
+, libqtdbusmock
+, libqtdbustest
+, lomiri-system-settings-unwrapped
+, pkg-config
+, polkit
+, python3
+, qtbase
+, qtdeclarative
+, trust-store
+, xvfb-run
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "lomiri-system-settings-security-privacy";
+  version = "1.0.2";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/lomiri-system-settings-security-privacy";
+    rev = finalAttrs.version;
+    hash = "sha256-d7OgxV362gJ3t5N+DEFgwyK+m6Ij6juRPuxfmbCg68Y=";
+  };
+
+  postPatch = ''
+    # CMake pkg_get_variable cannot replace prefix variable yet
+    for pcvar in plugin_manifest_dir plugin_private_module_dir plugin_qml_dir; do
+      pcvarname=$(echo $pcvar | tr '[:lower:]' '[:upper:]')
+      substituteInPlace CMakeLists.txt \
+        --replace-fail "pkg_get_variable($pcvarname LomiriSystemSettings $pcvar)" "set($pcvarname $(pkg-config LomiriSystemSettings --define-variable=prefix=$out --define-variable=libdir=$out/lib --variable=$pcvar))"
+    done
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    pkg-config
+    python3
+  ];
+
+  buildInputs = [
+    lomiri-system-settings-unwrapped
+    polkit
+    qtbase
+    qtdeclarative
+    trust-store
+  ];
+
+  # QML components and schemas the wrapper needs
+  propagatedBuildInputs = [
+    biometryd
+  ];
+
+  nativeCheckInputs = [
+    xvfb-run
+  ];
+
+  checkInputs = [
+    libqtdbusmock
+    libqtdbustest
+  ];
+
+  # Plugin library & modules for LSS
+  dontWrapQtApps = true;
+
+  cmakeFlags = [
+    (lib.cmakeBool "ENABLE_TESTS" finalAttrs.finalPackage.doCheck)
+  ];
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  preCheck = ''
+    export QT_PLUGIN_PATH=${lib.getBin qtbase}/${qtbase.qtPluginPrefix}
+  '';
+
+  meta = with lib; {
+    description = "Security and privacy settings plugin for Lomiri system settings";
+    homepage = "https://gitlab.com/ubports/development/core/lomiri-system-settings-security-privacy";
+    changelog = "https://gitlab.com/ubports/development/core/lomiri-system-settings-security-privacy/-/blob/${finalAttrs.version}/ChangeLog";
+    license = licenses.gpl3Only;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/applications/lomiri-system-settings/wrapper.nix b/nixpkgs/pkgs/desktops/lomiri/applications/lomiri-system-settings/wrapper.nix
new file mode 100644
index 000000000000..74767f41d9ec
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/applications/lomiri-system-settings/wrapper.nix
@@ -0,0 +1,70 @@
+{ stdenvNoCC
+, lib
+, nixosTests
+, glib
+, lndir
+, lomiri-system-settings-unwrapped
+, lomiri-system-settings-security-privacy
+, wrapGAppsHook
+, wrapQtAppsHook
+, plugins ? [ lomiri-system-settings-security-privacy ]
+}:
+
+stdenvNoCC.mkDerivation (finalAttrs: {
+  pname = "lomiri-system-settings";
+  inherit (lomiri-system-settings-unwrapped) version;
+
+  dontUnpack = true;
+  dontConfigure = true;
+  dontBuild = true;
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    lndir
+    wrapGAppsHook
+    wrapQtAppsHook
+  ];
+
+  buildInputs = [
+    glib # schema hook
+    lomiri-system-settings-unwrapped
+  ] ++ plugins;
+
+  installPhase = ''
+    runHook preInstall
+
+    mkdir -p $out/bin
+    ln -s ${lib.getExe lomiri-system-settings-unwrapped} $out/bin/${finalAttrs.meta.mainProgram}
+
+    for inheritedPath in share/lomiri-app-launch share/lomiri-url-dispatcher share/applications share/icons; do
+      mkdir -p $out/$inheritedPath
+      lndir ${lomiri-system-settings-unwrapped}/$inheritedPath $out/$inheritedPath
+    done
+
+    for mergedPath in lib/lomiri-system-settings share/lomiri-system-settings share/locale; do
+      mkdir -p $out/$mergedPath
+      for lssPart in ${lomiri-system-settings-unwrapped} ${lib.strings.concatStringsSep " " plugins}; do
+        lndir $lssPart/$mergedPath $out/$mergedPath
+      done
+    done
+
+    runHook postInstall
+  '';
+
+  dontWrapGApps = true;
+
+  preFixup = ''
+    qtWrapperArgs+=(
+      "''${gappsWrapperArgs[@]}"
+      --set NIX_LSS_PREFIX "$out"
+    )
+  '';
+
+  passthru.tests.standalone = nixosTests.lomiri-system-settings;
+
+  meta = lomiri-system-settings-unwrapped.meta // {
+    description = "System Settings application for Lomiri (wrapped)";
+    priority = (lomiri-system-settings-unwrapped.meta.priority or 0) - 1;
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/applications/lomiri-terminal-app/default.nix b/nixpkgs/pkgs/desktops/lomiri/applications/lomiri-terminal-app/default.nix
new file mode 100644
index 000000000000..31ef9ed8838c
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/applications/lomiri-terminal-app/default.nix
@@ -0,0 +1,104 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, fetchpatch
+, gitUpdater
+, nixosTests
+, cmake
+, gsettings-qt
+, lomiri-ui-extras
+, lomiri-ui-toolkit
+, pkg-config
+, qmltermwidget
+, qtbase
+, qtdeclarative
+, qtsystems
+, wrapQtAppsHook
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "lomiri-terminal-app";
+  version = "2.0.2";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/apps/lomiri-terminal-app";
+    rev = "v${finalAttrs.version}";
+    hash = "sha256-mXbPmVcl5dL78QUp+w3o4im5ohUQCPTKWLSVqlNO0yo=";
+  };
+
+  patches = [
+    # Stop usage of private qt5_use_modules function, seemingly unavailable in this package
+    # Remove when https://gitlab.com/ubports/development/apps/lomiri-terminal-app/-/merge_requests/103 merged & in release
+    (fetchpatch {
+      name = "0001-lomiri-terminal-app-Stop-using-qt5_use_modules.patch";
+      url = "https://gitlab.com/ubports/development/apps/lomiri-terminal-app/-/commit/db210c74e771a427066aebdc3a99cab6e782d326.patch";
+      hash = "sha256-op4+/eo8rBRMcW6MZ0rOEFReM7JBCck1B+AsgAPyqAI=";
+    })
+
+    # Explicitly bind textdomain, don't rely on hacky workaround in LUITK
+    # Remove when https://gitlab.com/ubports/development/apps/lomiri-terminal-app/-/merge_requests/104 merged & in release
+    (fetchpatch {
+      name = "0002-lomiri-terminal-app-Call-i18n.bindtextdomain.patch";
+      url = "https://gitlab.com/ubports/development/apps/lomiri-terminal-app/-/commit/7f9d419e29043f0d0922d2ac1dce5673e2723a01.patch";
+      hash = "sha256-HfIvGVbIdTasoHAfHysnzFLufQQ4lskym5HTekH+mjk=";
+    })
+
+    # Add more & correct existing usage of GNUInstallDirs variables
+    # Remove when https://gitlab.com/ubports/development/apps/lomiri-terminal-app/-/merge_requests/105 merged & in release
+    (fetchpatch {
+      name = "0003-lomiri-terminal-app-GNUInstallDirs-usage.patch";
+      url = "https://gitlab.com/ubports/development/apps/lomiri-terminal-app/-/commit/fcde1f05bb442c74b1dff95917fd7594f26e97a7.patch";
+      hash = "sha256-umxCMGNjyz0TVmwH0Gl0MpgjLQtkW9cHkUfpNJcoasE=";
+    })
+  ];
+
+  postPatch = ''
+    substituteInPlace CMakeLists.txt \
+      --replace "\''${CMAKE_INSTALL_LIBDIR}/qt5/qml" "\''${CMAKE_INSTALL_PREFIX}/${qtbase.qtQmlPrefix}"
+
+    # Tests look abandoned - add_test in CMake code is commented out, refers to old repo structure in import paths
+    sed -i -e '/add_subdirectory(tests)/d' CMakeLists.txt
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    pkg-config
+    wrapQtAppsHook
+  ];
+
+  buildInputs = [
+    qtbase
+    qtdeclarative
+    qmltermwidget
+
+    # QML
+    gsettings-qt
+    lomiri-ui-extras
+    lomiri-ui-toolkit
+    qtsystems
+  ];
+
+  cmakeFlags = [
+    "-DINSTALL_TESTS=OFF"
+    "-DCLICK_MODE=OFF"
+  ];
+
+  passthru = {
+    tests.vm-test = nixosTests.terminal-emulators.lomiri-terminal-app;
+    updateScript = gitUpdater {
+      rev-prefix = "v";
+    };
+  };
+
+  meta = with lib; {
+    description = "A terminal app for desktop and mobile devices";
+    homepage = "https://gitlab.com/ubports/development/apps/lomiri-terminal-app";
+    license = licenses.gpl3Only;
+    mainProgram = "lomiri-terminal-app";
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/applications/lomiri/9901-lomiri-Disable-Wizard.patch b/nixpkgs/pkgs/desktops/lomiri/applications/lomiri/9901-lomiri-Disable-Wizard.patch
new file mode 100644
index 000000000000..7fe6332cadab
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/applications/lomiri/9901-lomiri-Disable-Wizard.patch
@@ -0,0 +1,30 @@
+From b7757a71bbce18b4718474cab6a7ff7b613f8c86 Mon Sep 17 00:00:00 2001
+From: OPNA2608 <opna2608@protonmail.com>
+Date: Sun, 19 Nov 2023 13:25:55 +0100
+Subject: [PATCH] lomiri: Disable Wizard
+
+NixOS does all of this configuration statically at generation build & setup time. For us this just ends up being series of screens
+re-confirming abunch of things set in your configuration, so pointless.
+---
+ plugins/Wizard/System.cpp | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+diff --git a/plugins/Wizard/System.cpp b/plugins/Wizard/System.cpp
+index aee8184a8..06c867023 100644
+--- a/plugins/Wizard/System.cpp
++++ b/plugins/Wizard/System.cpp
+@@ -69,10 +69,7 @@ bool System::wizardPathExists() {
+ 
+ bool System::wizardEnabled() const
+ {
+-    if (!wizardPathExists()) {
+-        return true;
+-    }
+-    return isUpdate();
++    return false;
+ }
+ 
+ QString System::readCurrentFramework()
+-- 
+2.40.1
+
diff --git a/nixpkgs/pkgs/desktops/lomiri/applications/lomiri/default.nix b/nixpkgs/pkgs/desktops/lomiri/applications/lomiri/default.nix
new file mode 100644
index 000000000000..2c1b64bf0ca8
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/applications/lomiri/default.nix
@@ -0,0 +1,289 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, fetchpatch
+, fetchpatch2
+, gitUpdater
+, linkFarm
+, nixosTests
+, ayatana-indicator-datetime
+, bash
+, biometryd
+, boost
+, cmake
+, cmake-extras
+, coreutils
+, dbus
+, dbus-test-runner
+, deviceinfo
+, geonames
+, glib
+, glm
+, gnome-desktop
+, gsettings-qt
+, gtk3
+, hfd-service
+, libevdev
+, libqtdbustest
+, libqtdbusmock
+, libusermetrics
+, libuuid
+, lightdm_qt
+, lomiri-api
+, lomiri-app-launch
+, lomiri-download-manager
+, lomiri-indicator-network
+, lomiri-ui-toolkit
+, lomiri-settings-components
+, lomiri-system-settings-unwrapped
+, lomiri-schemas
+, lomiri-notifications
+, lomiri-thumbnailer
+, maliit-keyboard
+, mir
+, nixos-icons
+, pam
+, pkg-config
+, properties-cpp
+, protobuf
+, python3
+, qmenumodel
+, qtbase
+, qtdeclarative
+, qtmir
+, qtmultimedia
+, qtsvg
+, telephony-service
+, wrapGAppsHook
+, wrapQtAppsHook
+, xwayland
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "lomiri";
+  version = "0.2.1";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/lomiri";
+    rev = finalAttrs.version;
+    hash = "sha256-V5Lt870eHgmJ63OF8bTiNFLAFrxdgNihkd7aodSO3v8=";
+  };
+
+  patches = [
+    # Remove when version > 0.2.1
+    (fetchpatch {
+      name = "0001-lomiri-Fix-overwriting-INCLUDE_DIRECTORIES-variable.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri/-/commit/53190bf2f03c8a35491efb26222b8d67ff6caa34.patch";
+      hash = "sha256-sbwqOqpTf5OlEB4NZZZTFNXyKq4rTQAxJ6U8YP/DT5s=";
+    })
+
+    # fetchpatch2 for renames
+    # Use GNUInstallDirs variables better, replace more /usr references
+    # Remove when https://gitlab.com/ubports/development/core/lomiri/-/merge_requests/137 merged & in release
+    (fetchpatch2 {
+      name = "0002-lomiri-Make-less-FHS-assumptions.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri/-/commit/817ae1d8ed927e661fbc006851163ba99c46ae13.patch";
+      hash = "sha256-NLvpzI2MtjKcGrgTn6PbLXSy3/Jg8KxdSvVYO9KYu9g=";
+    })
+
+    # Fix greeter & related settings
+    # These patches are seemingly not submitted upstream yet
+    (fetchpatch {
+      name = "1000-lomiri-QT_IM_MODULE-maliit.patch";
+      url = "https://salsa.debian.org/ubports-team/lomiri/-/raw/ebbe0f3f568bd145bb58a2e47f7112442328a0a5/debian/patches/2003_maliit-not-maliitphablet-as-im-module-namespace.patch";
+      hash = "sha256-5HEMl0x1S9Hb7spxPRgu8OBebmpaLa6zko2uVEYtBmY=";
+    })
+    (fetchpatch {
+      name = "1001-lomiri-QT_QPA_PLATFORM-wayland.patch";
+      url = "https://salsa.debian.org/ubports-team/lomiri/-/raw/ebbe0f3f568bd145bb58a2e47f7112442328a0a5/debian/patches/2004_qt-qpa-platform-is-wayland.patch";
+      hash = "sha256-4C6X2TW+yjZhqYPIcQ3GJeTKbz785i7p/DpT+vX1DSQ=";
+    })
+    (fetchpatch {
+      name = "1002-lomiri-Fix-Lomiri-greeter.patch";
+      url = "https://salsa.debian.org/ubports-team/lomiri/-/raw/ebbe0f3f568bd145bb58a2e47f7112442328a0a5/debian/patches/1008_lomiri-greeter-wayland.patch";
+      excludes = [ "data/lomiri-greeter.desktop.in.in" ]; # conflict with GNUInstallDirs patch
+      hash = "sha256-XSSxf06Su8PMoqYwqevN034b/li8G/cNXjrqOXyhTRg=";
+    })
+    (fetchpatch {
+      name = "1003-lomiri-Hide-launcher-in-greeter-mode.patch";
+      url = "https://salsa.debian.org/ubports-team/lomiri/-/raw/ebbe0f3f568bd145bb58a2e47f7112442328a0a5/debian/patches/0002_qml-shell-hide-and-disallow-launcher-in-greeter-only-mode.patch";
+      hash = "sha256-R0aMlb7N7XACCthML4SQSd0LvbadADfdQJqrYFhmujk=";
+    })
+    (fetchpatch {
+      name = "1004-lomiri-Dont-reset-OSK-setting.patch";
+      url = "https://salsa.debian.org/ubports-team/lomiri/-/raw/ebbe0f3f568bd145bb58a2e47f7112442328a0a5/debian/patches/2005_dont-reset-alwaysShowOsk-to-system-defaults-on-login.patch";
+      hash = "sha256-guq/Ykcq4WcuXxNKO1eA4sJFyGSpZo0gtyFTdeK/GeE=";
+    })
+
+    ./9901-lomiri-Disable-Wizard.patch
+  ];
+
+  postPatch = ''
+    # Part of greeter fix, applies separately due to merge conflicts
+    substituteInPlace data/lomiri-greeter.desktop.in.in \
+      --replace-fail '@CMAKE_INSTALL_FULL_BINDIR@/lomiri-greeter-wrapper @CMAKE_INSTALL_FULL_BINDIR@/lomiri --mode=greeter' '@CMAKE_INSTALL_FULL_BINDIR@/lomiri --mode=greeter' \
+      --replace-fail 'X-LightDM-Session-Type=mir' 'X-LightDM-Session-Type=wayland'
+
+    # Need to replace prefix
+    substituteInPlace data/systemd-user/CMakeLists.txt \
+      --replace-fail 'pkg_get_variable(SYSTEMD_USERUNITDIR systemd systemduserunitdir)' 'pkg_get_variable(SYSTEMD_USERUNITDIR systemd systemduserunitdir DEFINE_VARIABLES prefix=''${CMAKE_INSTALL_PREFIX})'
+
+    # Don't embed full paths into regular desktop files (but do embed them into lightdm greeter one)
+    substituteInPlace data/{indicators-client,lomiri}.desktop.in.in \
+      --replace-fail '@CMAKE_INSTALL_FULL_BINDIR@/' ""
+
+    # Exclude tests that don't compile (Mir headers these relied on were removed in mir 2.9)
+    # fatal error: mirtest/mir/test/doubles/stub_surface.h: No such file or directory
+    substituteInPlace tests/mocks/CMakeLists.txt \
+      --replace-fail 'add_subdirectory(QtMir/Application)' ""
+
+    #substituteInPlace plugins/AccountsService/CMakeLists.txt \
+    #  --replace-fail 'CMAKE_INSTALL_DATADIR' 'CMAKE_INSTALL_FULL_DATADIR'
+
+    # NixOS-ify
+
+    # Use Nix flake instead of Canonical's Ubuntu logo
+    rm qml/Launcher/graphics/home.svg
+    ln -s ${nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake-white.svg qml/Launcher/graphics/home.svg
+
+    # Look up default wallpaper in current system
+    substituteInPlace plugins/Utils/constants.cpp \
+      --replace-fail '/usr/share/backgrounds' '/run/current-system/sw/share/wallpapers'
+  '' + lib.optionalString finalAttrs.finalPackage.doCheck ''
+    patchShebangs tests/whitespace/check_whitespace.py
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    glib # populates GSETTINGS_SCHEMAS_PATH
+    pkg-config
+    wrapGAppsHook # XDG_DATA_DIRS wrapper flags for schemas
+    wrapQtAppsHook
+  ];
+
+  buildInputs = [
+    ayatana-indicator-datetime
+    bash
+    boost
+    cmake-extras
+    dbus
+    dbus-test-runner
+    deviceinfo
+    geonames
+    glib
+    glm
+    gnome-desktop
+    gsettings-qt
+    gtk3
+    libevdev
+    libusermetrics
+    libuuid
+    lightdm_qt
+    lomiri-api
+    lomiri-app-launch
+    lomiri-download-manager
+    lomiri-indicator-network
+    lomiri-schemas
+    lomiri-system-settings-unwrapped
+    lomiri-ui-toolkit
+    maliit-keyboard
+    mir
+    pam
+    properties-cpp
+    protobuf
+    qmenumodel
+    qtbase
+    qtdeclarative
+    qtmir
+    qtsvg
+
+    # QML import path
+    biometryd
+    hfd-service
+    lomiri-notifications
+    lomiri-settings-components
+    lomiri-thumbnailer
+    qtmultimedia
+    telephony-service
+  ];
+
+  nativeCheckInputs = [
+    (python3.withPackages (ps: with ps; [
+      python-dbusmock
+    ]))
+  ];
+
+  checkInputs = [
+    libqtdbustest
+    libqtdbusmock
+  ];
+
+  # Need its flags
+  dontWrapGApps = true;
+
+  # Manually calling, to avoid double & unnecessary wrapping
+  dontWrapQtApps = true;
+
+  cmakeFlags = [
+    (lib.cmakeBool "NO_TESTS" (!finalAttrs.finalPackage.doCheck))
+  ];
+
+  postInstall = ''
+    install -Dm755 ../data/lomiri-greeter-wrapper $out/bin/lomiri-greeter-wrapper
+  '';
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  preCheck = ''
+    export QT_PLUGIN_PATH=${lib.getBin qtbase}/${qtbase.qtPluginPrefix}
+    export XDG_DATA_DIRS=${libqtdbusmock}/share
+  '';
+
+  preFixup = ''
+    qtWrapperArgs+=("''${gappsWrapperArgs[@]}")
+  '';
+
+  postFixup = ''
+    wrapQtApp $out/bin/lomiri
+    wrapQtApp $out/bin/indicators-client
+    wrapQtApp $out/bin/lomiri-mock-indicator-service
+
+    wrapProgram $out/bin/lomiri-greeter-wrapper \
+      --prefix PATH : ${lib.makeBinPath [ coreutils dbus deviceinfo glib ]} \
+      --set LOMIRI_BINARY "$out/bin/lomiri"
+
+    wrapProgram $out/libexec/Xwayland.lomiri \
+      --prefix PATH : ${lib.makeBinPath [ deviceinfo ]}
+
+    wrapProgram $out/libexec/lomiri-systemd-wrapper \
+      --prefix PATH : ${lib.makeBinPath [ dbus ]}
+  '';
+
+  passthru = {
+    tests.lomiri = nixosTests.lomiri;
+    updateScript = gitUpdater { };
+    greeter = linkFarm "lomiri-greeter" [{
+      path = "${finalAttrs.finalPackage}/share/lightdm/greeters/lomiri-greeter.desktop";
+      name = "lomiri-greeter.desktop";
+    }];
+  };
+
+  meta = with lib; {
+    description = "Shell of the Lomiri Operating environment";
+    longDescription = ''
+      Shell of the Lomiri Operating environment optimized for touch based human-machine interaction, but also supporting
+      convergence (i.e. switching between tablet/phone and desktop mode).
+
+      Lomiri is the user shell driving Ubuntu Touch based mobile devices.
+    '';
+    homepage = "https://lomiri.com/";
+    changelog = "https://gitlab.com/ubports/development/core/lomiri/-/blob/${finalAttrs.version}/ChangeLog";
+    license = licenses.gpl3Only;
+    mainProgram = "lomiri";
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/applications/morph-browser/default.nix b/nixpkgs/pkgs/desktops/lomiri/applications/morph-browser/default.nix
new file mode 100644
index 000000000000..f6e92d0c3504
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/applications/morph-browser/default.nix
@@ -0,0 +1,148 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, fetchpatch
+, gitUpdater
+, nixosTests
+, cmake
+, content-hub
+, gettext
+, libapparmor
+, lomiri-action-api
+, lomiri-ui-extras
+, lomiri-ui-toolkit
+, pkg-config
+, qqc2-suru-style
+, qtbase
+, qtdeclarative
+, qtquickcontrols2
+, qtsystems
+, qtwebengine
+, wrapQtAppsHook
+, xvfb-run
+}:
+
+let
+  listToQtVar = suffix: lib.makeSearchPathOutput "bin" suffix;
+in
+stdenv.mkDerivation (finalAttrs: {
+  pname = "morph-browser";
+  version = "1.1.0";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/morph-browser";
+    rev = finalAttrs.version;
+    hash = "sha256-C5iXv8VS8Mm1ryxK7Vi5tVmiM01OSIFiTyH0vP9B/xA=";
+  };
+
+  patches = [
+    # Remove when https://gitlab.com/ubports/development/core/morph-browser/-/merge_requests/575 merged & in release
+    (fetchpatch {
+      name = "0001-morph-browser-tst_SessionUtilsTests-Set-permissions-on-temporary-xdg-runtime-directory.patch";
+      url = "https://gitlab.com/ubports/development/core/morph-browser/-/commit/e90206105b8b287fbd6e45ac37ca1cd259981928.patch";
+      hash = "sha256-5htFn+OGVVBn3mJQaZcF5yt0mT+2QRlKyKFesEhklfA=";
+    })
+
+    # Remove when https://gitlab.com/ubports/development/core/morph-browser/-/merge_requests/576 merged & in release
+    (fetchpatch {
+      name = "0002-morph-browser-Call-i18n-bindtextdomain-with-buildtime-determined-locale-path.patch";
+      url = "https://gitlab.com/ubports/development/core/morph-browser/-/commit/0527a1e01fb27c62f5e0011274f73bad400e9691.patch";
+      hash = "sha256-zx/pP72uNqAi8TZR4bKeONuqcJyK/vGtPglTA+5R5no=";
+    })
+  ];
+
+  postPatch = ''
+    substituteInPlace src/{Morph,Ubuntu}/CMakeLists.txt \
+      --replace '/usr/lib/''${CMAKE_LIBRARY_ARCHITECTURE}/qt5/qml' "\''${CMAKE_INSTALL_PREFIX}/${qtbase.qtQmlPrefix}"
+
+    # We normally don't want to use absolute paths in desktop file, but this one is special
+    # There appears to be some issue in lomiri-app-launch's lookup of relative Icon entries (while lomiri is starting up?)
+    # that makes the session segfault.
+    # As a compromise, hardcode /run/current-system
+    substituteInPlace src/app/webbrowser/morph-browser.desktop.in.in \
+      --replace 'Icon=@CMAKE_INSTALL_FULL_DATADIR@/morph-browser/morph-browser.svg' 'Icon=/run/current-system/sw/share/icons/hicolor/scalable/apps/morph-browser.svg' \
+      --replace 'X-Lomiri-Splash-Image=@CMAKE_INSTALL_FULL_DATADIR@/morph-browser/morph-browser-splash.svg' 'X-Lomiri-Splash-Image=lomiri-app-launch/splash/morph-browser.svg'
+  '' + lib.optionalString (!finalAttrs.doCheck) ''
+    substituteInPlace CMakeLists.txt \
+      --replace 'add_subdirectory(tests)' ""
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    gettext
+    pkg-config
+    wrapQtAppsHook
+  ];
+
+  buildInputs = [
+    libapparmor
+    qtbase
+    qtdeclarative
+    qtwebengine
+
+    # QML
+    content-hub
+    lomiri-action-api
+    lomiri-ui-extras
+    lomiri-ui-toolkit
+    qqc2-suru-style
+    qtquickcontrols2
+    qtsystems
+  ];
+
+  nativeCheckInputs = [
+    xvfb-run
+  ];
+
+  cmakeFlags = [
+    (lib.cmakeFeature "CMAKE_CTEST_ARGUMENTS" (lib.concatStringsSep ";" [
+      # Exclude tests
+      "-E" (lib.strings.escapeShellArg "(${lib.concatStringsSep "|" [
+        # Don't care about linter failures
+        "^flake8"
+
+        # Runs into ShapeMaterial codepath in lomiri-ui-toolkit which needs OpenGL, see LUITK for details
+        "^tst_QmlTests"
+      ]})")
+    ]))
+  ];
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  preCheck = ''
+    export HOME=$TMPDIR
+    export QT_PLUGIN_PATH=${listToQtVar qtbase.qtPluginPrefix [ qtbase ]}
+    export QML2_IMPORT_PATH=${listToQtVar qtbase.qtQmlPrefix ([ lomiri-ui-toolkit qtwebengine qtdeclarative qtquickcontrols2 qtsystems ] ++ lomiri-ui-toolkit.propagatedBuildInputs)}
+  '';
+
+  postInstall = ''
+    mkdir -p $out/share/{icons/hicolor/scalable/apps,lomiri-app-launch/splash}
+
+    ln -s $out/share/{morph-browser,icons/hicolor/scalable/apps}/morph-browser.svg
+    ln -s $out/share/{morph-browser/morph-browser-splash.svg,lomiri-app-launch/splash/morph-browser.svg}
+  '';
+
+  passthru = {
+    updateScript = gitUpdater { };
+    tests = {
+      # Test of morph-browser itself
+      standalone = nixosTests.morph-browser;
+
+      # Lomiri-specific issues with the desktop file may break the entire session, make sure it still works
+      lomiri = nixosTests.lomiri;
+    };
+  };
+
+  meta = with lib; {
+    description = "Lightweight web browser tailored for Ubuntu Touch";
+    homepage = "https://gitlab.com/ubports/development/core/morph-browser";
+    changelog = "https://gitlab.com/ubports/development/core/morph-browser/-/blob/${finalAttrs.version}/ChangeLog";
+    license = with licenses; [ gpl3Only cc-by-sa-30 ];
+    mainProgram = "morph-browser";
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/data/lomiri-schemas/default.nix b/nixpkgs/pkgs/desktops/lomiri/data/lomiri-schemas/default.nix
new file mode 100644
index 000000000000..4d1caf6eb873
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/data/lomiri-schemas/default.nix
@@ -0,0 +1,61 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, gitUpdater
+, testers
+, cmake
+, cmake-extras
+, glib
+, intltool
+, pkg-config
+, validatePkgConfig
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "lomiri-schemas";
+  version = "0.1.4";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/lomiri-schemas";
+    rev = finalAttrs.version;
+    hash = "sha256-Pnn/Qh5EYEqmP8QFsZcSCpDL36++aeUUok3t9a1/1n0=";
+  };
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    glib # glib-compile-schemas
+    pkg-config
+    intltool
+    validatePkgConfig
+  ];
+
+  buildInputs = [
+    cmake-extras
+    glib
+  ];
+
+  cmakeFlags = [
+    (lib.cmakeBool "GSETTINGS_LOCALINSTALL" true)
+    (lib.cmakeBool "GSETTINGS_COMPILE" true)
+  ];
+
+  passthru = {
+    tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "GSettings / AccountsService schema files for Lomiri";
+    homepage = "https://gitlab.com/ubports/development/core/lomiri-schemas";
+    changelog = "https://gitlab.com/ubports/development/core/lomiri-schemas/-/blob/${finalAttrs.version}/ChangeLog";
+    license = licenses.lgpl21Plus;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+    pkgConfigModules = [
+      "lomiri-schemas"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/data/lomiri-session/default.nix b/nixpkgs/pkgs/desktops/lomiri/data/lomiri-session/default.nix
new file mode 100644
index 000000000000..c62e4ab572bd
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/data/lomiri-session/default.nix
@@ -0,0 +1,198 @@
+{ stdenvNoCC
+, lib
+, fetchFromGitLab
+, fetchpatch
+, fetchpatch2
+, gitUpdater
+, nixosTests
+, bash
+, cmake
+, dbus
+, deviceinfo
+, inotify-tools
+, lomiri
+, makeWrapper
+, pkg-config
+, runtimeShell
+, systemd
+}:
+
+stdenvNoCC.mkDerivation (finalAttrs: {
+  pname = "lomiri-session";
+  version = "0.2";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/lomiri-session";
+    rev = finalAttrs.version;
+    hash = "sha256-1ZpAn1tFtlXIfeejG0TnrJBRjf3tyz7CD+riWo+sd0s=";
+  };
+
+  patches = [
+    # Properly gate of UBtouch-specific code
+    # Otherwise session won't launch, errors out on a removed Mir setting
+    # Remove when version > 0.2
+    (fetchpatch {
+      name = "0001-lomiri-session-Properly-differentiate-between-Ubuntu-Touch-and-Lomiri-Desktop-session.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-session/-/commit/780c19d8b4f18ce24ceb64b8abfae70018579dce.patch";
+      hash = "sha256-eFiagFEpH43WpVGA6xkI1IiQ99HHizonhXYg1wYAhwU=";
+    })
+
+    # Export Lomiri-prefixed stop envvar
+    # Remove when version > 0.2
+    (fetchpatch {
+      name = "0002-lomiri-session-Use-LOMIRI_MIR_EMITS_SIGSTOP.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-session/-/commit/452e38b489b5893aac3481410d708f4397b1fa1c.patch";
+      hash = "sha256-w/kifBLfDm8+CBliVjm4o8JtjaOByHf97XyPhVk6Gho=";
+    })
+
+    # Removes broken first-time wizard check
+    # Remove when version > 0.2
+    (fetchpatch {
+      name = "0003-lomiri-session-Drop-old-wizard-has-run-check.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-session/-/commit/c16ae87d8848f9909850072f7728c03c894b1a47.patch";
+      hash = "sha256-AIwgztFOGwG2zUsaUen/Z3Mes9m7VgbvNKWp/qYp4g4=";
+    })
+
+    # Fix quoting on ps check
+    # Remove when version > 0.2
+    (fetchpatch {
+      name = "0004-lomiri-session-Put-evaluation-of-ps-call-in-quotes.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-session/-/commit/2d7368eae99f07200c814c840636206b9eaa485d.patch";
+      hash = "sha256-6LqurJqi/I+Qw64hWTrvA8uA/EIRZbcS6TRRXK+9s1s=";
+    })
+
+    # Check for Xwayland presense to determine X11 support
+    # Remove when version > 0.2
+    (fetchpatch {
+      name = "0005-lomiri-session-Check-for-Xwayland-presence.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-session/-/commit/707e43d3b1a6200535b7682e63817265a8e4ee7e.patch";
+      hash = "sha256-sI00P31QVF7ZKdwNep2r+0MetNGg/bbrd2YfEzZPLFI=";
+    })
+
+    # Fix systemd service startup things, drop upstart hacks
+    # Remove when https://gitlab.com/ubports/development/core/lomiri-session/-/merge_requests/13 merged & in release
+    (fetchpatch {
+      name = "0100-lomiri-session-Drop-Before-Wants-for-App-Indicator-targets.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-session/-/commit/ccebdc1c47d7411a9cf4ad2e529471fb0403433a.patch";
+      hash = "sha256-vGFvcCjbwcuLrAUIsL5y/QmoOR5i0560LNv01ZT9OOg=";
+    })
+    (fetchpatch {
+      name = "0101-lomiri-session-Start-lal-application-end.target-on-stop-restart.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-session/-/commit/9a945b09feff0c1d2b3203caaf3cec5230481e80.patch";
+      hash = "sha256-1vD+I5YDEh2wF7UDn6ZxPTBRrdUvwWVXt5x5QdkIAkY=";
+    })
+    (fetchpatch {
+      name = "0102-lomiri-session-Drop-manual-Xwayland-start-logic.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-session/-/commit/6aee0d6cfd76ab1904876f4166621f9f6d833056.patch";
+      hash = "sha256-iW/Ko+Xm2ZuJuNE7ATeuMTSHby0fXD+D5nWjX6LLLwU=";
+    })
+    (fetchpatch {
+      name = "0103-lomiri-session-Set-SyslogIdentifier.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-session/-/commit/09d378728685411a04333040279cdaef487dedc8.patch";
+      hash = "sha256-minJSxrn2d0+FBlf7bdN3ddSvsn6YWdeH6ZuCW7qbII=";
+    })
+    (fetchpatch {
+      name = "0104-lomiri-session-Use-LOMIRI_AS_SYSTEMD_UNIT-to-launch-session.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-session/-/commit/9bd2552c2638c139a0abff527fda99f2ef94cc42.patch";
+      hash = "sha256-7ipsGrQRJ98uVSRp2e0U4q3iTuyeUalqZIohbxXpT9k=";
+    })
+    (fetchpatch {
+      name = "0105-lomiri-session-Allow-sd_notify-calls-for-NOTIFY_SOCKET.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-session/-/commit/2157bfc472f2d35e7c81002a924a1f6aa85f7395.patch";
+      hash = "sha256-qtArOG4gysFWGnXbz3KpXEppaZ1PGDQKEGqnJvU6/RE=";
+    })
+    (fetchpatch {
+      name = "0106-lomiri-session-Change-envvar-for-1-time-binary.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-session/-/commit/0cd1dbd30f3d5c6e50bce79146e8511e0ee56153.patch";
+      hash = "sha256-b8/Mrs36JPJE6l6/Dc/PN+zNV8Oq37HOFx+zMQvWPBY=";
+    })
+    (fetchpatch {
+      name = "0107-lomiri-session-Drag-lomiri-process-under-umbrella-of-wrapper-script.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-session/-/commit/d8212b1862924eb283fd1ee7ea390a144d5ee97e.patch";
+      hash = "sha256-UJzV0pYEBBrXSpYxdFoBoMRzPeIQtvtPzDW2/Ljz+uI=";
+    })
+    (fetchpatch {
+      name = "0108-lomiri-session-Dont-hide-exit-code-from-systemd.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-session/-/commit/9ac78d736caa891a4923be8d040fe8224e335215.patch";
+      hash = "sha256-yPg1K0IfaGYKqg9536i9AFCLTcAENlsJNdHjrElSeZ4=";
+    })
+
+    # Don't require a C & C++ compiler, nothing to compile
+    # Remove when https://gitlab.com/ubports/development/core/lomiri-session/-/merge_requests/14 merged & in release
+    (fetchpatch {
+      name = "0200-lomiri-session-Dont-require-a-compiler.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-session/-/commit/6915a5678e09e5dbcb26d29a8e5585d032a19186.patch";
+      hash = "sha256-2SWiOLDLsdTjRHaJcnZe/WKcFMFmHtpZsuj7bQCtB4A=";
+    })
+
+    # Use GNUInstallDirs for install locations, find_program() for locations of used binaries
+    # fetchpatch2 due to renames, need to resolve merge conflict manually in postPatch
+    # Remove when https://gitlab.com/ubports/development/core/lomiri-session/-/merge_requests/15 merged & in release
+    (fetchpatch2 {
+      name = "0201-lomiri-session-Hardcode-less-locations.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-session/-/commit/d5b93ecaf08ba776a79c69e8a9dd05d0b6181947.patch";
+      excludes = [ "systemd/lomiri.service" ];
+      hash = "sha256-BICb6ZwU/sUBzmM4udsOndIgw1A03I/UEG000YvMZ9Y=";
+    })
+  ];
+
+  postPatch = ''
+    # Resolving merge conflict
+    mv systemd/lomiri.service{,.in}
+    substituteInPlace systemd/lomiri.service.in \
+      --replace-fail '/usr/bin/lomiri-session' '@CMAKE_INSTALL_FULL_BINDIR@/lomiri-session' \
+      --replace-fail '/usr/bin/dbus-update-activation-environment' '@DUAE_BIN@'
+
+    substituteInPlace lomiri-session \
+      --replace-fail '/usr/libexec/Xwayland.lomiri' '${lib.getBin lomiri}/libexec/Xwayland.lomiri'
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    makeWrapper
+    pkg-config
+  ];
+
+  buildInputs = [
+    bash
+    deviceinfo
+    dbus
+    inotify-tools
+    lomiri
+    systemd
+  ];
+
+  cmakeFlags = [
+    # Requires lomiri-system-compositor -> not ported to Mir 2.x yet
+    (lib.cmakeBool "ENABLE_TOUCH_SESSION" false)
+  ];
+
+  postInstall = ''
+    patchShebangs $out/bin/lomiri-session
+    wrapProgram $out/bin/lomiri-session \
+      --prefix PATH : ${lib.makeBinPath [ deviceinfo inotify-tools lomiri ]}
+  '';
+
+  passthru = {
+    providedSessions = [
+      "lomiri"
+      # not packaged/working yet
+      # "lomiri-touch"
+    ];
+    tests.lomiri = nixosTests.lomiri;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "Integrates Lomiri desktop/touch sessions into display / session managers";
+    homepage = "https://gitlab.com/ubports/development/core/lomiri-session";
+    changelog = "https://gitlab.com/ubports/development/core/lomiri-session/-/blob/${finalAttrs.version}/ChangeLog";
+    license = licenses.gpl3Only;
+    mainProgram = "lomiri-session";
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/data/lomiri-sounds/default.nix b/nixpkgs/pkgs/desktops/lomiri/data/lomiri-sounds/default.nix
new file mode 100644
index 000000000000..1b54723b2925
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/data/lomiri-sounds/default.nix
@@ -0,0 +1,47 @@
+{ stdenvNoCC
+, lib
+, fetchFromGitLab
+, gitUpdater
+, testers
+, cmake
+}:
+
+stdenvNoCC.mkDerivation (finalAttrs: {
+  pname = "lomiri-sounds";
+  version = "22.02";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/lomiri-sounds";
+    rev = finalAttrs.version;
+    hash = "sha256-t9JYxrJ5ICslxidHmbD1wa6n7XZMf2a+PgMLcwgsDvU=";
+  };
+
+  postPatch = ''
+    # Doesn't need a compiler, only installs data
+    substituteInPlace CMakeLists.txt \
+      --replace 'project (lomiri-sounds)' 'project (lomiri-sounds LANGUAGES NONE)'
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+  ];
+
+  passthru = {
+    tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "Notification and ringtone sound effects for Lomiri";
+    homepage = "https://gitlab.com/ubports/development/core/lomiri-sounds";
+    license = with licenses; [ cc-by-30 cc0 cc-by-sa-30 cc-by-40 ];
+    maintainers = teams.lomiri.members;
+    platforms = platforms.all;
+    pkgConfigModules = [
+      "lomiri-sounds"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/data/lomiri-wallpapers/default.nix b/nixpkgs/pkgs/desktops/lomiri/data/lomiri-wallpapers/default.nix
new file mode 100644
index 000000000000..9cdb7887ee88
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/data/lomiri-wallpapers/default.nix
@@ -0,0 +1,48 @@
+{ stdenvNoCC
+, lib
+, fetchFromGitLab
+, gitUpdater
+}:
+
+stdenvNoCC.mkDerivation (finalAttrs: {
+  pname = "lomiri-wallpapers";
+  version = "20.04.0";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/lomiri-wallpapers";
+    rev = finalAttrs.version;
+    hash = "sha256-n8+vY+MPVqW6s5kSo4aEtGZv1AsjB3nNEywbmcNWfhI=";
+  };
+
+  dontConfigure = true;
+  dontBuild = true;
+
+  installPhase = ''
+    runHook preInstall
+
+    mkdir -p $out/share
+
+    # release-specific wallpapers
+    cp -r ${lib.versions.majorMinor finalAttrs.version} $out/share/wallpapers
+    rm $out/share/wallpapers/.placeholder
+
+    # eternal hardwired fallback/default
+    install -Dm644 {.,$out/share/wallpapers}/warty-final-ubuntu.png
+    ln -s warty-final-ubuntu.png $out/share/wallpapers/lomiri-default-background.png
+
+    runHook postInstall
+  '';
+
+  passthru.updateScript = gitUpdater { };
+
+  meta = with lib; {
+    description = "Wallpapers for the Lomiri Operating Environment, gathered from people of the Ubuntu Touch / UBports community";
+    homepage = "https://gitlab.com/ubports/development/core/lomiri-wallpapers";
+    changelog = "https://gitlab.com/ubports/development/core/lomiri-wallpapers/-/blob/${finalAttrs.version}/ChangeLog";
+    # On update, recheck debian/copyright for which licenses apply to the installed images
+    license = with licenses; [ cc-by-sa-30 ];
+    maintainers = teams.lomiri.members;
+    platforms = platforms.all;
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/data/suru-icon-theme/default.nix b/nixpkgs/pkgs/desktops/lomiri/data/suru-icon-theme/default.nix
new file mode 100644
index 000000000000..32b2cef1f021
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/data/suru-icon-theme/default.nix
@@ -0,0 +1,58 @@
+{ stdenvNoCC
+, lib
+, fetchFromGitLab
+, gitUpdater
+, gtk3
+, hicolor-icon-theme
+, ubuntu-themes
+}:
+
+stdenvNoCC.mkDerivation (finalAttrs: {
+  pname = "suru-icon-theme";
+  version = "2024.02.1";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/suru-icon-theme";
+    rev = finalAttrs.version;
+    hash = "sha256-7T9FILhZrs5bbdBEV/FszCOwUd/C1Rl9tbDt77SIzRk=";
+  };
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    gtk3 # gtk-update-icon-cache
+    hicolor-icon-theme # theme setup hook
+  ];
+
+  propagatedBuildInputs = [
+    ubuntu-themes
+  ];
+
+  dontConfigure = true;
+  dontBuild = true;
+
+  installPhase = ''
+    runHook preInstall
+
+    mkdir -p $out/share/icons
+    cp -r suru $out/share/icons/
+
+    gtk-update-icon-cache $out/share/icons/suru
+
+    runHook postInstall
+  '';
+
+  dontDropIconThemeCache = true;
+
+  passthru.updateScript = gitUpdater { };
+
+  meta = with lib; {
+    description = "Suru Icon Theme for Lomiri Operating Environment";
+    homepage = "https://gitlab.com/ubports/development/core/suru-icon-theme";
+    changelog = "https://gitlab.com/ubports/development/core/suru-icon-theme/-/blob/${finalAttrs.version}/ChangeLog";
+    license = licenses.cc-by-sa-30;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.all;
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/default.nix b/nixpkgs/pkgs/desktops/lomiri/default.nix
new file mode 100644
index 000000000000..76e0351e5a07
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/default.nix
@@ -0,0 +1,59 @@
+{ lib
+, pkgs
+, libsForQt5
+}:
+
+let
+  packages = self: let
+    inherit (self) callPackage;
+  in {
+    #### Core Apps
+    lomiri = callPackage ./applications/lomiri { };
+    lomiri-system-settings-unwrapped = callPackage ./applications/lomiri-system-settings { };
+    lomiri-system-settings-security-privacy = callPackage ./applications/lomiri-system-settings/plugins/lomiri-system-settings-security-privacy.nix { };
+    lomiri-system-settings = callPackage ./applications/lomiri-system-settings/wrapper.nix { };
+    lomiri-terminal-app = callPackage ./applications/lomiri-terminal-app { };
+    morph-browser = callPackage ./applications/morph-browser { };
+
+    #### Data
+    lomiri-schemas = callPackage ./data/lomiri-schemas { };
+    lomiri-session = callPackage ./data/lomiri-session { };
+    lomiri-sounds = callPackage ./data/lomiri-sounds { };
+    lomiri-wallpapers = callPackage ./data/lomiri-wallpapers { };
+    suru-icon-theme = callPackage ./data/suru-icon-theme { };
+
+    #### Development tools / libraries
+    cmake-extras = callPackage ./development/cmake-extras { };
+    deviceinfo = callPackage ./development/deviceinfo { };
+    geonames = callPackage ./development/geonames { };
+    gmenuharness = callPackage ./development/gmenuharness { };
+    libusermetrics = callPackage ./development/libusermetrics { };
+    lomiri-api = callPackage ./development/lomiri-api { };
+    lomiri-app-launch = callPackage ./development/lomiri-app-launch { };
+    qtmir = callPackage ./development/qtmir { };
+    trust-store = callPackage ./development/trust-store { };
+    u1db-qt = callPackage ./development/u1db-qt { };
+
+    #### QML / QML-related
+    lomiri-action-api = callPackage ./qml/lomiri-action-api { };
+    lomiri-notifications = callPackage ./qml/lomiri-notifications { };
+    lomiri-push-qml = callPackage ./qml/lomiri-push-qml { };
+    lomiri-settings-components = callPackage ./qml/lomiri-settings-components { };
+    lomiri-ui-extras = callPackage ./qml/lomiri-ui-extras { };
+    lomiri-ui-toolkit = callPackage ./qml/lomiri-ui-toolkit { };
+    qqc2-suru-style = callPackage ./qml/qqc2-suru-style { };
+
+    #### Services
+    biometryd = callPackage ./services/biometryd { };
+    content-hub = callPackage ./services/content-hub { };
+    hfd-service = callPackage ./services/hfd-service { };
+    history-service = callPackage ./services/history-service { };
+    lomiri-download-manager = callPackage ./services/lomiri-download-manager { };
+    lomiri-indicator-network = callPackage ./services/lomiri-indicator-network { };
+    lomiri-thumbnailer = callPackage ./services/lomiri-thumbnailer { };
+    lomiri-url-dispatcher = callPackage ./services/lomiri-url-dispatcher { };
+    mediascanner2 = callPackage ./services/mediascanner2 { };
+    telephony-service = callPackage ./services/telephony-service { };
+  };
+in
+  lib.makeScope libsForQt5.newScope packages
diff --git a/nixpkgs/pkgs/desktops/lomiri/development/cmake-extras/default.nix b/nixpkgs/pkgs/desktops/lomiri/development/cmake-extras/default.nix
new file mode 100644
index 000000000000..fcad286f4daf
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/development/cmake-extras/default.nix
@@ -0,0 +1,49 @@
+{ stdenvNoCC
+, lib
+, fetchFromGitLab
+, cmake
+, qtbase
+}:
+
+stdenvNoCC.mkDerivation (finalAttrs: {
+  pname = "cmake-extras";
+  version = "1.7";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/cmake-extras";
+    rev = finalAttrs.version;
+    hash = "sha256-5bLMk21pSZkuU3jAGTnjPc9ZrvVZqMUWSfFgkTtkYLw=";
+  };
+
+  postPatch = ''
+    # We have nothing to build here, no need to depend on a C compiler
+    substituteInPlace CMakeLists.txt \
+      --replace 'project(cmake-extras' 'project(cmake-extras LANGUAGES NONE'
+
+    # This is in a function that reverse dependencies use to determine where to install their files to
+    substituteInPlace src/QmlPlugins/QmlPluginsConfig.cmake \
+      --replace "\''${CMAKE_INSTALL_LIBDIR}/qt5/qml" "\''${CMAKE_INSTALL_PREFIX}/${qtbase.qtQmlPrefix}"
+  '';
+
+  strictDeps = true;
+
+  # Produces no binaries
+  dontWrapQtApps = true;
+
+  nativeBuildInputs = [
+    cmake
+  ];
+
+  buildInputs = [
+    qtbase
+  ];
+
+  meta = with lib; {
+    description = "A collection of add-ons for the CMake build tool";
+    homepage = "https://gitlab.com/ubports/development/core/cmake-extras/";
+    license = licenses.gpl3Only;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.all;
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/development/deviceinfo/default.nix b/nixpkgs/pkgs/desktops/lomiri/development/deviceinfo/default.nix
new file mode 100644
index 000000000000..6b05a4adddcf
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/development/deviceinfo/default.nix
@@ -0,0 +1,75 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, gitUpdater
+, testers
+, cmake
+, pkg-config
+, cmake-extras
+, gtest
+, yaml-cpp
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "deviceinfo";
+  version = "0.2.2";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/deviceinfo";
+    rev = finalAttrs.version;
+    hash = "sha256-wTl+GgNiWzJxGLdU2iMH94UhQ40gjAPTVErouQIGXOA=";
+  };
+
+  outputs = [
+    "out"
+    "dev"
+    "bin"
+  ];
+
+  postPatch = ''
+    # For our automatic pkg-config output patcher to work, prefix must be used here
+    substituteInPlace headers/deviceinfo.pc.in \
+      --replace-fail 'libdir=''${exec_prefix}' 'libdir=''${prefix}'
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    pkg-config
+  ];
+
+  buildInputs = [
+    cmake-extras
+    yaml-cpp
+  ];
+
+  checkInputs = [
+    gtest
+  ];
+
+  cmakeFlags = [
+    "-DDISABLE_TESTS=${lib.boolToString (!finalAttrs.finalPackage.doCheck)}"
+  ];
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  passthru = {
+    tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "Library to detect and configure devices";
+    homepage = "https://gitlab.com/ubports/development/core/deviceinfo";
+    changelog = "https://gitlab.com/ubports/development/core/deviceinfo/-/blob/${finalAttrs.version}/ChangeLog";
+    license = licenses.gpl3Only;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+    mainProgram = "device-info";
+    pkgConfigModules = [
+      "deviceinfo"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/development/geonames/default.nix b/nixpkgs/pkgs/desktops/lomiri/development/geonames/default.nix
new file mode 100644
index 000000000000..ce77bca6bc41
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/development/geonames/default.nix
@@ -0,0 +1,115 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, gitUpdater
+, testers
+, buildPackages
+, cmake
+, docbook-xsl-nons
+, docbook_xml_dtd_45
+, gettext
+, glib
+, glibcLocales
+, withExamples ? true
+, gtk3
+# Uses gtkdoc-scan* tools, which produces a binary linked against lib for hostPlatform and executes it to generate docs
+, withDocumentation ? stdenv.buildPlatform.canExecute stdenv.hostPlatform
+, gtk-doc
+, pkg-config
+, validatePkgConfig
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "geonames";
+  version = "0.3.1";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/geonames";
+    rev = finalAttrs.version;
+    hash = "sha256-AhRnUoku17kVY0UciHQXFDa6eCH6HQ4ZGIOobCaGTKQ=";
+  };
+
+  outputs = [
+    "out"
+    "dev"
+  ] ++ lib.optionals withExamples [
+    "bin"
+  ] ++ lib.optionals withDocumentation [
+    "devdoc"
+  ];
+
+  postPatch = ''
+    patchShebangs src/generate-locales.sh tests/setup-test-env.sh
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    gettext
+    glib # glib-compile-resources
+    pkg-config
+    validatePkgConfig
+  ] ++ lib.optionals withDocumentation [
+    docbook-xsl-nons
+    docbook_xml_dtd_45
+    gtk-doc
+  ];
+
+  buildInputs = [
+    glib
+  ] ++ lib.optionals withExamples [
+    gtk3
+  ];
+
+  # Tests need to be able to check locale
+  LC_ALL = lib.optionalString finalAttrs.finalPackage.doCheck "en_US.UTF-8";
+  nativeCheckInputs = [
+    glibcLocales
+  ];
+
+  makeFlags = [
+    # gtkdoc-scan runs ld, can't find qsort & strncpy symbols
+    "LD=${stdenv.cc.targetPrefix}cc"
+  ];
+
+  cmakeFlags = [
+    (lib.cmakeBool "WANT_DOC" withDocumentation)
+    (lib.cmakeBool "WANT_DEMO" withExamples)
+    (lib.cmakeBool "WANT_TESTS" finalAttrs.finalPackage.doCheck)
+    # Keeps finding & using glib-compile-resources from buildInputs otherwise
+    (lib.cmakeFeature "CMAKE_PROGRAM_PATH" (lib.makeBinPath [ buildPackages.glib.dev ]))
+  ] ++ lib.optionals (!stdenv.buildPlatform.canExecute stdenv.hostPlatform) [
+    # only for cross without native execute support because the canExecute "emulator" call has a format that I can't get CMake to accept
+    (lib.cmakeFeature "CMAKE_CROSSCOMPILING_EMULATOR" (stdenv.hostPlatform.emulator buildPackages))
+  ];
+
+  preInstall = lib.optionalString withDocumentation ''
+    # gtkdoc-mkhtml generates images without write permissions, errors out during install
+    chmod +w doc/reference/html/*
+  '';
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  passthru = {
+    tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "Parse and query the geonames database dump";
+    mainProgram = "geonames-demo";
+    homepage = "https://gitlab.com/ubports/development/core/geonames";
+    changelog = "https://gitlab.com/ubports/development/core/geonames/-/blob/${finalAttrs.version}/ChangeLog";
+    license = licenses.gpl3Only;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.all;
+    # Cross requires hostPlatform emulation during build
+    # https://gitlab.com/ubports/development/core/geonames/-/issues/1
+    broken = stdenv.buildPlatform != stdenv.hostPlatform && !stdenv.hostPlatform.emulatorAvailable buildPackages;
+    pkgConfigModules = [
+      "geonames"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/development/gmenuharness/default.nix b/nixpkgs/pkgs/desktops/lomiri/development/gmenuharness/default.nix
new file mode 100644
index 000000000000..101b6e216777
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/development/gmenuharness/default.nix
@@ -0,0 +1,96 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, fetchpatch
+, gitUpdater
+, testers
+, cmake
+, cmake-extras
+, dbus
+, dbus-test-runner
+, glib
+, gtest
+, libqtdbustest
+, lomiri-api
+, pkg-config
+, qtbase
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "gmenuharness";
+  version = "0.1.4";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/gmenuharness";
+    rev = finalAttrs.version;
+    hash = "sha256-MswB8cQvz3JvcJL2zj7szUOBzKRjxzJO7/x+87m7E7c=";
+  };
+
+  patches = [
+    # Remove when version > 0.1.4
+    (fetchpatch {
+      name = "0001-gmenuharness-Rename-type-attribute-from-x-canonical-type-to-x-lomiri-type.patch";
+      url = "https://gitlab.com/ubports/development/core/gmenuharness/-/commit/70e9ed85792a6ac1950faaf26391ce91e69486ab.patch";
+      hash = "sha256-jeue0qrl2JZCt/Yfj4jT210wsF/E+MlbtNT/yFTcw5I=";
+    })
+  ];
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    pkg-config
+  ];
+
+  buildInputs = [
+    cmake-extras
+    glib
+    lomiri-api
+    qtbase
+  ];
+
+  nativeCheckInputs = [
+    dbus
+    dbus-test-runner
+  ];
+
+  checkInputs = [
+    gtest
+    libqtdbustest
+  ];
+
+  cmakeFlags = [
+    "-Denable_tests=${lib.boolToString finalAttrs.finalPackage.doCheck}"
+  ];
+
+  dontWrapQtApps = true;
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  enableParallelChecking = false;
+
+  checkPhase = ''
+    runHook preCheck
+
+    dbus-test-runner -t make -p test -p "''${enableParallelChecking:+-j $NIX_BUILD_CORES}"
+
+    runHook postCheck
+  '';
+
+  passthru = {
+    tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "Library to test GMenuModel structures";
+    homepage = "https://gitlab.com/ubports/development/core/gmenuharness";
+    license = licenses.gpl3Only;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.unix;
+    pkgConfigModules = [
+      "libgmenuharness"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/development/libusermetrics/2001-Remove-custom-check-target.patch b/nixpkgs/pkgs/desktops/lomiri/development/libusermetrics/2001-Remove-custom-check-target.patch
new file mode 100644
index 000000000000..dfa90b18ca09
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/development/libusermetrics/2001-Remove-custom-check-target.patch
@@ -0,0 +1,37 @@
+From 52ac1d6548b4a92d569c5d2f53b84c604c7fce8a Mon Sep 17 00:00:00 2001
+From: OPNA2608 <opna2608@protonmail.com>
+Date: Thu, 1 Feb 2024 22:42:39 +0100
+Subject: [PATCH] Remove custom check target
+
+The automatic one provides better controls for us
+---
+ CMakeLists.txt | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index af643a7..75b3cc1 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -105,18 +105,13 @@ add_subdirectory("data")
+ 
+ 
+ if(ENABLE_TESTS)
+-enable_testing()
++include(CTest)
+ 
+ pkg_check_modules(QTDBUSTEST REQUIRED libqtdbustest-1 REQUIRED)
+ include_directories(${QTDBUSTEST_INCLUDE_DIRS})
+ 
+ add_subdirectory(tests)
+ 
+-ADD_CUSTOM_TARGET(
+-	check
+-	${CMAKE_CTEST_COMMAND} --force-new-ctest-process --output-on-failure
+-)
+-
+ find_package(CoverageReport)
+ enable_coverage_report(
+   TARGETS
+-- 
+2.42.0
+
diff --git a/nixpkgs/pkgs/desktops/lomiri/development/libusermetrics/2002-Launch-module-created-systemd-service.patch b/nixpkgs/pkgs/desktops/lomiri/development/libusermetrics/2002-Launch-module-created-systemd-service.patch
new file mode 100644
index 000000000000..82961cd4ba79
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/development/libusermetrics/2002-Launch-module-created-systemd-service.patch
@@ -0,0 +1,21 @@
+From cf8ba54d22f5ac839004c0d984fb402bde82b527 Mon Sep 17 00:00:00 2001
+From: OPNA2608 <opna2608@protonmail.com>
+Date: Mon, 8 Apr 2024 15:22:55 +0200
+Subject: [PATCH] Launch module-created systemd service
+
+---
+ data/com.lomiri.UserMetrics.service.in | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/data/com.lomiri.UserMetrics.service.in b/data/com.lomiri.UserMetrics.service.in
+index c2e6ae1..212e24f 100644
+--- a/data/com.lomiri.UserMetrics.service.in
++++ b/data/com.lomiri.UserMetrics.service.in
+@@ -3,3 +3,4 @@ Name=com.lomiri.UserMetrics
+ Exec=@CMAKE_INSTALL_FULL_LIBEXECDIR@/libusermetrics/usermetricsservice
+ User=usermetrics
+ StandardOutput=syslog
++SystemdService=dbus-com.lomiri.UserMetrics.service
+-- 
+2.42.0
+
diff --git a/nixpkgs/pkgs/desktops/lomiri/development/libusermetrics/default.nix b/nixpkgs/pkgs/desktops/lomiri/development/libusermetrics/default.nix
new file mode 100644
index 000000000000..351900af7f13
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/development/libusermetrics/default.nix
@@ -0,0 +1,134 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, gitUpdater
+, testers
+, cmake
+, cmake-extras
+, dbus
+, doxygen
+, gsettings-qt
+, gtest
+, intltool
+, json-glib
+, libapparmor
+, libqtdbustest
+, pkg-config
+, qdjango
+, qtbase
+, qtdeclarative
+, qtxmlpatterns
+, ubports-click
+, validatePkgConfig
+, wrapQtAppsHook
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "libusermetrics";
+  version = "1.3.2";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/libusermetrics";
+    rev = finalAttrs.version;
+    hash = "sha256-jmJH5vByBnBqgQfyb7HNVe+eS/jHcU64R2dnvuLbqss=";
+  };
+
+  outputs = [
+    "out"
+    "dev"
+    "doc"
+  ];
+
+  patches = [
+    # Not submitted yet, waiting for decision on how CMake testing should be handled
+    ./2001-Remove-custom-check-target.patch
+
+    # Due to https://gitlab.com/ubports/development/core/libusermetrics/-/issues/8, we require knowledge about AppArmor availability at launch time
+    # Custom patch to launch a module-defined service that can handle this
+    ./2002-Launch-module-created-systemd-service.patch
+  ];
+
+  postPatch = ''
+    # Tries to query QMake for QT_INSTALL_QML variable, would return broken paths into /build/qtbase-<commit> even if qmake was available
+    substituteInPlace src/modules/UserMetrics/CMakeLists.txt \
+      --replace 'query_qmake(QT_INSTALL_QML QT_IMPORTS_DIR)' 'set(QT_IMPORTS_DIR "''${CMAKE_INSTALL_PREFIX}/${qtbase.qtQmlPrefix}")'
+
+    substituteInPlace doc/CMakeLists.txt \
+      --replace "\''${CMAKE_INSTALL_DATAROOTDIR}/doc/libusermetrics-doc" "\''${CMAKE_INSTALL_DOCDIR}"
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    doxygen
+    intltool
+    pkg-config
+    validatePkgConfig
+    wrapQtAppsHook
+  ];
+
+  buildInputs = [
+    cmake-extras
+    gsettings-qt
+    json-glib
+    libapparmor
+    qdjango
+    qtxmlpatterns
+    ubports-click
+
+    # Plugin
+    qtbase
+  ];
+
+  nativeCheckInputs = [
+    dbus
+  ];
+
+  checkInputs = [
+    gtest
+    libqtdbustest
+    qtdeclarative
+  ];
+
+  cmakeFlags = [
+    (lib.cmakeBool "GSETTINGS_LOCALINSTALL" true)
+    (lib.cmakeBool "GSETTINGS_COMPILE" true)
+    (lib.cmakeBool "ENABLE_CLICK" true)
+    (lib.cmakeBool "ENABLE_TESTS" finalAttrs.finalPackage.doCheck)
+    (lib.cmakeFeature "CMAKE_CTEST_ARGUMENTS" (lib.concatStringsSep ";" [
+      # Exclude tests
+      "-E" (lib.strings.escapeShellArg "(${lib.concatStringsSep "|" [
+        # Flaky, randomly failing in UserMetricsImplTest.AddTranslatedData (data not ready when signal is emitted?)
+        "^usermetricsoutput-unit-tests"
+      ]})")
+    ]))
+  ];
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  preCheck = ''
+    export QT_PLUGIN_PATH=${lib.getBin qtbase}/lib/qt-${qtbase.version}/plugins/
+    export QML2_IMPORT_PATH=${lib.getBin qtdeclarative}/lib/qt-${qtbase.version}/qml/
+  '';
+
+  passthru = {
+    tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "Enables apps to locally store interesting numerical data for later presentation";
+    homepage = "https://gitlab.com/ubports/development/core/libusermetrics";
+    changelog = "https://gitlab.com/ubports/development/core/libusermetrics/-/blob/${finalAttrs.version}/ChangeLog";
+    license = licenses.lgpl3Only;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+    mainProgram = "usermetricsinput";
+    pkgConfigModules = [
+      "libusermetricsinput-1"
+      "libusermetricsoutput-1"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/development/lomiri-api/default.nix b/nixpkgs/pkgs/desktops/lomiri/development/lomiri-api/default.nix
new file mode 100644
index 000000000000..9f699bbd715a
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/development/lomiri-api/default.nix
@@ -0,0 +1,115 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, fetchpatch
+, gitUpdater
+, makeFontsConf
+, testers
+, cmake
+, cmake-extras
+, dbus
+, doxygen
+, glib
+, graphviz
+, gtest
+, libqtdbustest
+, pkg-config
+, python3
+, qtbase
+, qtdeclarative
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "lomiri-api";
+  version = "0.2.1";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/lomiri-api";
+    rev = finalAttrs.version;
+    hash = "sha256-UTl0vObSlEvHuLmDt7vS3yEqZWGklJ9tVwlUAtRSTlU=";
+  };
+
+  outputs = [ "out" "dev" "doc" ];
+
+  patches = [
+    (fetchpatch {
+      name = "0001-lomiri-api-Add-missing-headers-for-GCC13.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-api/-/commit/029b42a9b4d5467951595dff8bc536eb5a9e3ef7.patch";
+      hash = "sha256-eWrDQGrwf22X49rtUAVbrd+QN+OwyGacVLCWYFsS02o=";
+    })
+  ];
+
+  postPatch = ''
+    patchShebangs $(find test -name '*.py')
+
+    substituteInPlace data/*.pc.in \
+      --replace "\''${prefix}/@CMAKE_INSTALL_LIBDIR@" "\''${prefix}/lib"
+
+    # Variable is queried via pkg-config by reverse dependencies
+    # TODO This is likely not supposed to be the regular Qt QML import prefix
+    # but otherwise i.e. lomiri-notifications cannot be found in lomiri
+    substituteInPlace CMakeLists.txt \
+      --replace 'SHELL_PLUGINDIR ''${CMAKE_INSTALL_LIBDIR}/lomiri/qml' 'SHELL_PLUGINDIR ${qtbase.qtQmlPrefix}'
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    doxygen
+    graphviz
+    pkg-config
+  ];
+
+  buildInputs = [
+    cmake-extras
+    glib
+    gtest
+    libqtdbustest
+    qtbase
+    qtdeclarative
+  ];
+
+  nativeCheckInputs = [
+    dbus
+    python3
+  ];
+
+  dontWrapQtApps = true;
+
+  FONTCONFIG_FILE = makeFontsConf { fontDirectories = [ ]; };
+
+  preBuild = ''
+    # Makes fontconfig produce less noise in logs
+    export HOME=$TMPDIR
+  '';
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  preCheck = ''
+    # needs minimal plugin and QtTest QML
+    export QT_PLUGIN_PATH=${lib.getBin qtbase}/${qtbase.qtPluginPrefix}
+    export QML2_IMPORT_PATH=${lib.getBin qtdeclarative}/${qtbase.qtQmlPrefix}
+  '';
+
+  passthru = {
+    tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "Lomiri API Library for integrating with the Lomiri shell";
+    homepage = "https://gitlab.com/ubports/development/core/lomiri-api";
+    license = with licenses; [ lgpl3Only gpl3Only ];
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+    pkgConfigModules = [
+      "liblomiri-api"
+      "lomiri-shell-api"
+      "lomiri-shell-application"
+      "lomiri-shell-launcher"
+      "lomiri-shell-notifications"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/development/lomiri-app-launch/default.nix b/nixpkgs/pkgs/desktops/lomiri/development/lomiri-app-launch/default.nix
new file mode 100644
index 000000000000..381a89fe10ff
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/development/lomiri-app-launch/default.nix
@@ -0,0 +1,150 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, fetchpatch
+, gitUpdater
+, testers
+, cmake
+, cmake-extras
+, curl
+, dbus
+, dbus-test-runner
+, dpkg
+, gobject-introspection
+, gtest
+, json-glib
+, libxkbcommon
+, lomiri-api
+, lttng-ust
+, pkg-config
+, properties-cpp
+, python3
+, systemd
+, ubports-click
+, validatePkgConfig
+, zeitgeist
+, withDocumentation ? true
+, doxygen
+, python3Packages
+, sphinx
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "lomiri-app-launch";
+  version = "0.1.9";
+
+  outputs = [
+    "out"
+    "dev"
+  ] ++ lib.optionals withDocumentation [
+    "doc"
+  ];
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/lomiri-app-launch";
+    rev = finalAttrs.version;
+    hash = "sha256-vuu6tZ5eDJN2rraOpmrDddSl1cIFFBSrILKMJqcUDVc=";
+  };
+
+  patches = [
+    # Remove when https://gitlab.com/ubports/development/core/lomiri-app-launch/-/merge_requests/57 merged & in release
+    (fetchpatch {
+      name = "0001-lomiri-app-launch-Fix-typelib-gir-dependency.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-app-launch/-/commit/0419b2592284f43ee5e76060948ea3d5f1c991fd.patch";
+      hash = "sha256-11pEhFi39Cvqb9Hg47kT8+5hq+bz6WmySqaIdwt1MVk=";
+    })
+  ];
+
+  postPatch = ''
+    patchShebangs tests/{desktop-hook-test.sh.in,repeat-until-pass.sh}
+
+    # used pkg_get_variable, cannot replace prefix
+    substituteInPlace data/CMakeLists.txt \
+      --replace 'pkg_get_variable(SYSTEMD_USER_UNIT_DIR systemd systemduserunitdir)' 'set(SYSTEMD_USER_UNIT_DIR "''${CMAKE_INSTALL_PREFIX}/lib/systemd/user")'
+
+    substituteInPlace tests/jobs-systemd.cpp \
+      --replace '^(/usr)?' '^(/nix/store/\\w+-bash-.+)?'
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    dpkg # for setting LOMIRI_APP_LAUNCH_ARCH
+    gobject-introspection
+    pkg-config
+    validatePkgConfig
+  ] ++ lib.optionals withDocumentation [
+    doxygen
+    python3Packages.breathe
+    sphinx
+  ];
+
+  buildInputs = [
+    cmake-extras
+    curl
+    dbus
+    json-glib
+    libxkbcommon
+    lomiri-api
+    lttng-ust
+    properties-cpp
+    systemd
+    ubports-click
+    zeitgeist
+  ];
+
+  nativeCheckInputs = [
+    dbus
+    (python3.withPackages (ps: with ps; [
+      python-dbusmock
+    ]))
+  ];
+
+  checkInputs = [
+    dbus-test-runner
+    gtest
+  ];
+
+  cmakeFlags = [
+    (lib.cmakeBool "ENABLE_MIRCLIENT" false)
+    (lib.cmakeBool "ENABLE_TESTS" finalAttrs.finalPackage.doCheck)
+    (lib.cmakeFeature "CMAKE_CTEST_ARGUMENTS" (lib.concatStringsSep ";" [
+      # Exclude tests
+      "-E" (lib.strings.escapeShellArg "(${lib.concatStringsSep "|" [
+        # Flaky, randomly hangs
+        # https://gitlab.com/ubports/development/core/lomiri-app-launch/-/issues/19
+        "^helper-handshake-test"
+      ]})")
+    ]))
+  ];
+
+  postBuild = lib.optionalString withDocumentation ''
+    make -C ../docs html
+  '';
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  postInstall = lib.optionalString withDocumentation ''
+    mkdir -p $doc/share/doc/lomiri-app-launch
+    mv ../docs/_build/html $doc/share/doc/lomiri-app-launch/
+  '';
+
+  passthru = {
+    tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "System and associated utilities to launch applications in a standard and confined way";
+    homepage = "https://gitlab.com/ubports/development/core/lomiri-app-launch";
+    changelog = "https://gitlab.com/ubports/development/core/lomiri-app-launch/-/blob/${finalAttrs.version}/ChangeLog";
+    license = licenses.gpl3Only;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+    pkgConfigModules = [
+      "lomiri-app-launch-0"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/development/qtmir/default.nix b/nixpkgs/pkgs/desktops/lomiri/development/qtmir/default.nix
new file mode 100644
index 000000000000..ba49507f3d36
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/development/qtmir/default.nix
@@ -0,0 +1,160 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, fetchpatch
+, testers
+, cmake
+, cmake-extras
+, pkg-config
+, wrapQtAppsHook
+, gsettings-qt
+, gtest
+, libqtdbustest
+, libqtdbusmock
+, libuuid
+, lomiri-api
+, lomiri-app-launch
+, lomiri-url-dispatcher
+, lttng-ust
+, mir
+, process-cpp
+, qtbase
+, qtdeclarative
+, qtsensors
+, valgrind
+, protobuf
+, glm
+, boost
+, properties-cpp
+, glib
+, validatePkgConfig
+, wayland
+, xwayland
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  # Not regular qtmir, experimental support for Mir 2.x
+  # Currently following https://gitlab.com/ubports/development/core/qtmir/-/tree/personal/mariogrip/desktop-development
+  pname = "qtmir-mir2";
+  version = "0.7.2-unstable-2024-01-08";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/qtmir";
+    rev = "ae0d87415d5c9ed2c4fd2284ba0807d23d564bb0";
+    hash = "sha256-fE8ttCC0FNavs91pASGGG7k7nKVg2lD3JK0WTmCA3gM=";
+  };
+
+  outputs = [
+    "out"
+    "dev"
+  ];
+
+  patches = [
+    # Mir 2.15 compatibility patch
+    # Remove when https://gitlab.com/ubports/development/core/qtmir/-/merge_requests/70 merged into branch
+    (fetchpatch {
+      name = "0001-qtmir-Update-for-Mir-2.15-removals.patch";
+      url = "https://gitlab.com/ubports/development/core/qtmir/-/commit/ead5cacd4d69094ab956627f4dd94ecaff1fd69e.patch";
+      hash = "sha256-hUUUnYwhNH3gm76J21M8gA5okaRd/Go03ZFJ4qn0JUo=";
+    })
+
+    # Remove when https://gitlab.com/ubports/development/core/qtmir/-/merge_requests/72 merged in branch
+    (fetchpatch {
+      name = "0002-qtmir-Add-more-better-GNUInstallDirs-variables-usage.patch";
+      url = "https://gitlab.com/ubports/development/core/qtmir/-/commit/87e2cd31052ce15e9625c1327807a320ee5d12af.patch";
+      hash = "sha256-MTE9tHw+xJhraEO1up7dLg0UIcmfHXgWOeuyYrVu2wc=";
+    })
+
+    # Remove when https://gitlab.com/ubports/development/core/qtmir/-/merge_requests/73 merged in branch
+    (fetchpatch {
+      name = "0003-qtmir-CMakeLists-Only-require-test-dependencies-when-building-tests.patch";
+      url = "https://gitlab.com/ubports/development/core/qtmir/-/commit/b7144e67bcbb4cfbd2283d5d05146fb22b7d8cd4.patch";
+      hash = "sha256-Afbj40MopztchDnk6fphTYk86YrQkiK8L1e/oXiL1Mw=";
+    })
+
+    # Remove when https://gitlab.com/ubports/development/core/qtmir/-/merge_requests/74 merged in branch
+    (fetchpatch {
+      name = "0004-qtmir-CMakeLists-Drop-call-of-Qt-internal-macro.patch";
+      url = "https://gitlab.com/ubports/development/core/qtmir/-/commit/8f9c599a4dbc4cf35e289157fd0c82df55b9f8d9.patch";
+      hash = "sha256-SMAErXnlMtVleWRPgO4xuUI7gAAy6W18LxtgXgetRA4=";
+    })
+  ];
+
+  postPatch = ''
+    substituteInPlace CMakeLists.txt \
+      --replace "\''${CMAKE_INSTALL_FULL_LIBDIR}/qt5/qml" "\''${CMAKE_INSTALL_PREFIX}/${qtbase.qtQmlPrefix}" \
+      --replace "\''${CMAKE_INSTALL_FULL_LIBDIR}/qt5/plugins/platforms" "\''${CMAKE_INSTALL_PREFIX}/${qtbase.qtPluginPrefix}/platforms" \
+
+    substituteInPlace data/xwayland.qtmir.desktop \
+      --replace '/usr/bin/Xwayland' 'Xwayland'
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    glib # glib-compile-schemas
+    pkg-config
+    validatePkgConfig
+    wrapQtAppsHook
+  ];
+
+  buildInputs = [
+    cmake-extras
+    boost
+    gsettings-qt
+    libuuid
+    lomiri-api
+    lomiri-app-launch
+    lomiri-url-dispatcher
+    lttng-ust
+    mir
+    process-cpp
+    protobuf
+    qtbase
+    qtdeclarative
+    qtsensors
+    valgrind
+
+    glm # included by mir header
+    wayland # mirwayland asks for this
+    properties-cpp # included by l-a-l header
+  ];
+
+  propagatedBuildInputs = [
+    # Needs Xwayland on PATH for desktop file, else launching X11 applications crashes qtmir
+    xwayland
+  ];
+
+  checkInputs = [
+    gtest
+    libqtdbustest
+    libqtdbusmock
+  ];
+
+  cmakeFlags = [
+    (lib.cmakeBool "NO_TESTS" (!finalAttrs.finalPackage.doCheck))
+    (lib.cmakeBool "WITH_MIR2" true)
+  ];
+
+  postInstall = ''
+    glib-compile-schemas $out/share/glib-2.0/schemas
+  '';
+
+  # Tests currently unavailable when building with Mir2
+  doCheck = false;
+
+  passthru.tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+
+  meta = with lib; {
+    description = "QPA plugin to make Qt a Mir server";
+    homepage = "https://gitlab.com/ubports/development/core/qtmir";
+    license = licenses.lgpl3Only;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+    pkgConfigModules = [
+      "qtmirserver"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/development/trust-store/default.nix b/nixpkgs/pkgs/desktops/lomiri/development/trust-store/default.nix
new file mode 100644
index 000000000000..fbbd8cf4ac6f
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/development/trust-store/default.nix
@@ -0,0 +1,129 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, gitUpdater
+, testers
+, boost
+, cmake
+, cmake-extras
+, dbus
+, dbus-cpp
+, doxygen
+, gettext
+, glog
+, graphviz
+, gtest
+, libapparmor
+, newt
+, pkg-config
+, process-cpp
+, properties-cpp
+, qtbase
+, qtdeclarative
+, validatePkgConfig
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "trust-store";
+  version = "2.0.2";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/trust-store";
+    rev = finalAttrs.version;
+    hash = "sha256-tVwqBu4py8kdydyKECZfLvcLijpZSQszeo8ytTDagy0=";
+  };
+
+  outputs = [
+    "out"
+    "dev"
+    "doc"
+    "bin"
+  ];
+
+  postPatch = ''
+    # pkg-config patching hook expects prefix variable
+    substituteInPlace data/trust-store.pc.in \
+      --replace-fail 'libdir=''${exec_prefix}' 'libdir=''${prefix}' \
+      --replace-fail 'includedir=''${exec_prefix}' 'includedir=''${prefix}'
+
+    substituteInPlace src/core/trust/terminal_agent.h \
+      --replace-fail '/bin/whiptail' '${lib.getExe' newt "whiptail"}'
+  '' + lib.optionalString (!finalAttrs.doCheck) ''
+    substituteInPlace CMakeLists.txt \
+      --replace-fail 'add_subdirectory(tests)' ""
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    doxygen
+    gettext
+    graphviz
+    pkg-config
+    validatePkgConfig
+  ];
+
+  buildInputs = [
+    boost
+    cmake-extras
+    dbus-cpp
+    glog
+    libapparmor
+    newt
+    process-cpp
+    properties-cpp
+    qtbase
+    qtdeclarative
+  ];
+
+  nativeCheckInputs = [
+    dbus
+  ];
+
+  checkInputs = [
+    gtest
+  ];
+
+  dontWrapQtApps = true;
+
+  cmakeFlags = [
+    # Requires mirclient API, unavailable in Mir 2.x
+    # https://gitlab.com/ubports/development/core/trust-store/-/issues/2
+    (lib.cmakeBool "TRUST_STORE_MIR_AGENT_ENABLED" false)
+    (lib.cmakeBool "TRUST_STORE_ENABLE_DOC_GENERATION" true)
+    # error: moving a temporary object prevents copy elision
+    (lib.cmakeBool "ENABLE_WERROR" false)
+  ];
+
+  # Not working
+  # - remote_agent_test cases using unix domain socket fail to do *something*, with std::system_error "Invalid argument" + follow-up "No such file or directory".
+  #   potentially something broken/missing on our end
+  # - dbus_test hangs indefinitely waiting for a std::future, not provicient enough to debug this.
+  #   same hang on upstream CI
+  doCheck = false;
+
+  preCheck = ''
+    export XDG_DATA_HOME=$TMPDIR
+  '';
+
+  # Starts & talks to DBus
+  enableParallelChecking = false;
+
+  passthru = {
+    tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "Common implementation of a trust store to be used by trusted helpers";
+    homepage = "https://gitlab.com/ubports/development/core/trust-store";
+    license = licenses.lgpl3Only;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+    pkgConfigModules = [
+      "trust-store"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/development/u1db-qt/default.nix b/nixpkgs/pkgs/desktops/lomiri/development/u1db-qt/default.nix
new file mode 100644
index 000000000000..a141abb79d69
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/development/u1db-qt/default.nix
@@ -0,0 +1,117 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, fetchpatch
+, gitUpdater
+, testers
+, cmake
+, dbus-test-runner
+, pkg-config
+, qtbase
+, qtdeclarative
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "u1db-qt";
+  version = "0.1.7";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/u1db-qt";
+    rev = finalAttrs.version;
+    hash = "sha256-qlWkxpiVEUbpsKhzR0s7SKaEFCLM2RH+v9XmJ3qLoGY=";
+  };
+
+  outputs = [
+    "out"
+    "dev"
+    "examples"
+  ];
+
+  patches = [
+    # Fixes some issues with the pkg-config file
+    # Remove when https://gitlab.com/ubports/development/core/u1db-qt/-/merge_requests/7 merged & in release
+    (fetchpatch {
+      name = "0001-u1db-qt-Fix-pkg-config-files-includedir-variable.patch";
+      url = "https://gitlab.com/ubports/development/core/u1db-qt/-/commit/ddafbfadfad6dfc508a866835354a4701dda1fe1.patch";
+      hash = "sha256-entwjU9TiHuSuht7Cdl0k1v0cP7350a04/FXgTVhGmk=";
+    })
+  ];
+
+  postPatch = ''
+    patchShebangs tests/strict-qmltestrunner.sh
+
+    # QMake query response is broken, just hardcode the expected location
+    substituteInPlace modules/U1db/CMakeLists.txt \
+      --replace-fail 'exec_program(''${QMAKE_EXECUTABLE} ARGS "-query QT_INSTALL_QML"' 'exec_program(echo ARGS "''${CMAKE_INSTALL_PREFIX}/${qtbase.qtQmlPrefix}"'
+
+    # For our automatic pkg-config output patcher to work, prefix must be used here
+    substituteInPlace libu1db-qt.pc.in \
+      --replace-fail 'libdir=''${exec_prefix}/lib' 'libdir=''${prefix}/lib'
+  '' + lib.optionalString (!finalAttrs.doCheck) ''
+    # Other locations add dependencies to custom check target from tests
+    substituteInPlace CMakeLists.txt \
+      --replace-fail 'add_subdirectory(tests)' 'add_custom_target(check COMMAND "echo check dummy")'
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    pkg-config
+    qtdeclarative # qmlplugindump
+  ];
+
+  buildInputs = [
+    qtbase
+    qtdeclarative
+  ];
+
+  nativeCheckInputs = [
+    dbus-test-runner
+  ];
+
+  cmakeFlags = [
+    # Needs qdoc, see https://github.com/NixOS/nixpkgs/pull/245379
+    (lib.cmakeBool "BUILD_DOCS" false)
+  ];
+
+  dontWrapQtApps = true;
+
+  preBuild = ''
+    # Executes qmlplugindump
+    export QT_PLUGIN_PATH=${lib.getBin qtbase}/${qtbase.qtPluginPrefix}
+  '';
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  preCheck = ''
+    export QT_QPA_PLATFORM=minimal
+  '';
+
+  postInstall = ''
+    # Example seems unmaintained & depends on old things
+    # (unity-icon-theme, QtWebKit, Ubuntu namespace compat in LUITK)
+    # With an uneducated attempt at porting it to QtWebView, only displays blank window. Just throw it away.
+    rm -r $out/share/applications
+
+    moveToOutput share/u1db-qt/qtcreator $dev
+    moveToOutput share/u1db-qt/examples $examples
+  '';
+
+  passthru = {
+    tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "Qt5 binding and QtQuick2 plugin for U1DB";
+    homepage = "https://gitlab.com/ubports/development/core/u1db-qt";
+    license = licenses.lgpl3Only;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+    pkgConfigModules = [
+      "libu1db-qt5"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-action-api/default.nix b/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-action-api/default.nix
new file mode 100644
index 000000000000..d3d23c68f8bf
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-action-api/default.nix
@@ -0,0 +1,88 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, gitUpdater
+, testers
+, cmake
+, dbus
+, dbus-test-runner
+, pkg-config
+, qtbase
+, qtdeclarative
+, validatePkgConfig
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "lomiri-action-api";
+  version = "1.1.3";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/lomiri-action-api";
+    rev = finalAttrs.version;
+    hash = "sha256-JDcUq7qEp6Z8TjdNspIz4FE/euH+ytGWa4rSxy4voiU=";
+  };
+
+  outputs = [
+    "out"
+    "dev"
+  ];
+
+  postPatch = ''
+    # Queries QMake for broken Qt variable: '/build/qtbase-<commit>/$(out)/$(qtQmlPrefix)'
+    substituteInPlace qml/Lomiri/Action/CMakeLists.txt \
+      --replace 'exec_program(''${QMAKE_EXECUTABLE} ARGS "-query QT_INSTALL_QML" OUTPUT_VARIABLE QT_IMPORTS_DIR)' 'set(QT_IMPORTS_DIR "''${CMAKE_INSTALL_PREFIX}/${qtbase.qtQmlPrefix}")'
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    pkg-config
+    validatePkgConfig
+  ];
+
+  buildInputs = [
+    qtbase
+    qtdeclarative
+  ];
+
+  nativeCheckInputs = [
+    dbus
+    dbus-test-runner
+  ];
+
+  cmakeFlags = [
+    (lib.cmakeBool "ENABLE_TESTING" finalAttrs.finalPackage.doCheck)
+    # Use vendored libhud2, TODO package libhud2 separately?
+    (lib.cmakeBool "use_libhud2" false)
+    # QML docs need qdoc, https://github.com/NixOS/nixpkgs/pull/245379
+    (lib.cmakeBool "GENERATE_DOCUMENTATION" false)
+  ];
+
+  dontWrapQtApps = true;
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  preCheck = ''
+    export QT_PLUGIN_PATH=${lib.getBin qtbase}/${qtbase.qtPluginPrefix}
+    export QML2_IMPORT_PATH=${lib.getBin qtdeclarative}/${qtbase.qtQmlPrefix}
+  '';
+
+  passthru = {
+    tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "Allow applications to export actions in various forms to the Lomiri Shell";
+    homepage = "https://gitlab.com/ubports/development/core/lomiri-action-api";
+    changelog = "https://gitlab.com/ubports/development/core/lomiri-action-api/-/blob/${finalAttrs.version}/ChangeLog";
+    license = licenses.lgpl3Only;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+    pkgConfigModules = [
+      "lomiri-action-qt-1"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-notifications/default.nix b/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-notifications/default.nix
new file mode 100644
index 000000000000..56b86eaa3918
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-notifications/default.nix
@@ -0,0 +1,92 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, fetchpatch
+, gitUpdater
+, cmake
+, dbus
+, libqtdbustest
+, lomiri-api
+, pkg-config
+, qtbase
+, qtdeclarative
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "lomiri-notifications";
+  version = "1.3.0";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/lomiri-notifications";
+    rev = finalAttrs.version;
+    hash = "sha256-EGslfTgfADrmVGhNLG7HWqcDKhu52H/r41j7fxoliko=";
+  };
+
+  patches = [
+    # Drop use of deprecated qt5_use_modules
+    # Remove when https://gitlab.com/ubports/development/core/lomiri-notifications/-/merge_requests/11 merged & in release
+    (fetchpatch {
+      url = "https://gitlab.com/OPNA2608/lomiri-notifications/-/commit/5d164d6d8d68efe1d14154eca4d0d736ce2a1265.patch";
+      hash = "sha256-nUg0zUft1n4AlotOaZgDqWbiVDvWvMizdlClavwygoI=";
+    })
+  ];
+
+  postPatch = ''
+    substituteInPlace CMakeLists.txt \
+      --replace "\''${CMAKE_INSTALL_LIBDIR}/qt5/qml" "\''${CMAKE_INSTALL_PREFIX}/${qtbase.qtQmlPrefix}"
+
+    # Need to replace prefix to not try to install into lomiri-api prefix
+    substituteInPlace src/CMakeLists.txt \
+      --replace '--variable=plugindir' '--define-variable=prefix=''${CMAKE_INSTALL_PREFIX} --variable=plugindir'
+  '' + lib.optionalString (!finalAttrs.finalPackage.doCheck) ''
+    sed -i CMakeLists.txt -e '/add_subdirectory(test)/d'
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    pkg-config
+  ];
+
+  buildInputs = [
+    lomiri-api
+    qtbase
+    qtdeclarative
+  ];
+
+  nativeCheckInputs = [
+    dbus
+  ];
+
+  checkInputs = [
+    libqtdbustest
+  ];
+
+  dontWrapQtApps = true;
+
+  cmakeFlags = [
+    # In case anything still depends on deprecated hints
+    "-DENABLE_UBUNTU_COMPAT=ON"
+  ];
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  # Deals with DBus
+  enableParallelChecking = false;
+
+  preCheck = ''
+    export QT_PLUGIN_PATH=${lib.getBin qtbase}/${qtbase.qtPluginPrefix}
+  '';
+
+  passthru.updateScript = gitUpdater { };
+
+  meta = with lib; {
+    description = "Free Desktop Notification server QML implementation for Lomiri";
+    homepage = "https://gitlab.com/ubports/development/core/lomiri-notifications";
+    license = licenses.gpl3Only;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-push-qml/default.nix b/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-push-qml/default.nix
new file mode 100644
index 000000000000..5fba08098879
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-push-qml/default.nix
@@ -0,0 +1,74 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, fetchpatch
+, cmake
+, lomiri-api
+, lomiri-indicator-network
+, pkg-config
+, qtbase
+, qtdeclarative
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "lomiri-push-qml";
+  version = "0-unstable-2022-09-15";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/lomiri-push-qml";
+    rev = "6f87ee5cf92e2af0e0ce672835e71704e236b8c0";
+    hash = "sha256-ezLcQRJ7Sq/TVbeGJL3Vq2lzBe7StRRCrWXZs2CCUX8=";
+  };
+
+  patches = [
+    # Remove when https://gitlab.com/ubports/development/core/lomiri-push-qml/-/merge_requests/6 merged
+    (fetchpatch {
+      name = "0001-lomiri-push-qml-Stop-using-qt5_use_modules.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-push-qml/-/commit/a4268c98b9f50fdd52da69c173d377f78ea93104.patch";
+      hash = "sha256-OijTB5+I9/wabT7dX+DkvoEROKzAUIKhBZkkhqq5Oig=";
+    })
+  ];
+
+  postPatch = ''
+    # Queries QMake for QML install location, returns QtBase build path
+    substituteInPlace src/*/PushNotifications/CMakeLists.txt \
+      --replace-fail 'qmake -query QT_INSTALL_QML' 'echo ''${CMAKE_INSTALL_PREFIX}/${qtbase.qtQmlPrefix}' \
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    pkg-config
+    qtdeclarative # qmlplugindump
+  ];
+
+  buildInputs = [
+    lomiri-api
+    lomiri-indicator-network
+    qtbase
+    qtdeclarative
+  ];
+
+  dontWrapQtApps = true;
+
+  cmakeFlags = [
+    # In case anything still depends on deprecated hints
+    (lib.cmakeBool "ENABLE_UBUNTU_COMPAT" true)
+  ];
+
+  preBuild = ''
+    # For qmlplugindump
+    export QT_PLUGIN_PATH=${lib.getBin qtbase}/${qtbase.qtPluginPrefix}
+  '';
+
+  meta = with lib; {
+    description = "Lomiri Push Notifications QML plugin";
+    homepage = "https://gitlab.com/ubports/development/core/lomiri-push-qml";
+    # License file indicates gpl3Only, but de87869c2cdb9819c2ca7c9eca9c5fb8b500a01f says it should be lgpl3Only
+    license = licenses.lgpl3Only;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-settings-components/default.nix b/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-settings-components/default.nix
new file mode 100644
index 000000000000..854615512d67
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-settings-components/default.nix
@@ -0,0 +1,66 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, gitUpdater
+, cmake
+, cmake-extras
+, pkg-config
+, python3
+, qtbase
+, qtdeclarative
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "lomiri-settings-components";
+  version = "1.1.1";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/lomiri-settings-components";
+    rev = finalAttrs.version;
+    hash = "sha256-2Wyh+2AW6EeKRv26D4l+GIoH5sWC9SmOODNHOveFZPg=";
+  };
+
+  postPatch = ''
+    patchShebangs tests/imports/check_imports.py
+
+    substituteInPlace CMakeLists.txt \
+      --replace "\''${CMAKE_INSTALL_LIBDIR}/qt5/qml" '${placeholder "out"}/${qtbase.qtQmlPrefix}'
+  '' + lib.optionalString (!finalAttrs.doCheck) ''
+    sed -i CMakeLists.txt \
+      -e '/add_subdirectory(tests)/d'
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    pkg-config
+  ];
+
+  buildInputs = [
+    cmake-extras
+    qtbase
+    qtdeclarative
+  ];
+
+  nativeCheckInputs = [
+    python3
+  ];
+
+  # No apps, just QML components
+  dontWrapQtApps = true;
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  passthru.updateScript = gitUpdater { };
+
+  meta = with lib; {
+    description = "QML settings components for the Lomiri Desktop Environment";
+    homepage = "https://gitlab.com/ubports/development/core/lomiri-settings-components";
+    changelog = "https://gitlab.com/ubports/development/core/lomiri-settings-components/-/blob/${finalAttrs.version}/ChangeLog";
+    license = licenses.lgpl3Only;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-ui-extras/default.nix b/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-ui-extras/default.nix
new file mode 100644
index 000000000000..5a2097f47657
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-ui-extras/default.nix
@@ -0,0 +1,103 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, gitUpdater
+, cmake
+, cmake-extras
+, cups
+, exiv2
+, lomiri-ui-toolkit
+, pam
+, pkg-config
+, qtbase
+, qtdeclarative
+, xvfb-run
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "lomiri-ui-extras";
+  version = "0.6.3";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/lomiri-ui-extras";
+    rev = finalAttrs.version;
+    hash = "sha256-SF/UF84K9kNtLHO9FDuIFdQId0NfbmRiRZiPrOKvE9o=";
+  };
+
+  postPatch = ''
+    substituteInPlace modules/Lomiri/Components/Extras{,/{plugin,PamAuthentication}}/CMakeLists.txt \
+      --replace "\''${CMAKE_INSTALL_LIBDIR}/qt5/qml" "\''${CMAKE_INSTALL_PREFIX}/${qtbase.qtQmlPrefix}"
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    pkg-config
+  ];
+
+  buildInputs = [
+    cmake-extras
+    cups
+    exiv2
+    pam
+    qtbase
+    qtdeclarative
+  ];
+
+  nativeCheckInputs = [
+    qtdeclarative # qmltestrunner
+    xvfb-run
+  ];
+
+  checkInputs = [
+    lomiri-ui-toolkit
+  ];
+
+  dontWrapQtApps = true;
+
+  cmakeFlags = [
+    (lib.cmakeBool "ENABLE_TESTS" finalAttrs.finalPackage.doCheck)
+    (lib.cmakeFeature "CMAKE_CTEST_ARGUMENTS" (lib.concatStringsSep ";" [
+      # Exclude tests
+      "-E" (lib.strings.escapeShellArg "(${lib.concatStringsSep "|" [
+        # tst_busy_indicator runs into a codepath in lomiri-ui-toolkit that expects a working GL context
+        "^tst_busy_indicator"
+        # Photo & PhotoImageProvider Randomly fail, unsure why
+        "^tst_PhotoEditorPhoto"
+      ]})")
+    ]))
+  ];
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  # Parallelism breaks xvfb-run-launched script for QML tests
+  enableParallelChecking = false;
+
+  preCheck = let
+    listToQtVar = suffix: lib.makeSearchPathOutput "bin" suffix;
+  in ''
+    export QT_PLUGIN_PATH=${listToQtVar qtbase.qtPluginPrefix [ qtbase ]}
+    export QML2_IMPORT_PATH=${listToQtVar qtbase.qtQmlPrefix ([ qtdeclarative lomiri-ui-toolkit ] ++ lomiri-ui-toolkit.propagatedBuildInputs)}
+    export XDG_RUNTIME_DIR=$PWD
+  '';
+
+  passthru = {
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "Lomiri UI Extra Components";
+    longDescription = ''
+      A collection of UI components that for various reasons can't be included in
+      the main Lomiri UI toolkit - mostly because of the level of quality, lack of
+      documentation and/or lack of automated tests.
+    '';
+    homepage = "https://gitlab.com/ubports/development/core/lomiri-ui-extras";
+    changelog = "https://gitlab.com/ubports/development/core/lomiri-ui-extras/-/blob/${finalAttrs.version}/ChangeLog";
+    license = licenses.gpl3Only;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-ui-toolkit/2001-Mark-problematic-tests.patch b/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-ui-toolkit/2001-Mark-problematic-tests.patch
new file mode 100644
index 000000000000..dc1d1e2083c0
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-ui-toolkit/2001-Mark-problematic-tests.patch
@@ -0,0 +1,155 @@
+From c71d5fed4ef1f0b6d56400cddf02d8ac438168c8 Mon Sep 17 00:00:00 2001
+From: OPNA2608 <opna2608@protonmail.com>
+Date: Wed, 17 Apr 2024 16:18:23 +0200
+Subject: [PATCH] Mark problematic tests
+
+- ShapeMaterial requires a Qt OpenGL context, doesn't work in our sandbox
+- SignalSpy on QML shaders compilers don't see changes
+- TypeError on some properties with Qt 5.15
+  https://gitlab.com/ubports/development/core/lomiri-ui-toolkit/-/issues/9
+---
+ tests/checkresults.sh | 88 ++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 82 insertions(+), 6 deletions(-)
+
+diff --git a/tests/checkresults.sh b/tests/checkresults.sh
+index fc498985e..b5d204d0d 100755
+--- a/tests/checkresults.sh
++++ b/tests/checkresults.sh
+@@ -22,6 +22,7 @@ ERRORS_PATTERN='<failure'
+ 
+ FAILURES=0
+ FATAL_WARNINGS=0
++EXCEPTED_FAILURES=0
+ EXCEPTED=0
+ for _XML in $*; do
+     _TESTNAME=$(basename $_XML | sed -r 's@(.+)\.xml@\1@' -)
+@@ -31,7 +32,71 @@ for _XML in $*; do
+       exit 1
+     fi
+ 
+-    EXCEPTIONS='components_benchmark \
++    ERROR_EXCEPTIONS='\
++                tst_actionbar.13.qml \
++                tst_actionlist.13.qml \
++                tst_adaptivepagelayout.13.qml \
++                tst_adaptivepagelayout_configuration.13.qml \
++                tst_combobutton.11.qml \
++                tst_combobutton.13.qml \
++                tst_contextual_actions.13.qml \
++                tst_focus.13.qml \
++                tst_header.13.qml \
++                tst_hide_chrome.11.qml \
++                tst_listitem.12.qml \
++                tst_listitem.13.qml \
++                tst_listitem_actions_breaks_selectmode.12.qml \
++                tst_listitem_extras.13.qml \
++                tst_listitem_focus.13.qml \
++                tst_listitem_horizontal_navigation.13.qml \
++                tst_listitem_selectmode.12.qml \
++                tst_listitem_selectmode.13.qml \
++                tst_listitems_itemselector.11.qml \
++                tst_listitems_standard.11.qml \
++                tst_listitems_standard.13.qml \
++                tst_lomirilistview.11.qml \
++                tst_lomiritestcase.qml \
++                tst_multicolumnheader.13.qml \
++                tst_optionselector.11.qml \
++                tst_optionselector.13.qml \
++                tst_page_with_header.13.qml \
++                tst_pagehead_back_action.13.qml \
++                tst_pagehead_contents_width.13.qml \
++                tst_pagehead_sections.13.qml \
++                tst_pagehead_visible.13.qml \
++                tst_pageheader.13.qml \
++                tst_pagestack.13.qml \
++                tst_pagestack.DEPRECATED_APPHEADER_TABS.13.qml \
++                tst_picker.11.qml \
++                tst_picker.13.qml \
++                tst_popover.12.qml \
++                tst_popover.13.qml \
++                tst_popups_dialog.13.qml \
++                tst_popups_pagestack.13.qml \
++                tst_pulltorefresh_pagestack_topmargin.13.qml \
++                tst_slider.11.qml \
++                tst_slider.13.qml \
++                tst_switch_bug1510919.13.qml \
++                tst_tabs.11.qml \
++                tst_tabs.13.qml \
++                tst_tabs.DEPRECATED_TOOLBAR.11.qml \
++                tst_textarea.11.qml \
++                tst_textarea_in_flickable.11.qml \
++                tst_textfield.11.qml \
++                tst_textinput_common.12.qml \
++                tst_textinput_common.13.qml \
++                tst_toggles.13.qml \
++                inversemousearea \
++                layouts \
++                recreateview \
++                subtheming \
++                swipearea \
++                tst_icon.11.qml \
++                tst_icon.13.qml \
++                '
++
++    EXCEPTIONS='\
++                components_benchmark \
+                 tst_tabbar.11.qml \
+                 tst_datepicker.bug1567840.SEGFAULT.12.qml \
+                 tst_datepicker.bug1567840.SEGFAULT.13.qml \
+@@ -49,22 +114,28 @@ for _XML in $*; do
+                 inversemousearea \
+                 tst_listitem_focus_bug.13.qml \
+                 tst_shortcuts.13.qml \
++                tst_pagestack.DEPRECATED_TOOLBAR.11.qml \
+                 '
+ 
+     WARNINGS=$(grep -c -P "$WARNINGS_PATTERN" $_XML)
+     ERRORS=$(grep -c -P "$ERRORS_PATTERN" $_XML)
+     if [ $ERRORS -ne 0 ]; then
+-      FAILURES_FILES="${FAILURES_FILES}  ${_TESTNAME}\n"
+-      ((FAILURES+=$ERRORS))
++      if [[ $ERROR_EXCEPTIONS == *" $_TESTNAME "* ]]; then
++        EXCEPTED_FAILURES_FILES="${EXCEPTED_FAILURES_FILES}  ${_TESTNAME}\n"
++        ((EXCEPTED_FAILURES+=$ERRORS))
++      else
++        FAILURES_FILES="${FAILURES_FILES}  ${_TESTNAME}\n"
++        ((FAILURES+=$ERRORS))
++      fi
+     elif [ $WARNINGS -ne 0 ]; then
+-      if [[ $EXCEPTIONS == *$_TESTNAME* ]]; then
++      if [[ $EXCEPTIONS == *" $_TESTNAME "* ]]; then
+         EXCEPTED_FILES="${EXCEPTED_FILES}  ${_TESTNAME}\n"
+         ((EXCEPTED+=$WARNINGS))
+       else
+         FATAL_WARNINGS_FILES="${FATAL_WARNINGS_FILES}  ${_TESTNAME}\n"
+         ((FATAL_WARNINGS+=$WARNINGS))
+       fi
+-    elif [[ $EXCEPTIONS == *$_TESTNAME* ]]; then
++    elif [[ $ERROR_EXCEPTIONS == *" $_TESTNAME "* || $EXCEPTIONS == *" $_TESTNAME "* ]]; then
+       WOOT_FILES="${WOOT_FILES}  ${_TESTNAME}\n"
+     fi
+ done
+@@ -82,6 +153,11 @@ if [ -n "$FATAL_WARNINGS_FILES" ]; then
+     echo -e "$FATAL_WARNINGS_FILES"
+ fi
+ 
++if [ -n "$EXCEPTED_FAILURES_FILES" ]; then
++    echo The following tests issued $EXCEPTED_FAILURES expected failures:
++    echo -e "$EXCEPTED_FAILURES_FILES"
++fi
++
+ if [ -n "$EXCEPTED_FILES" ]; then
+     echo The following tests issued $EXCEPTED expected warnings:
+     echo -e "$EXCEPTED_FILES"
+@@ -89,7 +165,7 @@ fi
+ 
+ if [ -n "$WOOT_FILES" ]; then
+     echo Woot! Known problematic tests passed!
+-    echo Consider removing these from EXCEPTIONS in ${0#$(pwd)/}!
++    echo Consider removing these from ERROR_EXCEPTIONS/EXCEPTIONS in ${0#$(pwd)/}!
+     echo -e "$WOOT_FILES"
+ fi
+ 
+-- 
+2.42.0
+
diff --git a/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-ui-toolkit/2002-Nixpkgs-versioned-QML-path.patch.in b/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-ui-toolkit/2002-Nixpkgs-versioned-QML-path.patch.in
new file mode 100644
index 000000000000..d2e83baf98ae
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-ui-toolkit/2002-Nixpkgs-versioned-QML-path.patch.in
@@ -0,0 +1,29 @@
+From ca4c52a80532732243067eb00ec12b4ef84010a6 Mon Sep 17 00:00:00 2001
+From: OPNA2608 <opna2608@protonmail.com>
+Date: Tue, 30 Jan 2024 19:46:09 +0100
+Subject: [PATCH] Nixpkgs versioned QML path
+
+---
+ src/LomiriToolkit/uctheme.cpp | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/src/LomiriToolkit/uctheme.cpp b/src/LomiriToolkit/uctheme.cpp
+index a10c89344..4b0653589 100644
+--- a/src/LomiriToolkit/uctheme.cpp
++++ b/src/LomiriToolkit/uctheme.cpp
+@@ -180,6 +180,12 @@ QStringList themeSearchPath()
+         pathList << QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
+     }
+
++    // append versioned QML import path from Nixpkgs
++    const QString nixpkgsQmlImportPath = QString::fromLocal8Bit(getenv("NIXPKGS_QT@qtVersion@_QML_IMPORT_PATH"));
++    if (!nixpkgsQmlImportPath.isEmpty()) {
++        pathList << nixpkgsQmlImportPath.split(':', QString::SkipEmptyParts);
++    }
++
+     // append QML import path(s); we must explicitly support env override here
+     const QString qml2ImportPath = QString::fromLocal8Bit(getenv("QML2_IMPORT_PATH"));
+     if (!qml2ImportPath.isEmpty()) {
+--
+2.42.0
+
diff --git a/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-ui-toolkit/default.nix b/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-ui-toolkit/default.nix
new file mode 100644
index 000000000000..8767534d368f
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/qml/lomiri-ui-toolkit/default.nix
@@ -0,0 +1,231 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, gitUpdater
+, substituteAll
+, testers
+, dbus-test-runner
+, dpkg
+, gdb
+, glib
+, lttng-ust
+, perl
+, pkg-config
+, python3
+, qmake
+, qtbase
+, qtdeclarative
+, qtfeedback
+, qtgraphicaleffects
+, qtpim
+, qtquickcontrols2
+, qtsvg
+, qtsystems
+, suru-icon-theme
+, validatePkgConfig
+, wrapQtAppsHook
+, xvfb-run
+}:
+
+let
+  listToQtVar = suffix: lib.makeSearchPathOutput "bin" suffix;
+  qtPluginPaths = listToQtVar qtbase.qtPluginPrefix [ qtbase qtpim qtsvg ];
+  qtQmlPaths = listToQtVar qtbase.qtQmlPrefix [ qtdeclarative qtfeedback qtgraphicaleffects ];
+in
+stdenv.mkDerivation (finalAttrs: {
+  pname = "lomiri-ui-toolkit";
+  version = "1.3.5100";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/lomiri-ui-toolkit";
+    rev = finalAttrs.version;
+    hash = "sha256-r+wUCl+ywFcgFYo7BjBoXiulQptd1Zd3LJchXiMtx4I=";
+  };
+
+  outputs = [ "out" "dev" ];
+
+  patches = [
+    ./2001-Mark-problematic-tests.patch
+    (substituteAll {
+      src = ./2002-Nixpkgs-versioned-QML-path.patch.in;
+      name = "2002-Nixpkgs-versioned-QML-path.patch";
+      qtVersion = lib.versions.major qtbase.version;
+    })
+  ];
+
+  postPatch = ''
+    patchShebangs documentation/docs.sh tests/
+
+    for subproject in po app-launch-profiler lomiri-ui-toolkit-launcher; do
+      substituteInPlace $subproject/$subproject.pro \
+        --replace-fail "\''$\''$[QT_INSTALL_PREFIX]" "$out" \
+        --replace-warn "\''$\''$[QT_INSTALL_LIBS]" "$out/lib"
+    done
+
+    # Install apicheck tool into bin
+    substituteInPlace apicheck/apicheck.pro \
+      --replace-fail "\''$\''$[QT_INSTALL_LIBS]/lomiri-ui-toolkit" "$out/bin"
+
+    # Causes redefinition error with our own fortify hardening
+    sed -i '/DEFINES += _FORTIFY_SOURCE/d' features/lomiri_common.prf
+
+    # Reverse dependencies (and their reverse dependencies too) access the function patched here to register their gettext catalogues,
+    # so hardcoding any prefix here will make only catalogues in that prefix work. APP_DIR envvar will override this, but with domains from multiple derivations being
+    # used in a single application (lomiri-system-settings), that's of not much use either.
+    # https://gitlab.com/ubports/development/core/lomiri-ui-toolkit/-/blob/dcb3a523c56a400e5c3c163c2836cafca168767e/src/LomiriToolkit/i18n.cpp#L101-129
+    #
+    # This could be solved with a reference to the prefix of whoever requests the domain, but the call happens via some automatic Qt / QML callback magic,
+    # I'm not sure what the best way of injecting that there would be.
+    # https://gitlab.com/ubports/development/core/lomiri-ui-toolkit/-/blob/dcb3a523c56a400e5c3c163c2836cafca168767e/src/LomiriToolkit/i18n_p.h#L34
+    #
+    # Using /run/current-system/sw/share/locale instead of /usr/share/locale isn't a great
+    # solution, but at least it should get us working localisations
+    substituteInPlace src/LomiriToolkit/i18n.cpp \
+      --replace-fail "/usr" "/run/current-system/sw"
+
+    # The code here overrides the regular QML import variables so the just-built modules are found & used in the tests
+    # But we need their QML dependencies too, so put them back in there
+    substituteInPlace export_qml_dir.sh \
+      --replace-fail '_IMPORT_PATH=$BUILD_DIR/qml' '_IMPORT_PATH=$BUILD_DIR/qml:${qtQmlPaths}'
+
+    # These tests try to load Suru theme icons, but override XDG_DATA_DIRS / use full paths to load them
+    substituteInPlace \
+      tests/unit/visual/tst_visual.cpp \
+      tests/unit/visual/tst_icon.{11,13}.qml \
+      tests/unit/visual/tst_imageprovider.11.qml \
+      --replace-fail '/usr/share' '${suru-icon-theme}/share'
+  '';
+
+  # With strictDeps, QMake only picks up Qt dependencies from nativeBuildInputs
+  strictDeps = false;
+
+  nativeBuildInputs = [
+    perl
+    pkg-config
+    python3
+    qmake
+    validatePkgConfig
+    wrapQtAppsHook
+  ];
+
+  buildInputs = [
+    glib
+    lttng-ust
+    qtbase
+    qtdeclarative
+    qtpim
+    qtquickcontrols2
+    qtsystems
+  ];
+
+  propagatedBuildInputs = [
+    qtfeedback
+    qtgraphicaleffects
+    qtsvg
+  ];
+
+  nativeCheckInputs = [
+    dbus-test-runner
+    dpkg # `dpkg-architecture -qDEB_HOST_ARCH` response decides how tests are run
+    gdb
+    xvfb-run
+  ];
+
+  qmakeFlags = [
+    # docs require Qt5's qdoc, which we don't have before https://github.com/NixOS/nixpkgs/pull/245379
+    "CONFIG+=no_docs"
+    # Ubuntu UITK compatibility, for older / not-yet-migrated applications
+    "CONFIG+=ubuntu-uitk-compat"
+    "QMAKE_PKGCONFIG_PREFIX=${placeholder "out"}"
+  ];
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  # Explicitly not parallel-safe, large parts are always run in series and at least qquick_image_extension fails with parallelism
+  enableParallelChecking = false;
+
+  checkPhase = ''
+    runHook preCheck
+
+    export HOME=$PWD
+
+    # XDG_RUNTIME_DIR with wrong permissions causes warnings that are interpreted as errors in the test suite
+    export XDG_RUNTIME_DIR=$PWD/runtime-dir
+    mkdir -p $XDG_RUNTIME_DIR
+    chmod -R 700 $XDG_RUNTIME_DIR
+
+    # Tests need some Qt plugins
+    # Many tests try to load Suru theme icons via XDG_DATA_DIRS
+    export QT_PLUGIN_PATH=${qtPluginPaths}
+    export XDG_DATA_DIRS=${suru-icon-theme}/share
+
+    tests/xvfb.sh make check ''${enableParallelChecking:+-j''${NIX_BUILD_CORES}}
+
+    runHook postCheck
+  '';
+
+  preInstall = ''
+    # wrapper script calls qmlplugindump, crashes due to lack of minimal platform plugin
+    # Could not find the Qt platform plugin "minimal" in ""
+    # Available platform plugins are: wayland-egl, wayland, wayland-xcomposite-egl, wayland-xcomposite-glx.
+    export QT_PLUGIN_PATH=${qtPluginPaths}
+
+    # Qt-generated wrapper script lacks QML paths to dependencies
+    for qmlModule in Components PerformanceMetrics Test; do
+      substituteInPlace src/imports/$qmlModule/wrapper.sh \
+        --replace-fail 'QML2_IMPORT_PATH=' 'QML2_IMPORT_PATH=${qtQmlPaths}:'
+    done
+  '';
+
+  postInstall = ''
+    # Code loads Qt's qt_module.prf, which force-overrides all QMAKE_PKGCONFIG_* variables except PREFIX for QMake-generated pkg-config files
+    for pcFile in Lomiri{Gestures,Metrics,Toolkit}.pc; do
+      substituteInPlace $out/lib/pkgconfig/$pcFile \
+        --replace-fail "${lib.getLib qtbase}/lib" "\''${prefix}/lib" \
+        --replace-fail "${lib.getDev qtbase}/include" "\''${prefix}/include"
+    done
+
+    # These are all dev-related tools, but declaring a bin output also moves around the QML modules
+    moveToOutput "bin" "$dev"
+  '';
+
+  postFixup = ''
+    for qtBin in $dev/bin/{apicheck,lomiri-ui-toolkit-launcher}; do
+      wrapQtApp $qtBin
+    done
+  '';
+
+  passthru = {
+    tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "QML components to ease the creation of beautiful applications in QML";
+    longDescription = ''
+      This project consists of a set of QML components to ease the creation of beautiful applications in QML for Lomiri.
+
+      QML alone lacks built-in components for basic widgets like Button, Slider, Scrollbar, etc, meaning a developer has
+      to build them from scratch.
+      This toolkit aims to stop this duplication of work, supplying beautiful components ready-made and with a clear and
+      consistent API.
+
+      These components are fully themeable so the look and feel can be easily customized. Resolution independence
+      technology is built in so UIs are scaled to best suit the display.
+
+      Other features:
+        - localisation through gettext
+    '';
+    homepage = "https://gitlab.com/ubports/development/core/lomiri-ui-toolkit";
+    changelog = "https://gitlab.com/ubports/development/core/lomiri-ui-toolkit/-/blob/${finalAttrs.version}/ChangeLog";
+    license = with licenses; [ gpl3Only cc-by-sa-30 ];
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+    pkgConfigModules = [
+      "LomiriGestures"
+      "LomiriMetrics"
+      "LomiriToolkit"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/qml/qqc2-suru-style/default.nix b/nixpkgs/pkgs/desktops/lomiri/qml/qqc2-suru-style/default.nix
new file mode 100644
index 000000000000..5717ae35f113
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/qml/qqc2-suru-style/default.nix
@@ -0,0 +1,45 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, gitUpdater
+, qmake
+, qtdeclarative
+, qtquickcontrols2
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "qqc2-suru-style";
+  version = "0.20230206";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/qqc2-suru-style";
+    rev = finalAttrs.version;
+    hash = "sha256-ZLPuXnhlR1IDhGnprcdWHLnOeS6ZzVkFhQML0iKMjO8=";
+  };
+
+  # QMake can't find Qt modules from buildInputs
+  strictDeps = false;
+
+  nativeBuildInputs = [
+    qmake
+  ];
+
+  buildInputs = [
+    qtdeclarative
+    qtquickcontrols2
+  ];
+
+  dontWrapQtApps = true;
+
+  passthru.updateScript = gitUpdater { };
+
+  meta = with lib; {
+    description = "Suru Style for QtQuick Controls 2";
+    homepage = "https://gitlab.com/ubports/development/core/qqc2-suru-style";
+    changelog = "https://gitlab.com/ubports/development/core/qqc2-suru-style/-/blob/${finalAttrs.version}/ChangeLog";
+    license = with licenses; [ gpl2Plus lgpl3Only cc-by-sa-30 ];
+    maintainers = teams.lomiri.members;
+    platforms = platforms.unix;
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/services/biometryd/default.nix b/nixpkgs/pkgs/desktops/lomiri/services/biometryd/default.nix
new file mode 100644
index 000000000000..d06ecf16942e
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/services/biometryd/default.nix
@@ -0,0 +1,120 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, fetchpatch
+, gitUpdater
+, testers
+, boost
+, cmake
+, cmake-extras
+, dbus
+, dbus-cpp
+, gtest
+, libapparmor
+, libelf
+, pkg-config
+, process-cpp
+, properties-cpp
+, qtbase
+, qtdeclarative
+, sqlite
+, validatePkgConfig
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "biometryd";
+  version = "0.3.1";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/biometryd";
+    rev = finalAttrs.version;
+    hash = "sha256-derU7pKdNf6pwhskaW7gCLcU9ixBG3U0EI/qtANmmTs=";
+  };
+
+  outputs = [
+    "out"
+    "dev"
+  ];
+
+  postPatch = ''
+    # Substitute systemd's prefix in pkg-config call
+    substituteInPlace data/CMakeLists.txt \
+      --replace-fail 'pkg_get_variable(SYSTEMD_SYSTEM_UNIT_DIR systemd systemdsystemunitdir)' 'pkg_get_variable(SYSTEMD_SYSTEM_UNIT_DIR systemd systemdsystemunitdir DEFINE_VARIABLES prefix=''${CMAKE_INSTALL_PREFIX})'
+
+    substituteInPlace src/biometry/qml/Biometryd/CMakeLists.txt \
+      --replace-fail "\''${CMAKE_INSTALL_LIBDIR}/qt5/qml" "\''${CMAKE_INSTALL_PREFIX}/${qtbase.qtQmlPrefix}"
+
+    # For our automatic pkg-config output patcher to work, prefix must be used here
+    substituteInPlace data/biometryd.pc.in \
+      --replace-fail 'libdir=''${exec_prefix}' 'libdir=''${prefix}' \
+      --replace-fail 'includedir=''${exec_prefix}' 'includedir=''${prefix}' \
+  '' + lib.optionalString (!finalAttrs.doCheck) ''
+    sed -i -e '/add_subdirectory(tests)/d' CMakeLists.txt
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    pkg-config
+    qtdeclarative # qmlplugindump
+    validatePkgConfig
+  ];
+
+  buildInputs = [
+    boost
+    cmake-extras
+    dbus
+    dbus-cpp
+    libapparmor
+    libelf
+    process-cpp
+    properties-cpp
+    qtbase
+    qtdeclarative
+    sqlite
+  ];
+
+  checkInputs = [
+    gtest
+  ];
+
+  dontWrapQtApps = true;
+
+  cmakeFlags = [
+    # maybe-uninitialized warnings
+    (lib.cmakeBool "ENABLE_WERROR" false)
+    (lib.cmakeBool "WITH_HYBRIS" false)
+  ];
+
+  preBuild = ''
+    # Generating plugins.qmltypes (also used in checkPhase?)
+    export QT_PLUGIN_PATH=${lib.getBin qtbase}/${qtbase.qtPluginPrefix}
+  '';
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  passthru = {
+    tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "Mediates/multiplexes access to biometric devices";
+    longDescription = ''
+      biometryd mediates and multiplexes access to biometric devices present
+      on the system, enabling applications and system components to leverage
+      them for identification and verification of users.
+    '';
+    homepage = "https://gitlab.com/ubports/development/core/biometryd";
+    changelog = "https://gitlab.com/ubports/development/core/biometryd/-/${finalAttrs.version}/ChangeLog";
+    license = licenses.lgpl3Only;
+    maintainers = teams.lomiri.members;
+    mainProgram = "biometryd";
+    platforms = platforms.linux;
+    pkgConfigModules = [
+      "biometryd"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/services/content-hub/default.nix b/nixpkgs/pkgs/desktops/lomiri/services/content-hub/default.nix
new file mode 100644
index 000000000000..7cbf7f205871
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/services/content-hub/default.nix
@@ -0,0 +1,195 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, fetchpatch
+, fetchpatch2
+, gitUpdater
+, testers
+, cmake
+, cmake-extras
+, dbus-test-runner
+, gettext
+, glib
+, gsettings-qt
+, gtest
+, libapparmor
+, libnotify
+, lomiri-api
+, lomiri-app-launch
+, lomiri-download-manager
+, lomiri-ui-toolkit
+, pkg-config
+, properties-cpp
+, qtbase
+, qtdeclarative
+, qtfeedback
+, qtgraphicaleffects
+, validatePkgConfig
+, wrapGAppsHook
+, xvfb-run
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "content-hub";
+  version = "1.1.1";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/content-hub";
+    rev = finalAttrs.version;
+    hash = "sha256-sQeyJV+Wc6PHKGIefl/dfU06XqTdICsn+Xamjx3puiI=";
+  };
+
+  outputs = [
+    "out"
+    "dev"
+    "examples"
+  ];
+
+  patches = [
+    # Remove when https://gitlab.com/ubports/development/core/content-hub/-/merge_requests/33 merged & in release
+    (fetchpatch {
+      name = "0001-content-hub-Migrate-to-GetConnectionCredentials.patch";
+      url = "https://gitlab.com/ubports/development/core/content-hub/-/commit/9c0eae42d856b4b6e24fa609ade0e674c7a84cfe.patch";
+      hash = "sha256-IWoCQKSCCk26n7133oG0Ht+iEjavn/IiOVUM+tCLX2U=";
+    })
+
+    # Remove when https://gitlab.com/ubports/development/core/content-hub/-/merge_requests/34 merged & in release
+    (fetchpatch {
+      name = "0002-content-hub-import-Lomiri-Content-CMakeLists-Drop-qt-argument-to-qmlplugindump.patch";
+      url = "https://gitlab.com/ubports/development/core/content-hub/-/commit/63a4baf1469de31c4fd50c69ed85d061f5e8e80a.patch";
+      hash = "sha256-T+6T9lXne6AhDFv9d7L8JNwdl8f0wjDmvSoNVPkHza4=";
+    })
+
+    # Remove when https://gitlab.com/ubports/development/core/content-hub/-/merge_requests/35 merged & in release
+    # fetchpatch2 due to renames, https://github.com/NixOS/nixpkgs/issues/32084
+    (fetchpatch2 {
+      name = "0003-content-hub-Add-more-better-GNUInstallDirs-variables-usage.patch";
+      url = "https://gitlab.com/ubports/development/core/content-hub/-/commit/3c5ca4a8ec125e003aca78c14521b70140856c25.patch";
+      hash = "sha256-kYN0eLwMyM/9yK+zboyEsoPKZMZ4SCXodVYsvkQr2F8=";
+    })
+
+    # Remove when https://gitlab.com/ubports/development/core/content-hub/-/merge_requests/37 merged & in release
+    (fetchpatch {
+      name = "0004-content-hub-Fix-generation-of-transfer_files.patch";
+      url = "https://gitlab.com/ubports/development/core/content-hub/-/commit/7ab3a4421356f83515f0deffb5f97a5b38601c13.patch";
+      hash = "sha256-MJZm3ny5t0/GX0bd5hGQbPM2k7M4KUvKqce/0cYYgvM=";
+    })
+    (fetchpatch {
+      name = "0005-content-hub-Fix-generation-of-moc_test_harness.patch";
+      url = "https://gitlab.com/ubports/development/core/content-hub/-/commit/6e30f4f10ef90e817ca01d32959b6c782de48955.patch";
+      hash = "sha256-TAbYn265RpHpulaRVaHy9XqNF+qoDE7YQIfFMPfqEhw=";
+    })
+  ];
+
+  postPatch = ''
+    substituteInPlace import/*/Content/CMakeLists.txt \
+      --replace-fail "\''${CMAKE_INSTALL_LIBDIR}/qt5/qml" "\''${CMAKE_INSTALL_PREFIX}/${qtbase.qtQmlPrefix}"
+
+    # Look for peer files in running system
+    substituteInPlace src/com/lomiri/content/service/registry-updater.cpp \
+      --replace-fail '/usr' '/run/current-system/sw'
+
+    # Don't override default theme search path (which honours XDG_DATA_DIRS) with a FHS assumption
+    substituteInPlace import/Lomiri/Content/contenthubplugin.cpp \
+      --replace-fail 'QIcon::setThemeSearchPaths(QStringList() << ("/usr/share/icons/"));' ""
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    gettext
+    pkg-config
+    qtdeclarative # qmlplugindump
+    validatePkgConfig
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    cmake-extras
+    glib
+    gsettings-qt
+    libapparmor
+    libnotify
+    lomiri-api
+    lomiri-app-launch
+    lomiri-download-manager
+    lomiri-ui-toolkit
+    properties-cpp
+    qtbase
+    qtdeclarative
+    qtfeedback
+    qtgraphicaleffects
+  ];
+
+  nativeCheckInputs = [
+    dbus-test-runner
+    xvfb-run
+  ];
+
+  checkInputs = [
+    gtest
+  ];
+
+  dontWrapQtApps = true;
+
+  cmakeFlags = [
+    (lib.cmakeBool "GSETTINGS_COMPILE" true)
+    (lib.cmakeBool "GSETTINGS_LOCALINSTALL" true)
+    (lib.cmakeBool "ENABLE_TESTS" finalAttrs.finalPackage.doCheck)
+    (lib.cmakeBool "ENABLE_DOC" false) # needs Qt5 qdoc: https://github.com/NixOS/nixpkgs/pull/245379
+    (lib.cmakeBool "ENABLE_UBUNTU_COMPAT" true) # in case something still depends on it
+  ];
+
+  preBuild = let
+    listToQtVar = list: suffix: lib.strings.concatMapStringsSep ":" (drv: "${lib.getBin drv}/${suffix}") list;
+  in ''
+    # Executes qmlplugindump
+    export QT_PLUGIN_PATH=${listToQtVar [ qtbase ] qtbase.qtPluginPrefix}
+    export QML2_IMPORT_PATH=${listToQtVar [ qtdeclarative lomiri-ui-toolkit qtfeedback qtgraphicaleffects ] qtbase.qtQmlPrefix}
+  '';
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  # Starts & talks to D-Bus services, breaks under parallelism
+  enableParallelChecking = false;
+
+  preFixup = ''
+    for exampleExe in content-hub-test-{importer,exporter,sharer}; do
+      moveToOutput bin/$exampleExe $examples
+      moveToOutput share/applications/$exampleExe.desktop $examples
+    done
+    moveToOutput share/icons $examples
+    moveToOutput share/content-hub/peers $examples
+  '';
+
+  postFixup = ''
+    for exampleBin in $examples/bin/*; do
+      wrapGApp $exampleBin
+    done
+  '';
+
+  passthru = {
+    tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "Content sharing/picking service";
+    longDescription = ''
+      content-hub is a mediation service to let applications share content between them,
+      even if they are not running at the same time.
+    '';
+    homepage = "https://gitlab.com/ubports/development/core/content-hub";
+    changelog = "https://gitlab.com/ubports/development/core/content-hub/-/blob/${finalAttrs.version}/ChangeLog";
+    license = with licenses; [ gpl3Only lgpl3Only ];
+    mainProgram = "content-hub-service";
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+    pkgConfigModules = [
+      "libcontent-hub"
+      "libcontent-hub-glib"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/services/hfd-service/default.nix b/nixpkgs/pkgs/desktops/lomiri/services/hfd-service/default.nix
new file mode 100644
index 000000000000..cdffee5edaef
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/services/hfd-service/default.nix
@@ -0,0 +1,77 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, gitUpdater
+, accountsservice
+, cmake
+, cmake-extras
+, deviceinfo
+, libgbinder
+, libglibutil
+, pkg-config
+, qtbase
+, qtdeclarative
+, qtfeedback
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "hfd-service";
+  version = "0.2.2";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/hfd-service";
+    rev = finalAttrs.version;
+    hash = "sha256-OpT1vNjnyq66v54EoGOZOUb4HECD4WRJRh9hYMB0GI0=";
+  };
+
+  postPatch = ''
+    substituteInPlace qt/feedback-plugin/CMakeLists.txt \
+      --replace "\''${CMAKE_INSTALL_LIBDIR}/qt5/plugins" "\''${CMAKE_INSTALL_PREFIX}/${qtbase.qtPluginPrefix}"
+
+    # Queries pkg-config via pkg_get_variable, can't override prefix
+    substituteInPlace init/CMakeLists.txt \
+      --replace 'pkg_get_variable(SYSTEMD_SYSTEM_DIR systemd systemdsystemunitdir)' 'set(SYSTEMD_SYSTEM_DIR ''${CMAKE_INSTALL_PREFIX}/lib/systemd/system)'
+    substituteInPlace CMakeLists.txt \
+      --replace 'pkg_get_variable(AS_INTERFACES_DIR accountsservice interfacesdir)' 'set(AS_INTERFACES_DIR "''${CMAKE_INSTALL_FULL_DATADIR}/accountsservice/interfaces")' \
+      --replace '../../dbus-1/interfaces' "\''${CMAKE_INSTALL_PREFIX}/\''${DBUS_INTERFACES_DIR}" \
+      --replace 'DESTINATION ''${DBUS_INTERFACES_DIR}' 'DESTINATION ''${CMAKE_INSTALL_PREFIX}/''${DBUS_INTERFACES_DIR}'
+    substituteInPlace src/CMakeLists.txt \
+      --replace "\''${DBUS_INTERFACES_DIR}/org.freedesktop.Accounts.xml" '${accountsservice}/share/dbus-1/interfaces/org.freedesktop.Accounts.xml'
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    pkg-config
+  ];
+
+  buildInputs = [
+    accountsservice
+    cmake-extras
+    deviceinfo
+    libgbinder
+    libglibutil
+    qtbase
+    qtdeclarative
+    qtfeedback
+  ];
+
+  cmakeFlags = [
+    (lib.cmakeBool "ENABLE_LIBHYBRIS" false)
+  ];
+
+  dontWrapQtApps = true;
+
+  passthru.updateScript = gitUpdater { };
+
+  meta = with lib; {
+    description = "DBus-activated service that manages human feedback devices such as LEDs and vibrators on mobile devices";
+    homepage = "https://gitlab.com/ubports/development/core/hfd-service";
+    changelog = "https://gitlab.com/ubports/development/core/hfd-service/-/blob/${finalAttrs.version}/ChangeLog";
+    license = licenses.lgpl3Only;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/services/history-service/default.nix b/nixpkgs/pkgs/desktops/lomiri/services/history-service/default.nix
new file mode 100644
index 000000000000..86866db3ce92
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/services/history-service/default.nix
@@ -0,0 +1,199 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, fetchpatch
+, gitUpdater
+, testers
+, cmake
+, dbus
+, dbus-test-runner
+, dconf
+, gnome
+, libphonenumber
+, libqtdbustest
+, pkg-config
+, protobuf
+, qtbase
+, qtdeclarative
+, qtpim
+, sqlite
+, telepathy
+, telepathy-mission-control
+, validatePkgConfig
+, wrapQtAppsHook
+, xvfb-run
+}:
+
+let
+  replaceDbusService = pkg: name: "--replace \"\\\${DBUS_SERVICES_DIR}/${name}\" \"${pkg}/share/dbus-1/services/${name}\"";
+in
+stdenv.mkDerivation (finalAttrs: {
+  pname = "history-service";
+  version = "0.5";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/history-service";
+    rev = finalAttrs.version;
+    hash = "sha256-m/ytJoHxW0q1vlVKK6Z9ovHzjoiS1AodCSGHTeKygfQ=";
+  };
+
+  outputs = [
+    "out"
+    "dev"
+  ];
+
+  patches = [
+    # Drop deprecated qt5_use_modules usage
+    # Remove when https://gitlab.com/ubports/development/core/history-service/-/merge_requests/36 merged & in release
+    (fetchpatch {
+      url = "https://gitlab.com/ubports/development/core/history-service/-/commit/b36ab377aca93555b29d1471d6eaa706b5c843ca.patch";
+      hash = "sha256-mOpXqqd4JI7lHtcWDm9LGCrtB8ERge04jMpHIagDM2k=";
+    })
+
+    # Add more / correct existing GNUInstallDirs usage
+    # Remove when https://gitlab.com/ubports/development/core/history-service/-/merge_requests/37 merged & in release
+    (fetchpatch {
+      url = "https://gitlab.com/ubports/development/core/history-service/-/commit/bb4dbdd16e80dcd286d8edfb86b08f0b61bc7fec.patch";
+      hash = "sha256-C/XaygI663yaU06klQD9g0NnbqYxHSmzdbrRxcfiJkk=";
+    })
+
+    # Correct version information
+    # Remove when https://gitlab.com/ubports/development/core/history-service/-/merge_requests/38 merged & in release
+    (fetchpatch {
+      url = "https://gitlab.com/ubports/development/core/history-service/-/commit/98458126f9f494b124134fb35c198af0545f6a98.patch";
+      hash = "sha256-4EfLsaueKTCovl8EilN30cmfNfg19wvyCsbKqOrXtuw=";
+    })
+
+    # Make tests optional
+    # Remove when https://gitlab.com/ubports/development/core/history-service/-/merge_requests/39 merged & in release
+    (fetchpatch {
+      url = "https://gitlab.com/ubports/development/core/history-service/-/commit/cb5c80cffc35611657244e15a7eb10edcd598ccd.patch";
+      hash = "sha256-MFHGu4OMScdThq9htUgFMpezP7Ym6YTIZUHWol20wqw=";
+    })
+  ];
+
+  postPatch = ''
+    # Upstream's way of generating their schema doesn't work for us, don't quite understand why.
+    # (gdb) bt
+    # #0  QSQLiteResult::prepare (this=0x4a4650, query=...) at qsql_sqlite.cpp:406
+    # #1  0x00007ffff344bcf4 in QSQLiteResult::reset (this=0x4a4650, query=...) at qsql_sqlite.cpp:378
+    # #2  0x00007ffff7f95f39 in QSqlQuery::exec (this=this@entry=0x7fffffffaad8, query=...) at kernel/qsqlquery.cpp:406
+    # #3  0x00000000004084cb in SQLiteDatabase::dumpSchema (this=<optimized out>) at /build/source/plugins/sqlite/sqlitedatabase.cpp:148
+    # #4  0x0000000000406d70 in main (argc=<optimized out>, argv=<optimized out>)
+    #     at /build/source/plugins/sqlite/schema/generate_schema.cpp:56
+    # (gdb) p lastError().driverText().toStdString()
+    # $17 = {_M_dataplus = {<std::allocator<char>> = {<std::__new_allocator<char>> = {<No data fields>}, <No data fields>},
+    #     _M_p = 0x4880d0 "Unable to execute statement"}, _M_string_length = 27, {
+    #     _M_local_buf = "\033\000\000\000\000\000\000\000+\344\371\367\377\177\000", _M_allocated_capacity = 27}}
+    # (gdb) p lastError().databaseText().toStdString()
+    # $18 = {_M_dataplus = {<std::allocator<char>> = {<std::__new_allocator<char>> = {<No data fields>}, <No data fields>},
+    #     _M_p = 0x48c480 "no such column: rowid"}, _M_string_length = 21, {
+    #     _M_local_buf = "\025\000\000\000\000\000\000\000A\344\371\367\377\177\000", _M_allocated_capacity = 21}}
+    #
+    # This makes the tests stall indefinitely and breaks history-service usage.
+    # This replacement script should hopefully achieve the same / a similar-enough result with just sqlite
+    cp ${./update_schema.sh.in} plugins/sqlite/schema/update_schema.sh.in
+
+    # libphonenumber -> protobuf -> abseil-cpp demands C++14
+    # But uses std::string_view which is C++17?
+    substituteInPlace CMakeLists.txt \
+      --replace '-std=c++11' '-std=c++17'
+
+    # Uses pkg_get_variable, cannot substitute prefix with that
+    substituteInPlace daemon/CMakeLists.txt \
+      --replace 'pkg_get_variable(SYSTEMD_USER_UNIT_DIR systemd systemduserunitdir)' 'set(SYSTEMD_USER_UNIT_DIR "''${CMAKE_INSTALL_PREFIX}/lib/systemd/user")'
+
+    # Queries qmake for the QML installation path, which returns a reference to Qt5's build directory
+    substituteInPlace CMakeLists.txt \
+      --replace "\''${QMAKE_EXECUTABLE} -query QT_INSTALL_QML" "echo $out/${qtbase.qtQmlPrefix}"
+  '' + lib.optionalString finalAttrs.finalPackage.doCheck ''
+    # Tests launch these DBus services, fix paths related to them
+    substituteInPlace tests/common/dbus-services/CMakeLists.txt \
+      ${replaceDbusService telepathy-mission-control "org.freedesktop.Telepathy.MissionControl5.service"} \
+      ${replaceDbusService telepathy-mission-control "org.freedesktop.Telepathy.AccountManager.service"} \
+      ${replaceDbusService dconf "ca.desrt.dconf.service"}
+
+    substituteInPlace cmake/modules/GenerateTest.cmake \
+      --replace '/usr/lib/dconf' '${lib.getLib dconf}/libexec' \
+      --replace '/usr/lib/telepathy' '${lib.getLib telepathy-mission-control}/libexec'
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    pkg-config
+    sqlite
+    validatePkgConfig
+    wrapQtAppsHook
+  ];
+
+  buildInputs = [
+    libphonenumber
+    protobuf
+    qtbase
+    qtdeclarative
+    qtpim
+    telepathy
+  ];
+
+  nativeCheckInputs = [
+    dbus
+    dbus-test-runner
+    dconf
+    gnome.gnome-keyring
+    telepathy-mission-control
+    xvfb-run
+  ];
+
+  cmakeFlags = [
+    # Many deprecation warnings with Qt 5.15
+    (lib.cmakeBool "ENABLE_WERROR" false)
+    (lib.cmakeFeature "CMAKE_CTEST_ARGUMENTS" (lib.concatStringsSep ";" [
+      # DaemonTest is flaky
+      # https://gitlab.com/ubports/development/core/history-service/-/issues/13
+      "-E" "^DaemonTest"
+    ]))
+  ];
+
+  preBuild = ''
+    # SQLiteDatabase is used on host to generate SQL schemas
+    # Tests also need this to use SQLiteDatabase for verifying correct behaviour
+    export QT_PLUGIN_PATH=${lib.getBin qtbase}/${qtbase.qtPluginPrefix}
+  '';
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  # Starts & talks to D-Bus services, breaks with parallelism
+  enableParallelChecking = false;
+
+  preCheck = ''
+    export QT_PLUGIN_PATH=${lib.getBin qtpim}/${qtbase.qtPluginPrefix}:$QT_PLUGIN_PATH
+    export HOME=$PWD
+  '';
+
+  passthru = {
+    tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "Service that provides call log and conversation history";
+    longDescription = ''
+      History service provides the database and an API to store/retrieve the call log (used by dialer-app) and the sms/mms history (used by messaging-app).
+
+      See as well telepathy-ofono for incoming message events.
+
+      Database location: ~/.local/share/history-service/history.sqlite
+    '';
+    homepage = "https://gitlab.com/ubports/development/core/history-service";
+    changelog = "https://gitlab.com/ubports/development/core/history-service/-/blob/${finalAttrs.version}/ChangeLog";
+    license = licenses.gpl3Only;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+    pkgConfigModules = [
+      "history-service"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/services/history-service/update_schema.sh.in b/nixpkgs/pkgs/desktops/lomiri/services/history-service/update_schema.sh.in
new file mode 100644
index 000000000000..3911c59ebe3a
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/services/history-service/update_schema.sh.in
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+if [ $# -lt 3 ]; then
+    echo "Usage: $0 <source directory> <target file> <version info file>"
+    exit 1
+fi
+
+SOURCE_DIR=$1
+TARGET_FILE=$2
+VERSION_FILE=$3
+
+VERSION="1"
+LATEST_VERSION="1"
+MERGED_COMMANDS="merged.sql"
+
+[ -e $MERGED_COMMANDS ] && rm $MERGED_COMMANDS
+SCHEMA_FILE="$SOURCE_DIR/v${VERSION}.sql"
+while [ -e $SCHEMA_FILE ]; do
+    cat $SCHEMA_FILE >> $MERGED_COMMANDS
+    LATEST_VERSION=$VERSION
+    VERSION=$(($VERSION+1))
+    SCHEMA_FILE="$SOURCE_DIR/v${VERSION}.sql"
+done
+
+# To output the schema
+echo ".fullschema" >> $MERGED_COMMANDS
+
+# The schemas may use functions that history-service defines in C which don't affect the generated schema in a meaningful way.
+# sqlite will return an error after processing queries with such function calls, so remove them.
+sed -i -e '/normalizeId(/d' $MERGED_COMMANDS
+
+sqlite3 <$MERGED_COMMANDS >$TARGET_FILE
+
+echo $LATEST_VERSION > $VERSION_FILE
diff --git a/nixpkgs/pkgs/desktops/lomiri/services/lomiri-download-manager/default.nix b/nixpkgs/pkgs/desktops/lomiri/services/lomiri-download-manager/default.nix
new file mode 100644
index 000000000000..6174bd9c54b0
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/services/lomiri-download-manager/default.nix
@@ -0,0 +1,144 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, fetchpatch
+, gitUpdater
+, testers
+, boost
+, cmake
+, cmake-extras
+, dbus
+, dbus-test-runner
+# Needs qdoc, https://github.com/NixOS/nixpkgs/pull/245379
+, withDocumentation ? false
+, doxygen
+, glog
+, graphviz
+, gtest
+, lomiri-api
+, pkg-config
+, python3
+, qtbase
+, qtdeclarative
+, validatePkgConfig
+, wrapQtAppsHook
+, xvfb-run
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "lomiri-download-manager";
+  version = "0.1.3";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/lomiri-download-manager";
+    rev = finalAttrs.version;
+    hash = "sha256-LhhO/zZ4wNiRd235NB2b08SQcCZt1awN/flcsLs2m8U=";
+  };
+
+  outputs = [
+    "out"
+    "dev"
+  ] ++ lib.optionals withDocumentation [
+    "doc"
+  ];
+
+  patches = [
+    # This change seems incomplete, potentially breaks things on systems that don't use AppArmor mediation
+    # https://gitlab.com/ubports/development/core/lomiri-download-manager/-/merge_requests/24#note_1746801673
+    (fetchpatch {
+      name = "0001-lomiri-download-manager-Revert-Drop-GetConnectionAppArmorSecurityContext.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-download-manager/-/commit/2367f3dff852b69457b1a65a487cb032c210569f.patch";
+      revert = true;
+      hash = "sha256-xS0Wz6d+bZWj/kDGK2WhOduzyP4Rgz3n9n2XY1Zu5hE=";
+    })
+  ];
+
+  postPatch = ''
+    # Substitute systemd's prefix in pkg-config call
+    substituteInPlace CMakeLists.txt \
+      --replace-fail 'pkg_get_variable(SYSTEMD_USER_DIR systemd systemduserunitdir)' 'pkg_get_variable(SYSTEMD_USER_DIR systemd systemduserunitdir DEFINE_VARIABLES prefix=''${CMAKE_INSTALL_PREFIX})' \
+      --replace-fail "\''${CMAKE_INSTALL_LIBDIR}/qt5/qml" "\''${CMAKE_INSTALL_PREFIX}/${qtbase.qtQmlPrefix}"
+
+    # For our automatic pkg-config output patcher to work, prefix must be used here
+    substituteInPlace src/{common/public,downloads/client,downloads/common,uploads/common}/*.pc.in \
+      --replace-fail 'libdir=''${exec_prefix}' 'libdir=''${prefix}'
+    substituteInPlace src/downloads/client/lomiri-download-manager-client.pc.in \
+      --replace-fail 'includedir=''${exec_prefix}' 'includedir=''${prefix}'
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    pkg-config
+    validatePkgConfig
+    wrapQtAppsHook
+  ] ++ lib.optionals withDocumentation [
+    doxygen
+    graphviz
+  ];
+
+  buildInputs = [
+    boost
+    cmake-extras
+    glog
+    lomiri-api
+    qtbase
+    qtdeclarative
+  ];
+
+  nativeCheckInputs = [
+    dbus
+    dbus-test-runner
+    python3
+    xvfb-run
+  ];
+
+  checkInputs = [
+    gtest
+  ];
+
+  cmakeFlags = [
+    (lib.cmakeBool "ENABLE_DOC" withDocumentation)
+    # Deprecation warnings on Qt 5.15
+    # https://gitlab.com/ubports/development/core/lomiri-download-manager/-/issues/1
+    (lib.cmakeBool "ENABLE_WERROR" false)
+  ];
+
+  makeTargets = [
+    "all"
+  ] ++ lib.optionals withDocumentation [
+    "doc"
+  ];
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  # xvfb tests are flaky on xvfb shutdown when parallelised
+  enableParallelChecking = false;
+
+  preCheck = ''
+    export HOME=$TMPDIR # temp files in home
+    export QT_PLUGIN_PATH=${lib.getBin qtbase}/${qtbase.qtPluginPrefix} # xcb platform & sqlite driver
+  '';
+
+  passthru = {
+    tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "Performs uploads and downloads from a centralized location";
+    homepage = "https://gitlab.com/ubports/development/core/lomiri-download-manager";
+    changelog = "https://gitlab.com/ubports/development/core/lomiri-download-manager/-/blob/${finalAttrs.version}/ChangeLog";
+    license = licenses.lgpl3Only;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+    pkgConfigModules = [
+      "ldm-common"
+      "lomiri-download-manager-client"
+      "lomiri-download-manager-common"
+      "lomiri-upload-manager-common"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/services/lomiri-indicator-network/default.nix b/nixpkgs/pkgs/desktops/lomiri/services/lomiri-indicator-network/default.nix
new file mode 100644
index 000000000000..fc552881f469
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/services/lomiri-indicator-network/default.nix
@@ -0,0 +1,133 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, gitUpdater
+, nixosTests
+, testers
+, cmake
+, cmake-extras
+, coreutils
+, dbus
+, doxygen
+, gettext
+, glib
+, gmenuharness
+, gtest
+, intltool
+, libsecret
+, libqofono
+, libqtdbusmock
+, libqtdbustest
+, lomiri-api
+, lomiri-url-dispatcher
+, networkmanager
+, ofono
+, pkg-config
+, python3
+, qtdeclarative
+, qtbase
+, validatePkgConfig
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "lomiri-indicator-network";
+  version = "1.0.2";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/lomiri-indicator-network";
+    rev = finalAttrs.version;
+    hash = "sha256-9AQCWCZFbt4XcmKsjoTXJlWOm02/kBhpPxbHRtftNFM=";
+  };
+
+  outputs = [
+    "out"
+    "dev"
+    "doc"
+  ];
+
+  postPatch = ''
+    # Override original prefixes
+    substituteInPlace data/CMakeLists.txt \
+      --replace-fail 'pkg_get_variable(DBUS_SESSION_BUS_SERVICES_DIR dbus-1 session_bus_services_dir)' 'pkg_get_variable(DBUS_SESSION_BUS_SERVICES_DIR dbus-1 session_bus_services_dir DEFINE_VARIABLES datadir=''${CMAKE_INSTALL_FULL_SYSCONFDIR})' \
+      --replace-fail 'pkg_get_variable(SYSTEMD_USER_DIR systemd systemduserunitdir)' 'pkg_get_variable(SYSTEMD_USER_DIR systemd systemduserunitdir DEFINE_VARIABLES prefix=''${CMAKE_INSTALL_PREFIX})'
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    doxygen
+    gettext
+    intltool
+    pkg-config
+    qtdeclarative
+    validatePkgConfig
+  ];
+
+  buildInputs = [
+    cmake-extras
+    dbus
+    glib
+    libqofono
+    libsecret
+    lomiri-api
+    lomiri-url-dispatcher
+    networkmanager
+    ofono
+    qtbase
+  ];
+
+  nativeCheckInputs = [
+    (python3.withPackages (ps: with ps; [
+      python-dbusmock
+    ]))
+  ];
+
+  checkInputs = [
+    gmenuharness
+    gtest
+    libqtdbusmock
+    libqtdbustest
+  ];
+
+  dontWrapQtApps = true;
+
+  cmakeFlags = [
+    (lib.cmakeBool "GSETTINGS_LOCALINSTALL" true)
+    (lib.cmakeBool "GSETTINGS_COMPILE" true)
+    (lib.cmakeBool "ENABLE_TESTS" finalAttrs.doCheck)
+    (lib.cmakeBool "ENABLE_UBUNTU_COMPAT" true) # just in case something needs it
+    (lib.cmakeBool "BUILD_DOC" true) # lacks QML docs, needs qdoc: https://github.com/NixOS/nixpkgs/pull/245379
+  ];
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  postInstall = ''
+    substituteInPlace $out/etc/dbus-1/services/com.lomiri.connectivity1.service \
+      --replace '/bin/false' '${lib.getExe' coreutils "false"}'
+  '';
+
+  passthru = {
+    ayatana-indicators = [
+      "lomiri-indicator-network"
+    ];
+    tests = {
+      pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+      vm = nixosTests.ayatana-indicators;
+    };
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "Ayatana indiator exporting the network settings menu through D-Bus";
+    homepage = "https://gitlab.com/ubports/development/core/lomiri-indicator-network";
+    changelog = "https://gitlab.com/ubports/development/core/lomiri-indicator-network/-/blob/${finalAttrs.version}/ChangeLog";
+    license = licenses.gpl3Only;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+    pkgConfigModules = [
+      "lomiri-connectivity-qt1"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/services/lomiri-thumbnailer/default.nix b/nixpkgs/pkgs/desktops/lomiri/services/lomiri-thumbnailer/default.nix
new file mode 100644
index 000000000000..e400b73a25ab
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/services/lomiri-thumbnailer/default.nix
@@ -0,0 +1,218 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, fetchpatch
+, gitUpdater
+, testers
+, boost
+, cmake
+, cmake-extras
+, doxygen
+, gst_all_1
+, gdk-pixbuf
+, gtest
+, makeFontsConf
+, libapparmor
+, libexif
+, libqtdbustest
+, librsvg
+, lomiri-api
+, persistent-cache-cpp
+, pkg-config
+, python3
+, qtbase
+, qtdeclarative
+, shared-mime-info
+, taglib
+, validatePkgConfig
+, wrapGAppsHook
+, xvfb-run
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "lomiri-thumbnailer";
+  version = "3.0.3";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/lomiri-thumbnailer";
+    rev = finalAttrs.version;
+    hash = "sha256-BE/U4CT4z4WzEJXrVhX8ME/x9q7w8wNnJKTbfVku2VQ=";
+  };
+
+  outputs = [
+    "out"
+    "dev"
+    "doc"
+  ];
+
+  patches = [
+    # Remove when https://gitlab.com/ubports/development/core/lomiri-thumbnailer/-/merge_requests/19 merged & in release
+    (fetchpatch {
+      name = "0001-lomiri-thumbnailer-Add-more-better-GNUInstallDirs-variables-usage.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-thumbnailer/-/commit/0b9795a6313fd025d5646f2628a2cbb3104b0ebc.patch";
+      hash = "sha256-br99n2nDLjUfnjbjhOsWlvP62VmVjYeZ6yPs1dhPN/s=";
+    })
+
+    # Remove when https://gitlab.com/ubports/development/core/lomiri-thumbnailer/-/merge_requests/22 merged & in release
+    (fetchpatch {
+      name = "0002-lomiri-thumbnailer-Make-tests-optional.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-thumbnailer/-/commit/df7a3d1689f875d207a90067b957e888160491b9.patch";
+      hash = "sha256-gVxigpSL/3fXNdJBjh8Ex3/TYmQUiwRji/NmLW/uhE4=";
+    })
+
+    # Remove when https://gitlab.com/ubports/development/core/lomiri-thumbnailer/-/merge_requests/23 merged & in release
+    (fetchpatch {
+      name = "0003-lomiri-thumbnailer-doc-liblomiri-thumbnailer-qt-Honour-CMAKE_INSTALL_DOCDIR.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-thumbnailer/-/commit/930a3b57e899f6eb65a96d096edaea6a6f6b242a.patch";
+      hash = "sha256-klYycUoQqA+Dfk/4fRQgdS4/G4o0sC1k98mbtl0iHkE=";
+    })
+    (fetchpatch {
+      name = "0004-lomiri-thumbnailer-Re-enable-documentation.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-thumbnailer/-/commit/2f9186f71fdd25e8a0852073f1da59ba6169cf3f.patch";
+      hash = "sha256-youaJfCeYVpLmruHMupuUdl0c/bSDPWqKPLgu5plBrw=";
+    })
+    (fetchpatch {
+      name = "0005-lomiri-thumbnailer-doc-liblomiri-thumbnailer-qt-examples-Drop-qt5_use_modules-usage.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-thumbnailer/-/commit/9e5cf09de626e73e6b8f180cbc1160ebd2f169e7.patch";
+      hash = "sha256-vfNCN7tqq6ngzNmb3qqHDHaDx/kI8/UXyyv7LqUWya0=";
+    })
+    (fetchpatch {
+      name = "0006-lomiri-thumbnailer-Re-enable-coverge-reporting.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-thumbnailer/-/commit/6a48831f042cd3ad34200f32800393d4eec2f84b.patch";
+      hash = "sha256-HZd4K0R1W6adOjKy7tODfQAD+9IKPcK0DnH1uKNd/Ak=";
+    })
+    (fetchpatch {
+      name = "0007-lomiri-thumbnailer-Make-GTest-available-to-example-test.patch";
+      url = "https://gitlab.com/ubports/development/core/lomiri-thumbnailer/-/commit/657be3bd1aeb227edc04e26b597b2fe97b2dc51a.patch";
+      hash = "sha256-XEvdWV3JJujG16+87iewYor0jFK7NTeE5459iT96SkU=";
+    })
+    (fetchpatch {
+      name = "0008-fix-googletest-1-13.patch";
+      url = "https://salsa.debian.org/ubports-team/lomiri-thumbnailer/-/raw/debian/3.0.3-1/debian/patches/0001_fix_googletest_1_13.patch";
+      hash = "sha256-oBcdspQMhCxh4L/XotG9NRp/Ij2YzIjpC8xg/jdiptw=";
+    })
+  ];
+
+  postPatch = ''
+    patchShebangs tools/{parse-settings.py,run-xvfb.sh} tests/{headers,whitespace,server}/*.py
+
+    substituteInPlace tests/thumbnailer-admin/thumbnailer-admin_test.cpp \
+      --replace '/usr/bin/test' 'test'
+
+    substituteInPlace plugins/*/Thumbnailer*/CMakeLists.txt \
+      --replace "\''${CMAKE_INSTALL_LIBDIR}/qt5/qml" "\''${CMAKE_INSTALL_PREFIX}/${qtbase.qtQmlPrefix}"
+
+    # I think this variable fails to be populated because of our toolchain, while upstream uses Debian / Ubuntu where this works fine
+    # https://cmake.org/cmake/help/v3.26/variable/CMAKE_LIBRARY_ARCHITECTURE.html
+    # > If the <LANG> compiler passes to the linker an architecture-specific system library search directory such as
+    # > <prefix>/lib/<arch> this variable contains the <arch> name if/as detected by CMake.
+    substituteInPlace tests/qml/CMakeLists.txt \
+      --replace 'CMAKE_LIBRARY_ARCHITECTURE' 'CMAKE_SYSTEM_PROCESSOR' \
+      --replace 'powerpc-linux-gnu' 'ppc' \
+      --replace 's390x-linux-gnu' 's390x'
+
+    # Tests run in parallel to other builds, don't suck up cores
+    substituteInPlace tests/headers/compile_headers.py \
+      --replace 'max_workers=multiprocessing.cpu_count()' "max_workers=1"
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    doxygen
+    gdk-pixbuf # setup hook
+    pkg-config
+    (python3.withPackages (ps: with ps; lib.optionals finalAttrs.doCheck [
+      python-dbusmock
+      tornado
+    ]))
+    validatePkgConfig
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    boost
+    cmake-extras
+    gdk-pixbuf
+    libapparmor
+    libexif
+    librsvg
+    lomiri-api
+    persistent-cache-cpp
+    qtbase
+    qtdeclarative
+    shared-mime-info
+    taglib
+  ] ++ (with gst_all_1; [
+    gstreamer
+    gst-plugins-base
+    gst-plugins-good
+    gst-plugins-bad
+    # maybe add ugly to cover all kinds of formats?
+  ]);
+
+  nativeCheckInputs = [
+    shared-mime-info
+    xvfb-run
+  ];
+
+  checkInputs = [
+    gtest
+    libqtdbustest
+  ];
+
+  dontWrapQtApps = true;
+
+  cmakeFlags = [
+    (lib.cmakeBool "GSETTINGS_LOCALINSTALL" true)
+    (lib.cmakeBool "GSETTINGS_COMPILE" true)
+    # error: use of old-style cast to 'std::remove_reference<_GstElement*>::type' {aka 'struct _GstElement*'}
+    (lib.cmakeBool "Werror" false)
+    (lib.cmakeFeature "CMAKE_CTEST_ARGUMENTS" (lib.concatStringsSep ";" [
+      # QSignalSpy tests in QML suite always fail, pass when running interactively
+      "-E" "^qml"
+    ]))
+  ];
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  enableParallelChecking = false;
+
+  preCheck = ''
+    # Fontconfig warnings breaks some tests
+    export FONTCONFIG_FILE=${makeFontsConf { fontDirectories = []; }}
+    export HOME=$TMPDIR
+
+    # Some tests need Qt plugins
+    export QT_PLUGIN_PATH=${lib.getBin qtbase}/${qtbase.qtPluginPrefix}
+
+    # QML tests need QML modules
+    export QML2_IMPORT_PATH=${lib.getBin qtdeclarative}/${qtbase.qtQmlPrefix}
+  '';
+
+  preFixup = ''
+    gappsWrapperArgs+=(
+      --prefix XDG_DATA_DIRS : ${lib.makeSearchPath "share" [ shared-mime-info ]}
+    )
+  '';
+
+  passthru = {
+    tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "D-Bus service for out of process thumbnailing";
+    mainProgram = "lomiri-thumbnailer-admin";
+    homepage = "https://gitlab.com/ubports/development/core/lomiri-thumbnailer";
+    changelog = "https://gitlab.com/ubports/development/core/lomiri-thumbnailer/-/blob/${finalAttrs.version}/ChangeLog";
+    license = with licenses; [ gpl3Only lgpl3Only ];
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+    pkgConfigModules = [
+      "liblomiri-thumbnailer-qt"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/services/lomiri-url-dispatcher/default.nix b/nixpkgs/pkgs/desktops/lomiri/services/lomiri-url-dispatcher/default.nix
new file mode 100644
index 000000000000..7629da2cbb84
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/services/lomiri-url-dispatcher/default.nix
@@ -0,0 +1,169 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, fetchpatch
+, gitUpdater
+, testers
+, cmake
+, cmake-extras
+, dbus
+, dbus-test-runner
+, glib
+, gtest
+, intltool
+, json-glib
+, libapparmor
+, libxkbcommon
+, lomiri-app-launch
+, lomiri-ui-toolkit
+, makeWrapper
+, pkg-config
+, python3
+, qtbase
+, qtdeclarative
+, qtwayland
+, runtimeShell
+, sqlite
+, systemd
+, wrapQtAppsHook
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "lomiri-url-dispatcher";
+  version = "0.1.3";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/lomiri-url-dispatcher";
+    rev = finalAttrs.version;
+    hash = "sha256-kde/HzhBHxTeyc2TCUJwpG7IfC8doDd/jNMF8KLM7KU=";
+  };
+
+  outputs = [
+    "out"
+    "dev"
+  ];
+
+  patches = [
+    # Fix case-sensitivity in tests
+    # Remove when https://gitlab.com/ubports/development/core/lomiri-url-dispatcher/-/merge_requests/8 merged & in release
+    (fetchpatch {
+      url = "https://gitlab.com/sunweaver/lomiri-url-dispatcher/-/commit/ebdd31b9640ca243e90bc7b8aca7951085998bd8.patch";
+      hash = "sha256-g4EohB3oDcWK4x62/3r/g6CFxqb7/rdK51+E/Fji1Do=";
+    })
+  ];
+
+  postPatch = ''
+    substituteInPlace data/CMakeLists.txt \
+      --replace "\''${SYSTEMD_USER_UNIT_DIR}" "\''${CMAKE_INSTALL_LIBDIR}/systemd/user"
+
+    substituteInPlace tests/url_dispatcher_testability/CMakeLists.txt \
+      --replace "\''${PYTHON_PACKAGE_DIR}" "$out/${python3.sitePackages}"
+
+    # Update URI handler database whenever new url-handler is installed system-wide
+    substituteInPlace data/lomiri-url-dispatcher-update-system-dir.*.in \
+      --replace '@CMAKE_INSTALL_FULL_DATAROOTDIR@' '/run/current-system/sw/share'
+  '' + lib.optionalString finalAttrs.finalPackage.doCheck ''
+    patchShebangs tests/test-sql.sh
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    glib # for gdbus-codegen
+    intltool
+    makeWrapper
+    pkg-config
+    (python3.withPackages (ps: with ps; [
+      setuptools
+    ] ++ lib.optionals finalAttrs.finalPackage.doCheck [
+      python-dbusmock
+    ]))
+    wrapQtAppsHook
+  ];
+
+  buildInputs = [
+    cmake-extras
+    dbus-test-runner
+    glib
+    gtest
+    json-glib
+    libapparmor
+    lomiri-app-launch
+    lomiri-ui-toolkit
+    qtdeclarative
+    sqlite
+    systemd
+    libxkbcommon
+  ];
+
+  nativeCheckInputs = [
+    dbus
+    sqlite
+  ];
+
+  cmakeFlags = [
+    "-DLOCAL_INSTALL=ON"
+    "-Denable_mirclient=OFF"
+  ];
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  # Tests work with an sqlite db, cannot handle >1 test at the same time
+  enableParallelChecking = false;
+
+  dontWrapQtApps = true;
+
+  preFixup = ''
+    substituteInPlace $out/bin/lomiri-url-dispatcher-dump \
+      --replace '/bin/sh' '${runtimeShell}'
+
+    wrapProgram $out/bin/lomiri-url-dispatcher-dump \
+      --prefix PATH : ${lib.makeBinPath [ sqlite ]}
+
+    # Move from qmlscene call in desktop file to easier-to-wrap script
+    guiScript=$out/bin/lomiri-url-dispatcher-gui
+    guiExec=$(grep 'Exec=' $out/share/applications/lomiri-url-dispatcher-gui.desktop | cut -d'=' -f2-)
+
+    cat <<EOF >$guiScript
+    #!${runtimeShell}
+    $guiExec
+    EOF
+    chmod +x $guiScript
+
+    mkdir -p $out/share/icons/hicolor/scalable/apps
+    ln -s $out/share/lomiri-url-dispatcher/gui/lomiri-url-dispatcher-gui.svg $out/share/icons/hicolor/scalable/apps/
+
+    substituteInPlace $out/share/applications/lomiri-url-dispatcher-gui.desktop \
+      --replace "Exec=$guiExec" "Exec=$(basename $guiScript)" \
+      --replace "Icon=$out/share/lomiri-url-dispatcher/gui/lomiri-url-dispatcher-gui.svg" "Icon=lomiri-url-dispatcher-gui"
+
+    # Calls qmlscene from PATH, needs Qt plugins & QML components
+    qtWrapperArgs+=(
+      --prefix PATH : ${lib.makeBinPath [ qtdeclarative.dev ]}
+    )
+    wrapQtApp $guiScript
+  '';
+
+  passthru = {
+    tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "Lomiri operating environment service for requesting URLs to be opened";
+    longDescription = ''
+       Allows applications to request a URL to be opened and handled by another
+       process without seeing the list of other applications on the system or
+       starting them inside its own Application Confinement.
+    '';
+    homepage = "https://gitlab.com/ubports/development/core/lomiri-url-dispatcher";
+    license = with licenses; [ lgpl3Only gpl3Only ];
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+    pkgConfigModules = [
+      "lomiri-url-dispatcher"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/services/mediascanner2/default.nix b/nixpkgs/pkgs/desktops/lomiri/services/mediascanner2/default.nix
new file mode 100644
index 000000000000..d9470668ce1d
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/services/mediascanner2/default.nix
@@ -0,0 +1,122 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, gitUpdater
+, testers
+, boost
+, cmake
+, cmake-extras
+, dbus
+, dbus-cpp
+, gdk-pixbuf
+, glib
+, gst_all_1
+, gtest
+, libapparmor
+, libexif
+, pkg-config
+, properties-cpp
+, qtbase
+, qtdeclarative
+, shared-mime-info
+, sqlite
+, taglib
+, udisks
+, wrapQtAppsHook
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "mediascanner2";
+  version = "0.115";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/mediascanner2";
+    rev = finalAttrs.version;
+    hash = "sha256-UEwFe65VB2asxQhuWGEAVow/9rEvZxry4dd2/60fXN4=";
+  };
+
+  outputs = [
+    "out"
+    "dev"
+  ];
+
+  postPatch = ''
+    substituteInPlace src/qml/MediaScanner.*/CMakeLists.txt \
+      --replace "\''${CMAKE_INSTALL_LIBDIR}/qt5/qml" "\''${CMAKE_INSTALL_PREFIX}/${qtbase.qtQmlPrefix}"
+
+    # Lomiri desktop doesn't identify itself under Canonical's name anymore
+    substituteInPlace src/daemon/scannerdaemon.cc \
+      --replace 'Unity8' 'Lomiri'
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    gst_all_1.gstreamer # GST_PLUGIN_SYSTEM_PATH_1_0 setup hook
+    pkg-config
+    wrapQtAppsHook
+  ];
+
+  buildInputs = [
+    boost
+    cmake-extras
+    dbus
+    dbus-cpp
+    gdk-pixbuf
+    glib
+    libapparmor
+    libexif
+    properties-cpp
+    qtbase
+    qtdeclarative
+    shared-mime-info
+    sqlite
+    taglib
+    udisks
+  ] ++ (with gst_all_1; [
+    gstreamer
+    gst-plugins-base
+    gst-plugins-good
+  ]);
+
+  checkInputs = [
+    gtest
+  ];
+
+  cmakeFlags = [
+    "-DENABLE_TESTS=${lib.boolToString finalAttrs.doCheck}"
+  ];
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  preCheck = ''
+    export QT_PLUGIN_PATH=${lib.getBin qtbase}/${qtbase.qtPluginPrefix}
+    export XDG_DATA_DIRS=${shared-mime-info}/share:$XDG_DATA_DIRS
+  '';
+
+  preFixup = ''
+    qtWrapperArgs+=(
+      --prefix GST_PLUGIN_SYSTEM_PATH_1_0 : "$GST_PLUGIN_SYSTEM_PATH_1_0"
+      --prefix XDG_DATA_DIRS : ${shared-mime-info}/share
+    )
+  '';
+
+  passthru = {
+    tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "Media scanner service & access library";
+    homepage = "https://gitlab.com/ubports/development/core/mediascanner2";
+    license = licenses.gpl3Only;
+    maintainers = teams.lomiri.members;
+    mainProgram = "mediascanner-service-2.0";
+    platforms = platforms.linux;
+    pkgConfigModules = [
+      "mediascanner-2.0"
+    ];
+  };
+})
diff --git a/nixpkgs/pkgs/desktops/lomiri/services/telephony-service/default.nix b/nixpkgs/pkgs/desktops/lomiri/services/telephony-service/default.nix
new file mode 100644
index 000000000000..975f96bce992
--- /dev/null
+++ b/nixpkgs/pkgs/desktops/lomiri/services/telephony-service/default.nix
@@ -0,0 +1,201 @@
+{ stdenv
+, lib
+, fetchFromGitLab
+, fetchpatch
+, fetchpatch2
+, gitUpdater
+, nixosTests
+, ayatana-indicator-messages
+, bash
+, cmake
+, dbus
+, dbus-glib
+, dbus-test-runner
+, dconf
+, gettext
+, glib
+, gnome
+, history-service
+, libnotify
+, libphonenumber
+, libpulseaudio
+, libusermetrics
+, lomiri-ui-toolkit
+, lomiri-url-dispatcher
+, makeWrapper
+, pkg-config
+, protobuf
+, python3
+, qtbase
+, qtdeclarative
+, qtfeedback
+, qtmultimedia
+, qtpim
+, telepathy
+, telepathy-glib
+, telepathy-mission-control
+, xvfb-run
+}:
+
+let
+  replaceDbusService = pkg: name: "--replace \"\\\${DBUS_SERVICES_DIR}/${name}\" \"${pkg}/share/dbus-1/services/${name}\"";
+in
+stdenv.mkDerivation (finalAttrs: {
+  pname = "telephony-service";
+  version = "0.5.3";
+
+  src = fetchFromGitLab {
+    owner = "ubports";
+    repo = "development/core/telephony-service";
+    rev = finalAttrs.version;
+    hash = "sha256-eLGwAJmBDDvSODQUNr/zcPA/0DdXtVBiS7vg+iIYPDo=";
+  };
+
+  patches = [
+    # Remove when https://gitlab.com/ubports/development/core/telephony-service/-/merge_requests/90 merged & in release
+    (fetchpatch {
+      name = "0001-telephony-service-CMakeLists-Make-tests-optional.patch";
+      url = "https://gitlab.com/ubports/development/core/telephony-service/-/commit/9a8297bcf9b34d77ffdae3dfe4ad2636022976fb.patch";
+      hash = "sha256-Za4ZGKnw9iz2RP1LzLhKrEJ1vLUufWk8J07LmWDW40E=";
+    })
+  ];
+
+  postPatch = ''
+    # Queries qmake for the QML installation path, which returns a reference to Qt5's build directory
+    substituteInPlace CMakeLists.txt \
+      --replace "\''${QMAKE_EXECUTABLE} -query QT_INSTALL_QML" "echo $out/${qtbase.qtQmlPrefix}"
+
+  '' + lib.optionalString finalAttrs.finalPackage.doCheck ''
+    substituteInPlace tests/common/dbus-services/CMakeLists.txt \
+      ${replaceDbusService telepathy-mission-control "org.freedesktop.Telepathy.MissionControl5.service"} \
+      ${replaceDbusService telepathy-mission-control "org.freedesktop.Telepathy.AccountManager.service"} \
+      ${replaceDbusService dconf "ca.desrt.dconf.service"}
+
+    substituteInPlace cmake/modules/GenerateTest.cmake \
+      --replace '/usr/lib/dconf' '${lib.getLib dconf}/libexec' \
+      --replace '/usr/lib/telepathy' '${lib.getLib telepathy-mission-control}/libexec'
+  '';
+
+  strictDeps = true;
+
+  nativeBuildInputs = [
+    cmake
+    pkg-config
+    makeWrapper
+  ];
+
+  buildInputs = [
+    ayatana-indicator-messages
+    bash
+    dbus-glib
+    dbus
+    dconf
+    gettext
+    glib
+    history-service
+    libnotify
+    libphonenumber
+    libpulseaudio
+    libusermetrics
+    lomiri-url-dispatcher
+    protobuf
+    (python3.withPackages (ps: with ps; [
+      dbus-python
+      pygobject3
+    ]))
+    qtbase
+    qtdeclarative
+    qtfeedback
+    qtmultimedia
+    qtpim
+    telepathy
+    telepathy-glib
+    telepathy-mission-control
+  ];
+
+  nativeCheckInputs = [
+    dbus-test-runner
+    dconf
+    gnome.gnome-keyring
+    telepathy-mission-control
+    xvfb-run
+  ];
+
+  dontWrapQtApps = true;
+
+  cmakeFlags = [
+    # These rely on libphonenumber reformatting inputs to certain results
+    # Seem to be broken for a small amount of numbers, maybe libphonenumber version change?
+    (lib.cmakeBool "SKIP_QML_TESTS" true)
+    (lib.cmakeFeature "CMAKE_CTEST_ARGUMENTS" (lib.concatStringsSep ";" [
+      # Exclude tests
+      "-E" (lib.strings.escapeShellArg "(${lib.concatStringsSep "|" [
+        # Flaky, randomly failing to launch properly & stuck until test timeout
+        "^HandlerTest"
+        "^OfonoAccountEntryTest"
+        "^TelepathyHelperSetupTest"
+        "^AuthHandlerTest"
+        "^ChatManagerTest"
+      ]})")
+    ]))
+  ];
+
+  env.NIX_CFLAGS_COMPILE = toString ([
+    "-I${lib.getDev telepathy-glib}/include/telepathy-1.0" # it's in telepathy-farstream's Requires.private, so it & its dependencies don't get pulled in
+    "-I${lib.getDev dbus-glib}/include/dbus-1.0" # telepathy-glib dependency
+    "-I${lib.getDev dbus}/include/dbus-1.0" # telepathy-glib dependency
+  ]);
+
+  doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
+
+  # Starts & talks to D-Bus services, breaks with parallelism
+  enableParallelChecking = false;
+
+  preCheck = ''
+    export QT_QPA_PLATFORM=minimal
+    export QT_PLUGIN_PATH=${lib.makeSearchPathOutput "bin" qtbase.qtPluginPrefix [ qtbase qtpim ]}
+  '';
+
+  postInstall = ''
+    patchShebangs $out/bin/{ofono-setup,phone-gsettings-migration.py}
+
+    # Still missing getprop from libhybris, we don't have it packaged (yet?)
+    wrapProgram $out/bin/ofono-setup \
+      --prefix PATH : ${lib.makeBinPath [ dbus dconf gettext glib telepathy-mission-control ]}
+
+    # These SystemD services are referenced by the installed D-Bus services, but not part of the installation. Why?
+    for service in telephony-service-{approver,indicator}; do
+      install -Dm644 ../debian/telephony-service."$service".user.service $out/lib/systemd/user/"$service".service
+
+      # ofono-setup.service would be rovided by ubuntu-touch-session, we don't plan to package it
+      substituteInPlace $out/lib/systemd/user/"$service".service \
+        --replace '/usr' "$out" \
+        --replace 'Requires=ofono-setup.service' "" \
+        --replace 'After=ofono-setup.service' "" \
+
+      sed -i $out/lib/systemd/user/"$service".service \
+        -e '/ofono-setup.service/d'
+    done
+
+    # Parses the call & SMS indicator desktop files & tries to find its own executable in PATH
+    wrapProgram $out/bin/telephony-service-indicator \
+      --prefix PATH : "$out/bin"
+  '';
+
+  passthru = {
+    ayatana-indicators = [
+      "telephony-service-indicator"
+    ];
+    tests.vm = nixosTests.ayatana-indicators;
+    updateScript = gitUpdater { };
+  };
+
+  meta = with lib; {
+    description = "Backend dispatcher service for various mobile phone related operations";
+    homepage = "https://gitlab.com/ubports/development/core/telephony-service";
+    changelog = "https://gitlab.com/ubports/development/core/telephony-service/-/blob/${finalAttrs.version}/ChangeLog";
+    license = licenses.gpl3Only;
+    maintainers = teams.lomiri.members;
+    platforms = platforms.linux;
+  };
+})