diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2ecfa17c..8a6775db 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -143,3 +143,56 @@ linting:
- apk update && apk add clang make git
script:
- make lint
+
+appimage-amd64:
+ stage: build
+ image: appimagecrafters/appimage-builder
+ tags: [docker]
+ before_script:
+ # app build requirements
+ - echo 'deb http://archive.neon.kde.org/user/ bionic main' > /etc/apt/sources.list.d/neon.list
+ - wget -qO - https://archive.neon.kde.org/public.key | apt-key add -
+ - apt-get update
+ - apt-get install -y git wget curl
+
+ # update appimage-builder (optional)
+ - pip3 install --upgrade git+https://www.opencode.net/azubieta/appimagecraft.git
+
+ - apt-get install -y qt5-default qtdeclarative5-dev qttools5-dev qtscript5-dev qtquickcontrols2-5-dev qtmultimedia5-dev libqt5svg5-dev liblmdb-dev libssl-dev git ninja-build qt5keychain-dev libgtest-dev ccache
+ - wget https://github.com/Kitware/CMake/releases/download/v3.19.0/cmake-3.19.0-Linux-x86_64.sh && sh cmake-3.19.0-Linux-x86_64.sh --skip-license --prefix=/usr/local
+ - /usr/sbin/update-ccache-symlinks
+ script:
+ - export PATH="/usr/local/bin/:/usr/lib/ccache:${PATH}"
+ - export CMAKE_BUILD_PARALLEL_LEVEL=$(cat /proc/cpuinfo | awk '/^processor/{print $3}' | wc -l)
+ - cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -GNinja
+ -DHUNTER_ROOT=".hunter"
+ -DHUNTER_ENABLED=ON -DBUILD_SHARED_LIBS=OFF
+ -DHUNTER_CONFIGURATION_TYPES=Release
+ -DUSE_BUNDLED_BOOST=ON
+ -DUSE_BUNDLED_SPDLOG=ON
+ -DUSE_BUNDLED_OLM=ON
+ -DUSE_BUNDLED_GTEST=OFF
+ -DUSE_BUNDLED_CMARK=ON
+ -DUSE_BUNDLED_JSON=ON
+ -DUSE_BUNDLED_OPENSSL=OFF
+ -DUSE_BUNDLED_MTXCLIENT=ON
+ -DUSE_BUNDLED_LMDB=OFF
+ -DUSE_BUNDLED_LMDBXX=ON
+ -DUSE_BUNDLED_TWEENY=ON
+ -DUSE_BUNDLED_QTKEYCHAIN=OFF
+ - DESTDIR=`pwd`/AppDir ninja -C build install/local
+ - DESTDIR=`pwd`/AppDir ninja -C build _deps/cmark-build/src/install
+ - mkdir -p AppDir/usr/lib/x86_64-linux-gnu AppDir/lib/x86_64-linux-gnu
+ - appimage-builder --skip-test
+ after_script:
+ - bash ./.ci/upload-nightly-gitlab.sh nheko-latest-x86_64.AppImage
+ artifacts:
+ paths:
+ - 'nheko-latest-x86_64.AppImage'
+ expire_in: 1 week
+ expose_as: 'appimage-amd64'
+ cache:
+ key: "$CI_JOB_NAME"
+ paths:
+ - .hunter/
+ - .ccache
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 935e7c6f..00000000
--- a/.travis.yml
+++ /dev/null
@@ -1,99 +0,0 @@
-language: cpp
-sudo: required
-dist: xenial
-
-notifications:
- webhooks:
- urls:
- - https://scalar.vector.im/api/neb/services/hooks/dHJhdmlzLWNpLyU0MHJlZF9za3klM0FuaGVrby5pbS8lMjFVYkNtSWxHVEhOSWdJUlpjcHQlM0FuaGVrby5pbQ
- on_success: always
- on_failure: always
- on_start: never
- email: false
-
-cache:
- directories:
- - .hunter
-
-matrix:
- include:
- - os: linux
- compiler: gcc-7
- env:
- - CXX=g++-7
- - CC=gcc-7
- - QT_PKG=512
- - DEPLOYMENT=1
- addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- - sourceline: 'ppa:beineri/opt-qt-5.12.6-xenial'
- packages:
- - g++-7
- - ninja-build
- - qt512base
- - qt512tools
- - qt512svg
- - qt512multimedia
- - qt512quickcontrols2
- - qt512graphicaleffects
- - liblmdb-dev
- - libgl1-mesa-dev # needed for missing gl.h
- - os: linux
- compiler: clang-6
- env:
- - CXX=clang++-6.0
- - CC=clang-6.0
- - QT_PKG=510
- addons:
- apt:
- sources:
- - ubuntu-toolchain-r-test
- - llvm-toolchain-xenial-6.0
- - sourceline: 'ppa:beineri/opt-qt-5.10.1-xenial'
- packages:
- - clang++-6.0
- - g++-7
- - ninja-build
- - qt510base
- - qt510tools
- - qt510svg
- - qt510multimedia
- - qt510quickcontrols2
- - qt510graphicaleffects
- - liblmdb-dev
- - libgl1-mesa-dev # needed for missing gl.h
-
-before_install:
- # Use TRAVIS_TAG if defined, or the short commit SHA otherwise
- - export VERSION=${TRAVIS_TAG:-$(git rev-parse --short HEAD)}
-install:
- - ./.ci/install.sh
- - export PATH=/usr/local/bin:${PATH}
-
-script:
- - ./.ci/script.sh
- - sed -i -e "s/VERSION_NAME_VALUE/${VERSION}/g" ./.ci/bintray-release.json || true
- - cp ./.ci/bintray-release.json .
-deploy:
-- provider: script
- script: ./.ci/upload-nightly.sh
- skip_cleanup: true
- on:
- condition: "$DEPLOYMENT == 1"
- repo: Nheko-Reborn/nheko
- tags: false
- all_branches: true
-- skip_cleanup: true
- overwrite: true
- provider: releases
- api_key:
- secure: "rDFG4DIwIG+A9R8seQ3SIXfWOWhJgJHlNQHtAsnfRrPOSIpI7kMebHLDO5sBPNaJ+9MH9acVTJZOabVLf0DdPqRsDUw/PN28aiiqbaH9+zAGOTxahaQ222Gz/ROf/iXvDoTDUnUzURqQUA0YlHy89Z1CnO7TKwlsYhA5A8n0biG7d8i7vQayvwYXfxlk7CouK+Y86ana4r54j1emGRg97p7BOhORibg54ZD520hN0Iif7EJM2hQDTWKZzTDdBt3mF1kBr7cBbuBHWuvE+eIFO3F3yi+u7ggHzw5FaAv245N4fhkpYUl/mSbhLrQG2NOnkglFCpQ2lLd6mWdXHwUNrxN/j+UPewmLg7CymY25zkiL43deDsT8KmpzYalmdaevCqEaX2VehuBzblmH4Re8wnXqBrab14fq0TNDfPqC+NKxy75mdxszbKBC55nTlTB+hsox43dvfvyXDSON4qAzwe9Q/tfp8mL2mehcM868vhw5cbNIskKT8SrhMwmA+sxoqnqLsmAjNVJVTgg6ppbMhjNMOBTndblRHfH6bxsgpTXPtnzC17o9Mw1WgF63eOWNYBEj2wW5ZvWX95Gvg5YzvsF178ipHZDqZfA62ShB3b89fcqN5SOxBsE8UYoHjQIHxQdWeKv23iFwmT8fWAOD8sKDcRyz0WCgidZ1/RjLqsU="
- file_glob: true
- file:
- - nheko-${VERSION}-x86_64.AppImage
- on:
- condition: "$TRAVIS_OS_NAME == linux && $DEPLOYMENT == 1"
- repo: Nheko-Reborn/nheko
- tags: true
diff --git a/AppImageBuilder.yml b/AppImageBuilder.yml
new file mode 100644
index 00000000..7b263058
--- /dev/null
+++ b/AppImageBuilder.yml
@@ -0,0 +1,122 @@
+# appimage-builder recipe see https://appimage-builder.readthedocs.io for details
+version: 1
+AppDir:
+ path: ./AppDir
+ app_info:
+ id: nheko
+ name: nheko
+ icon: nheko
+ version: latest
+ exec: usr/bin/nheko
+ exec_args: $@
+ runtime:
+ env:
+ APPDIR_LIBRARY_PATH: $APPDIR/usr/lib/x86_64-linux-gnu:$APPDIR/usr/lib/x86_64-linux-gnu/gstreamer-1.0:$APPDIR/usr/lib/x86_64-linux-gnu/gconv:$APPDIR/lib/x86_64-linux-gnu:$APPDIR/usr/lib/x86_64-linux-gnu/pulseaudio
+ apt:
+ arch: amd64
+ allow_unauthenticated: true
+ sources:
+ - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ bionic main restricted
+ - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ bionic-updates main restricted
+ - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ bionic universe
+ - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ bionic-updates universe
+ - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ bionic multiverse
+ - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ bionic-updates multiverse
+ - sourceline: deb http://de.archive.ubuntu.com/ubuntu/ bionic-backports main restricted
+ universe multiverse
+ - sourceline: deb http://security.ubuntu.com/ubuntu bionic-security main restricted
+ - sourceline: deb http://security.ubuntu.com/ubuntu bionic-security universe
+ - sourceline: deb http://security.ubuntu.com/ubuntu bionic-security multiverse
+ - sourceline: deb http://archive.neon.kde.org/user/ bionic main
+ include:
+ - gstreamer1.0-libav
+ - gstreamer1.0-plugins-bad
+ - gstreamer1.0-plugins-base
+ - gstreamer1.0-plugins-good
+ - gstreamer1.0-pulseaudio
+ - gstreamer1.0-x
+ - kimageformat-plugins
+ - libbs2b0
+ - libbz2-1.0
+ - libelf1
+ - libexpat1
+ - libhogweed4
+ - libjpeg-turbo8
+ - libkf5archive5
+ - libllvm10
+ - liblmdb0
+ - liblz4-1
+ - libnorm1
+ - libnss-mdns
+ - libopenexr22
+ - libpcre3
+ - libqt5keychain1
+ - libqt5multimedia5-plugins
+ - libqt5multimediagsttools5
+ - libqt5multimediawidgets5
+ - libqt5quickcontrols2-5
+ - libqt5quicktemplates2-5
+ - libqt5quickwidgets5
+ - libqt5svg5
+ - librubberband2
+ - libsensors4
+ - libsm6
+ - libsnappy1v5
+ - libsystemd0
+ - libwayland-server0
+ - libx264-152
+ - libxau6
+ - libxcb-render-util0
+ - libxcb-sync1
+ - libxcb-xinerama0
+ - libxcb-xkb1
+ - libxcursor1
+ - libxdmcp6
+ - libxext6
+ - libxfixes3
+ - libxrender1
+ - libxshmfence1
+ - libxv1
+ - libxxf86vm1
+ - libzstd1
+ - qml-module-qtgraphicaleffects
+ - qml-module-qtmultimedia
+ - qml-module-qtquick-controls2
+ - qml-module-qtquick-layouts
+ - qml-module-qtquick-templates2
+ - qml-module-qtquick-window2
+ - qml-module-qtquick2
+ - qt5-image-formats-plugins
+ exclude: []
+ files:
+ exclude:
+ - usr/share/man
+ - usr/share/doc/*/README.*
+ - usr/share/doc/*/changelog.*
+ - usr/share/doc/*/NEWS.*
+ - usr/share/doc/*/TODO.*
+ test:
+ fedora:
+ image: appimagecrafters/tests-env:fedora-30
+ command: ./AppRun
+ use_host_x: true
+ debian:
+ image: appimagecrafters/tests-env:debian-stable
+ command: ./AppRun
+ use_host_x: true
+ arch:
+ image: appimagecrafters/tests-env:archlinux-latest
+ command: ./AppRun
+ use_host_x: true
+ centos:
+ image: appimagecrafters/tests-env:centos-7
+ command: ./AppRun
+ use_host_x: true
+ ubuntu:
+ image: appimagecrafters/tests-env:ubuntu-xenial
+ command: ./AppRun
+ use_host_x: true
+AppImage:
+ arch: x86_64
+ update-information: None
+ sign-key: None
diff --git a/src/Cache.cpp b/src/Cache.cpp
index 5d11a178..dac0b23a 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -167,13 +167,14 @@ Cache::Cache(const QString &userId, QObject *parent)
void
Cache::setup()
{
- UserSettings settings;
+ auto settings = UserSettings::instance();
nhlog::db()->debug("setting up cache");
cacheDirectory_ = QString("%1/%2%3")
.arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation))
- .arg(QString::fromUtf8(localUserId_.toUtf8().toHex())).arg(QString::fromUtf8(settings.profile().toUtf8().toHex()));
+ .arg(QString::fromUtf8(localUserId_.toUtf8().toHex()))
+ .arg(QString::fromUtf8(settings->profile().toUtf8().toHex()));
bool isInitial = !QFile::exists(cacheDirectory_);
@@ -186,7 +187,9 @@ Cache::setup()
if (!QDir().mkpath(cacheDirectory_)) {
throw std::runtime_error(
- ("Unable to create state directory:" + cacheDirectory_).toStdString().c_str());
+ ("Unable to create state directory:" + cacheDirectory_)
+ .toStdString()
+ .c_str());
}
}
@@ -575,14 +578,14 @@ Cache::restoreOlmAccount()
void
Cache::storeSecret(const std::string &name, const std::string &secret)
{
- UserSettings settings;
+ auto settings = UserSettings::instance();
QKeychain::WritePasswordJob job(QCoreApplication::applicationName());
job.setAutoDelete(false);
job.setInsecureFallback(true);
- job.setKey(
- "matrix." +
- QString(QCryptographicHash::hash(settings.profile().toUtf8(), QCryptographicHash::Sha256)) +
- "." + name.c_str());
+ job.setKey("matrix." +
+ QString(QCryptographicHash::hash(settings->profile().toUtf8(),
+ QCryptographicHash::Sha256)) +
+ "." + name.c_str());
job.setTextData(QString::fromStdString(secret));
QEventLoop loop;
job.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit);
@@ -600,14 +603,14 @@ Cache::storeSecret(const std::string &name, const std::string &secret)
void
Cache::deleteSecret(const std::string &name)
{
- UserSettings settings;
+ auto settings = UserSettings::instance();
QKeychain::DeletePasswordJob job(QCoreApplication::applicationName());
job.setAutoDelete(false);
job.setInsecureFallback(true);
- job.setKey(
- "matrix." +
- QString(QCryptographicHash::hash(settings.profile().toUtf8(), QCryptographicHash::Sha256)) +
- "." + name.c_str());
+ job.setKey("matrix." +
+ QString(QCryptographicHash::hash(settings->profile().toUtf8(),
+ QCryptographicHash::Sha256)) +
+ "." + name.c_str());
QEventLoop loop;
job.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit);
job.start();
@@ -619,14 +622,14 @@ Cache::deleteSecret(const std::string &name)
std::optional<std::string>
Cache::secret(const std::string &name)
{
- UserSettings settings;
+ auto settings = UserSettings::instance();
QKeychain::ReadPasswordJob job(QCoreApplication::applicationName());
job.setAutoDelete(false);
job.setInsecureFallback(true);
- job.setKey(
- "matrix." +
- QString(QCryptographicHash::hash(settings.profile().toUtf8(), QCryptographicHash::Sha256)) +
- "." + name.c_str());
+ job.setKey("matrix." +
+ QString(QCryptographicHash::hash(settings->profile().toUtf8(),
+ QCryptographicHash::Sha256)) +
+ "." + name.c_str());
QEventLoop loop;
job.connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit);
job.start();
diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp
index bc7b5223..77269008 100644
--- a/src/MainWindow.cpp
+++ b/src/MainWindow.cpp
@@ -56,8 +56,8 @@
MainWindow *MainWindow::instance_ = nullptr;
MainWindow::MainWindow(QWidget *parent)
- : QMainWindow(parent),
- userSettings_{QSharedPointer<UserSettings>{new UserSettings}}
+ : QMainWindow(parent)
+ , userSettings_{UserSettings::instance()}
{
setWindowTitle(0);
setObjectName("MainWindow");
diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp
index 55f666c1..4ca3be49 100644
--- a/src/UserSettingsPage.cpp
+++ b/src/UserSettingsPage.cpp
@@ -50,10 +50,30 @@
#include "config/nheko.h"
-UserSettings::UserSettings() { load(); }
+QSharedPointer<UserSettings> UserSettings::instance_;
+
+UserSettings::UserSettings()
+{
+ connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, [this]() {
+ instance_.clear();
+ });
+}
+
+QSharedPointer<UserSettings>
+UserSettings::instance()
+{
+ return instance_;
+}
+
+void
+UserSettings::initialize(std::optional<QString> profile)
+{
+ instance_.reset(new UserSettings());
+ instance_->load(profile);
+}
void
-UserSettings::load()
+UserSettings::load(std::optional<QString> profile)
{
QSettings settings;
tray_ = settings.value("user/window/tray", false).toBool();
@@ -89,7 +109,11 @@ UserSettings::load()
cameraResolution_ = settings.value("user/camera_resolution", QString()).toString();
cameraFrameRate_ = settings.value("user/camera_frame_rate", QString()).toString();
useStunServer_ = settings.value("user/use_stun_server", false).toBool();
- profile_ = settings.value("user/currentProfile", "").toString();
+
+ if (profile)
+ profile_ = *profile;
+ else
+ profile_ = settings.value("user/currentProfile", "").toString();
QString prefix =
(profile_ != "" && profile_ != "default") ? "profile/" + profile_ + "/" : "";
@@ -527,6 +551,8 @@ UserSettings::save()
settings.setValue("use_stun_server", useStunServer_);
settings.setValue("currentProfile", profile_);
+ settings.endGroup(); // user
+
QString prefix =
(profile_ != "" && profile_ != "default") ? "profile/" + profile_ + "/" : "";
settings.setValue(prefix + "auth/access_token", accessToken_);
@@ -534,8 +560,6 @@ UserSettings::save()
settings.setValue(prefix + "auth/user_id", userId_);
settings.setValue(prefix + "auth/device_id", deviceId_);
- settings.endGroup(); // user
-
settings.sync();
}
diff --git a/src/UserSettingsPage.h b/src/UserSettingsPage.h
index dd1e26d9..af73202e 100644
--- a/src/UserSettingsPage.h
+++ b/src/UserSettingsPage.h
@@ -91,9 +91,12 @@ class UserSettings : public QObject
Q_PROPERTY(QString deviceId READ deviceId WRITE setDeviceId NOTIFY deviceIdChanged)
Q_PROPERTY(QString homeserver READ homeserver WRITE setHomeserver NOTIFY homeserverChanged)
-public:
UserSettings();
+public:
+ static QSharedPointer<UserSettings> instance();
+ static void initialize(std::optional<QString> profile);
+
enum class Presence
{
AutomaticPresence,
@@ -104,7 +107,7 @@ public:
Q_ENUM(Presence)
void save();
- void load();
+ void load(std::optional<QString> profile);
void applyTheme();
void setTheme(QString theme);
void setMessageHoverHighlight(bool state);
@@ -252,6 +255,8 @@ private:
QString accessToken_;
QString deviceId_;
QString homeserver_;
+
+ static QSharedPointer<UserSettings> instance_;
};
class HorizontalLine : public QFrame
diff --git a/src/main.cpp b/src/main.cpp
index 58bdda34..a60c66c4 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -196,17 +196,19 @@ main(int argc, char *argv[])
std::exit(1);
}
- UserSettings settings;
-
if (parser.isSet(configName))
- settings.setProfile(parser.value(configName));
+ UserSettings::initialize(parser.value(configName));
+ else
+ UserSettings::initialize(std::nullopt);
+
+ auto settings = UserSettings::instance().toWeakRef();
QFont font;
- QString userFontFamily = settings.font();
+ QString userFontFamily = settings.lock()->font();
if (!userFontFamily.isEmpty()) {
font.setFamily(userFontFamily);
}
- font.setPointSizeF(settings.fontSize());
+ font.setPointSizeF(settings.lock()->fontSize());
app.setFont(font);
@@ -226,7 +228,7 @@ main(int argc, char *argv[])
// Move the MainWindow to the center
w.move(screenCenter(w.width(), w.height()));
- if (!settings.startInTray() && !settings.tray())
+ if (!settings.lock()->startInTray() && !settings.lock()->tray())
w.show();
QObject::connect(&app, &QApplication::aboutToQuit, &w, [&w]() {
|