Merge pull request #130 from Nheko-Reborn/0.7.0-dev
0.7.0 dev merge to master
|
@ -11,5 +11,7 @@ FILES=$(find src -type f -type f \( -iname "*.cpp" -o -iname "*.h" \))
|
||||||
|
|
||||||
for f in $FILES
|
for f in $FILES
|
||||||
do
|
do
|
||||||
clang-format -i "$f" && git diff --exit-code
|
clang-format -i "$f"
|
||||||
done;
|
done;
|
||||||
|
|
||||||
|
git diff --exit-code
|
||||||
|
|
|
@ -2,14 +2,13 @@
|
||||||
|
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
|
if [ "$FLATPAK" ]; then
|
||||||
|
flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||||
|
flatpak --noninteractive install --user flathub org.kde.Platform//5.14
|
||||||
|
flatpak --noninteractive install --user flathub org.kde.Sdk//5.14
|
||||||
|
exit
|
||||||
|
fi
|
||||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||||
brew update
|
|
||||||
brew install qt5 lmdb clang-format ninja libsodium cmark
|
|
||||||
brew upgrade boost cmake icu4c || true
|
|
||||||
|
|
||||||
brew tap nlohmann/json
|
|
||||||
brew install --with-cmake nlohmann_json
|
|
||||||
|
|
||||||
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
|
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
|
||||||
sudo python get-pip.py
|
sudo python get-pip.py
|
||||||
|
|
||||||
|
@ -21,34 +20,12 @@ fi
|
||||||
|
|
||||||
|
|
||||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||||
|
sudo update-alternatives --install /usr/bin/gcc gcc "/usr/bin/${CC}" 10
|
||||||
|
sudo update-alternatives --install /usr/bin/g++ g++ "/usr/bin/${CXX}" 10
|
||||||
|
|
||||||
if [ -z "$QT_VERSION" ]; then
|
sudo update-alternatives --set gcc "/usr/bin/${CC}"
|
||||||
QT_VERSION="592"
|
sudo update-alternatives --set g++ "/usr/bin/${CXX}"
|
||||||
QT_PKG="59"
|
|
||||||
fi
|
|
||||||
|
|
||||||
wget https://cmake.org/files/v3.12/cmake-3.12.2-Linux-x86_64.sh
|
wget https://cmake.org/files/v3.15/cmake-3.15.5-Linux-x86_64.sh
|
||||||
sudo sh cmake-3.12.2-Linux-x86_64.sh --skip-license --prefix=/usr/local
|
sudo sh cmake-3.15.5-Linux-x86_64.sh --skip-license --prefix=/usr/local
|
||||||
|
|
||||||
mkdir -p build-libsodium
|
|
||||||
( cd build-libsodium
|
|
||||||
curl -L https://download.libsodium.org/libsodium/releases/libsodium-1.0.16.tar.gz -o libsodium-1.0.16.tar.gz
|
|
||||||
tar xfz libsodium-1.0.16.tar.gz
|
|
||||||
cd libsodium-1.0.16/
|
|
||||||
./configure && make && make check && sudo make install )
|
|
||||||
|
|
||||||
sudo add-apt-repository -y ppa:beineri/opt-qt${QT_VERSION}-trusty
|
|
||||||
# needed for git-lfs, otherwise the follow apt update fails.
|
|
||||||
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 6B05F25D762E3157
|
|
||||||
|
|
||||||
# needed for mongodb repository: https://github.com/travis-ci/travis-ci/issues/9037
|
|
||||||
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 0C49F3730359A14518585931BC711F9BA15703C6
|
|
||||||
|
|
||||||
sudo apt update -qq
|
|
||||||
sudo apt install -qq -y \
|
|
||||||
qt${QT_PKG}base \
|
|
||||||
qt${QT_PKG}tools \
|
|
||||||
qt${QT_PKG}svg \
|
|
||||||
qt${QT_PKG}multimedia \
|
|
||||||
liblmdb-dev
|
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -25,8 +25,8 @@ for iconSize in 16 32 48 64 128 256 512; do
|
||||||
done
|
done
|
||||||
|
|
||||||
# Only download the file when not already present
|
# Only download the file when not already present
|
||||||
if ! [ -f linuxdeployqt-continuous-x86_64.AppImage ] ; then
|
if ! [ -f linuxdeployqt-6-x86_64.AppImage ] ; then
|
||||||
wget -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage"
|
wget -c "https://github.com/probonopd/linuxdeployqt/releases/download/6/linuxdeployqt-6-x86_64.AppImage"
|
||||||
fi
|
fi
|
||||||
chmod a+x linuxdeployqt*.AppImage
|
chmod a+x linuxdeployqt*.AppImage
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ unset LD_LIBRARY_PATH
|
||||||
|
|
||||||
ARCH=$(uname -m)
|
ARCH=$(uname -m)
|
||||||
export ARCH
|
export ARCH
|
||||||
LD_LIBRARY_PATH=$(pwd)/.deps/usr/lib/:$LD_LIBRARY_PATH
|
LD_LIBRARY_PATH=$(pwd)/.deps/usr/lib/:/usr/local/lib/:$LD_LIBRARY_PATH
|
||||||
export LD_LIBRARY_PATH
|
export LD_LIBRARY_PATH
|
||||||
|
|
||||||
for res in ./linuxdeployqt*.AppImage
|
for res in ./linuxdeployqt*.AppImage
|
||||||
|
@ -44,12 +44,14 @@ do
|
||||||
linuxdeployqt=$res
|
linuxdeployqt=$res
|
||||||
done
|
done
|
||||||
|
|
||||||
./"$linuxdeployqt" ${DIR}/usr/share/applications/*.desktop -unsupported-allow-new-glibc -bundle-non-qt-libs
|
./"$linuxdeployqt" ${DIR}/usr/share/applications/*.desktop -unsupported-allow-new-glibc -bundle-non-qt-libs -qmldir=./resources/qml -appimage
|
||||||
./"$linuxdeployqt" ${DIR}/usr/share/applications/*.desktop -unsupported-allow-new-glibc -appimage
|
|
||||||
|
|
||||||
chmod +x nheko-*x86_64.AppImage
|
chmod +x nheko-*x86_64.AppImage
|
||||||
|
|
||||||
if [ ! -z "$VERSION" ]; then
|
mkdir artifacts
|
||||||
|
cp nheko-*x86_64.AppImage artifacts/
|
||||||
|
|
||||||
|
if [ -n "$VERSION" ]; then
|
||||||
# commented out for now, as AppImage file appears to already contain the version.
|
# commented out for now, as AppImage file appears to already contain the version.
|
||||||
#mv nheko-*x86_64.AppImage nheko-${VERSION}-x86_64.AppImage
|
#mv nheko-*x86_64.AppImage nheko-${VERSION}-x86_64.AppImage
|
||||||
echo "nheko-${VERSION}-x86_64.AppImage"
|
echo "nheko-${VERSION}-x86_64.AppImage"
|
||||||
|
|
|
@ -16,7 +16,7 @@ PATH=/usr/local/opt/qt/bin/:${PATH}
|
||||||
mkdir -p nheko.app/Contents/Frameworks
|
mkdir -p nheko.app/Contents/Frameworks
|
||||||
find "${ICU_LIB}" -type l -name "*.dylib" -exec cp -a -n {} nheko.app/Contents/Frameworks/ \; || true
|
find "${ICU_LIB}" -type l -name "*.dylib" -exec cp -a -n {} nheko.app/Contents/Frameworks/ \; || true
|
||||||
|
|
||||||
sudo macdeployqt nheko.app -dmg -always-overwrite
|
sudo macdeployqt nheko.app -dmg -always-overwrite -qmldir=../resources/qml/
|
||||||
|
|
||||||
user=$(id -nu)
|
user=$(id -nu)
|
||||||
sudo chown "${user}" nheko.dmg
|
sudo chown "${user}" nheko.dmg
|
||||||
|
@ -25,6 +25,8 @@ PATH=/usr/local/opt/qt/bin/:${PATH}
|
||||||
|
|
||||||
dmgbuild -s ./.ci/macos/settings.json "Nheko" nheko.dmg
|
dmgbuild -s ./.ci/macos/settings.json "Nheko" nheko.dmg
|
||||||
|
|
||||||
if [ ! -z "$VERSION" ]; then
|
if [ -n "$VERSION" ]; then
|
||||||
mv nheko.dmg "nheko-${VERSION}.dmg"
|
mv nheko.dmg "nheko-${VERSION}.dmg"
|
||||||
|
mkdir artifacts
|
||||||
|
cp "nheko-${VERSION}.dmg" artifacts/
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -2,17 +2,25 @@
|
||||||
|
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
|
if [ "$FLATPAK" ]; then
|
||||||
|
mkdir -p build-flatpak
|
||||||
|
cd build-flatpak
|
||||||
|
|
||||||
|
flatpak-builder --ccache --repo=repo --subject="Build of Nheko ${VERSION} `date`" app ../io.github.NhekoReborn.Nheko.json
|
||||||
|
flatpak build-bundle repo nheko-${VERSION}-${ARCH}.flatpak io.github.NhekoReborn.Nheko 0.7.0-dev
|
||||||
|
|
||||||
|
mkdir ../artifacts
|
||||||
|
mv nheko-*.flatpak ../artifacts
|
||||||
|
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||||
export CC=${C_COMPILER}
|
|
||||||
export CXX=${CXX_COMPILER}
|
|
||||||
# make build use all available cores
|
# make build use all available cores
|
||||||
export CMAKE_BUILD_PARALLEL_LEVEL=$(cat /proc/cpuinfo | awk '/^processor/{print $3}' | wc -l)
|
export CMAKE_BUILD_PARALLEL_LEVEL=$(cat /proc/cpuinfo | awk '/^processor/{print $3}' | wc -l)
|
||||||
|
|
||||||
sudo update-alternatives --install /usr/bin/gcc gcc "/usr/bin/${C_COMPILER}" 10
|
export PATH="/usr/local/bin/:${PATH}"
|
||||||
sudo update-alternatives --install /usr/bin/g++ g++ "/usr/bin/${CXX_COMPILER}" 10
|
cmake --version
|
||||||
|
|
||||||
sudo update-alternatives --set gcc "/usr/bin/${C_COMPILER}"
|
|
||||||
sudo update-alternatives --set g++ "/usr/bin/${CXX_COMPILER}"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||||
|
@ -24,27 +32,39 @@ if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||||
export CMAKE_PREFIX_PATH=/usr/local/opt/qt5
|
export CMAKE_PREFIX_PATH=/usr/local/opt/qt5
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Build & install dependencies
|
mkdir -p .deps/usr .hunter
|
||||||
cmake -GNinja -Hdeps -B.deps \
|
|
||||||
-DUSE_BUNDLED_BOOST="${USE_BUNDLED_BOOST}" \
|
|
||||||
-DUSE_BUNDLED_CMARK="${USE_BUNDLED_CMARK}" \
|
|
||||||
-DUSE_BUNDLED_JSON="${USE_BUNDLED_JSON}"
|
|
||||||
cmake --build .deps
|
|
||||||
|
|
||||||
# Build nheko
|
# Build nheko
|
||||||
|
|
||||||
|
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||||
cmake -GNinja -H. -Bbuild \
|
cmake -GNinja -H. -Bbuild \
|
||||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||||
-DCMAKE_INSTALL_PREFIX=.deps/usr
|
-DCMAKE_INSTALL_PREFIX=.deps/usr \
|
||||||
|
-DHUNTER_ROOT=".hunter" \
|
||||||
|
-DHUNTER_ENABLED=ON -DBUILD_SHARED_LIBS=OFF \
|
||||||
|
-DCMAKE_BUILD_TYPE=RelWithDebInfo -DHUNTER_CONFIGURATION_TYPES=RelWithDebInfo \
|
||||||
|
-DCMAKE_PREFIX_PATH=/usr/local/opt/qt5 \
|
||||||
|
-DCI_BUILD=ON
|
||||||
|
else
|
||||||
|
cmake -GNinja -H. -Bbuild \
|
||||||
|
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=.deps/usr \
|
||||||
|
-DHUNTER_ROOT=".hunter" \
|
||||||
|
-DHUNTER_ENABLED=ON -DBUILD_SHARED_LIBS=OFF \
|
||||||
|
-DCMAKE_BUILD_TYPE=RelWithDebInfo -DHUNTER_CONFIGURATION_TYPES=RelWithDebInfo \
|
||||||
|
-DUSE_BUNDLED_OPENSSL=OFF \
|
||||||
|
-DCI_BUILD=ON
|
||||||
|
fi
|
||||||
cmake --build build
|
cmake --build build
|
||||||
|
|
||||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||||
make lint;
|
make lint;
|
||||||
|
|
||||||
if [ "$DEPLOYMENT" = 1 ] && [ ! -z "$VERSION" ] ; then
|
if [ "$DEPLOYMENT" = 1 ] && [ -n "$VERSION" ] ; then
|
||||||
make macos-deploy;
|
make macos-deploy;
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$TRAVIS_OS_NAME" = "linux" ] && [ "$DEPLOYMENT" = 1 ] && [ ! -z "$VERSION" ]; then
|
if [ "$TRAVIS_OS_NAME" = "linux" ] && [ "$DEPLOYMENT" = 1 ] && [ -n "$VERSION" ]; then
|
||||||
make linux-deploy;
|
make linux-deploy;
|
||||||
fi
|
fi
|
||||||
|
|
4
.github/CONTRIBUTING.md
vendored
|
@ -20,9 +20,9 @@ If you're planning to work on a new feature leave a message on the Matrix room
|
||||||
|
|
||||||
Example for a Japanese translation.
|
Example for a Japanese translation.
|
||||||
- Create a new translation file using the prototype in English
|
- Create a new translation file using the prototype in English
|
||||||
- e.g `cp resources/langs/nheko_en.ts resources/langs/nheko_jp.ts`
|
- e.g `cp resources/langs/nheko_en.ts resources/langs/nheko_ja.ts`
|
||||||
- Open the new translation file and change the line regarding the locale to reflect the current language.
|
- Open the new translation file and change the line regarding the locale to reflect the current language.
|
||||||
- e.g `<TS version="2.1" language="en">` => `<TS version="2.1" language="jp">`
|
- e.g `<TS version="2.1" language="en">` => `<TS version="2.1" language="ja">`
|
||||||
- Run `make update-translations` to update the translation files with any missing text.
|
- Run `make update-translations` to update the translation files with any missing text.
|
||||||
- Fill out the translation file (Qt Linguist can make things easier).
|
- Fill out the translation file (Qt Linguist can make things easier).
|
||||||
- Submit a PR!
|
- Submit a PR!
|
||||||
|
|
16
.gitignore
vendored
|
@ -1,7 +1,16 @@
|
||||||
build
|
/build*
|
||||||
tags
|
tags
|
||||||
|
cscope*
|
||||||
.clang_complete
|
.clang_complete
|
||||||
*wintoastlib*
|
*wintoastlib*
|
||||||
|
/.ccls-cache
|
||||||
|
/.exrc
|
||||||
|
.gdb_history
|
||||||
|
|
||||||
|
# GTAGS
|
||||||
|
GTAGS
|
||||||
|
GRTAGS
|
||||||
|
GPATH
|
||||||
|
|
||||||
# C++ objects and libs
|
# C++ objects and libs
|
||||||
|
|
||||||
|
@ -31,6 +40,7 @@ moc_*.cpp
|
||||||
qrc_*.cpp
|
qrc_*.cpp
|
||||||
ui_*.h
|
ui_*.h
|
||||||
*-build-*
|
*-build-*
|
||||||
|
/.clangd/
|
||||||
|
|
||||||
# QtCreator
|
# QtCreator
|
||||||
|
|
||||||
|
@ -43,6 +53,10 @@ ui_*.h
|
||||||
*.qmlproject.user
|
*.qmlproject.user
|
||||||
*.qmlproject.user.*
|
*.qmlproject.user.*
|
||||||
|
|
||||||
|
# Vim
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
#####=== CMake ===#####
|
#####=== CMake ===#####
|
||||||
|
|
||||||
CMakeCache.txt
|
CMakeCache.txt
|
||||||
|
|
164
.travis.yml
|
@ -1,73 +1,138 @@
|
||||||
language: cpp
|
language: cpp
|
||||||
sudo: required
|
sudo: required
|
||||||
dist: trusty
|
dist: xenial
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
webhooks:
|
webhooks:
|
||||||
urls:
|
urls:
|
||||||
- https://scalar.vector.im/api/neb/services/hooks/dHJhdmlzLWNpLyU0MHJlZF9za3klM0FvY2Vhbi5qb2Vkb25vZnJ5LmNvbS8lMjFldkFxa1BIWnVQSElHZWVuaGklM0FvY2Vhbi5qb2Vkb25vZnJ5LmNvbQ
|
- https://scalar.vector.im/api/neb/services/hooks/dHJhdmlzLWNpLyU0MHJlZF9za3klM0FuaGVrby5pbS8lMjFVYkNtSWxHVEhOSWdJUlpjcHQlM0FuaGVrby5pbQ
|
||||||
on_success: always
|
on_success: always
|
||||||
on_failure: always
|
on_failure: always
|
||||||
on_start: never
|
on_start: never
|
||||||
email: false
|
email: false
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- .hunter
|
||||||
|
- build-flatpak/.flatpak-builder
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: osx
|
- os: osx
|
||||||
compiler: clang
|
compiler: clang
|
||||||
osx_image: xcode9
|
# C++17 support
|
||||||
|
osx_image: xcode10.2
|
||||||
env:
|
env:
|
||||||
- DEPLOYMENT=1
|
- DEPLOYMENT=1
|
||||||
- USE_BUNDLED_BOOST=0
|
addons:
|
||||||
- USE_BUNDLED_CMARK=0
|
homebrew:
|
||||||
- USE_BUNDLED_JSON=0
|
taps: nlohmann/json
|
||||||
|
packages:
|
||||||
|
- clang-format
|
||||||
|
- cmake
|
||||||
|
- ninja
|
||||||
|
- openssl
|
||||||
|
- qt5
|
||||||
|
update: true # workaround for broken travis homebrew
|
||||||
- os: linux
|
- os: linux
|
||||||
compiler: gcc
|
compiler: gcc-7
|
||||||
env:
|
env:
|
||||||
- CXX_COMPILER=g++-5
|
- CXX=g++-7
|
||||||
- C_COMPILER=gcc-5
|
- CC=gcc-7
|
||||||
- QT_VERSION="-5.10.1"
|
- QT_PKG=512
|
||||||
- QT_PKG=510
|
|
||||||
- DEPLOYMENT=1
|
- DEPLOYMENT=1
|
||||||
- USE_BUNDLED_BOOST=1
|
|
||||||
- USE_BUNDLED_CMARK=1
|
|
||||||
- USE_BUNDLED_JSON=1
|
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: ["ubuntu-toolchain-r-test"]
|
sources:
|
||||||
packages: ["g++-5", "ninja-build"]
|
- 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
|
- os: linux
|
||||||
compiler: gcc
|
compiler: gcc-8
|
||||||
env:
|
env:
|
||||||
- CXX_COMPILER=g++-8
|
- CXX=g++-8
|
||||||
- C_COMPILER=gcc-8
|
- CC=gcc-8
|
||||||
- QT_VERSION=571
|
|
||||||
- QT_PKG=57
|
|
||||||
- USE_BUNDLED_BOOST=1
|
|
||||||
- USE_BUNDLED_CMARK=1
|
|
||||||
- USE_BUNDLED_JSON=1
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
sources: ["ubuntu-toolchain-r-test"]
|
|
||||||
packages: ["g++-8", "ninja-build"]
|
|
||||||
- os: linux
|
|
||||||
compiler: clang
|
|
||||||
env:
|
|
||||||
- CXX_COMPILER=clang++-5.0
|
|
||||||
- C_COMPILER=clang-5.0
|
|
||||||
- QT_VERSION=592
|
|
||||||
- QT_PKG=59
|
- QT_PKG=59
|
||||||
- USE_BUNDLED_BOOST=1
|
|
||||||
- USE_BUNDLED_CMARK=1
|
|
||||||
- USE_BUNDLED_JSON=1
|
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-5.0"]
|
sources:
|
||||||
packages: ["clang-5.0", "g++-7", "ninja-build"]
|
- ubuntu-toolchain-r-test
|
||||||
|
- sourceline: 'ppa:beineri/opt-qt597-xenial'
|
||||||
|
packages:
|
||||||
|
- g++-8
|
||||||
|
- ninja-build
|
||||||
|
- qt59base
|
||||||
|
- qt59tools
|
||||||
|
- qt59svg
|
||||||
|
- qt59multimedia
|
||||||
|
- qt59quickcontrols2
|
||||||
|
- qt59graphicaleffects
|
||||||
|
- 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=59
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- ubuntu-toolchain-r-test
|
||||||
|
- llvm-toolchain-xenial-6.0
|
||||||
|
- sourceline: 'ppa:beineri/opt-qt597-xenial'
|
||||||
|
packages:
|
||||||
|
- clang++-6.0
|
||||||
|
- g++-7
|
||||||
|
- ninja-build
|
||||||
|
- qt59base
|
||||||
|
- qt59tools
|
||||||
|
- qt59svg
|
||||||
|
- qt59multimedia
|
||||||
|
- qt59quickcontrols2
|
||||||
|
- qt59graphicaleffects
|
||||||
|
- liblmdb-dev
|
||||||
|
- libgl1-mesa-dev # needed for missing gl.h
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
- DEPLOYMENT=1
|
||||||
|
- FLATPAK=1
|
||||||
|
- ARCH=amd64
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- sourceline: 'ppa:alexlarsson/flatpak'
|
||||||
|
packages:
|
||||||
|
- flatpak
|
||||||
|
- flatpak-builder
|
||||||
|
- elfutils
|
||||||
|
- os: linux
|
||||||
|
arch: arm64
|
||||||
|
env:
|
||||||
|
- DEPLOYMENT=1
|
||||||
|
- FLATPAK=1
|
||||||
|
- ARCH=arm64
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- sourceline: 'ppa:alexlarsson/flatpak'
|
||||||
|
packages:
|
||||||
|
- flatpak
|
||||||
|
- flatpak-builder
|
||||||
|
- elfutils
|
||||||
|
- librsvg2-bin
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- export CXX=${CXX_COMPILER}
|
|
||||||
- export CC=${C_COMPILER}
|
|
||||||
# Use TRAVIS_TAG if defined, or the short commit SHA otherwise
|
# Use TRAVIS_TAG if defined, or the short commit SHA otherwise
|
||||||
- export VERSION=${TRAVIS_TAG:-$(git rev-parse --short HEAD)}
|
- export VERSION=${TRAVIS_TAG:-$(git rev-parse --short HEAD)}
|
||||||
install:
|
install:
|
||||||
|
@ -79,6 +144,21 @@ script:
|
||||||
- sed -i -e "s/VERSION_NAME_VALUE/${VERSION}/g" ./.ci/bintray-release.json || true
|
- sed -i -e "s/VERSION_NAME_VALUE/${VERSION}/g" ./.ci/bintray-release.json || true
|
||||||
- cp ./.ci/bintray-release.json .
|
- cp ./.ci/bintray-release.json .
|
||||||
deploy:
|
deploy:
|
||||||
|
- provider: s3
|
||||||
|
access_key_id: $ARTIFACTS_KEY
|
||||||
|
secret_access_key: $ARTIFACTS_SECRET
|
||||||
|
bucket: $ARTIFACTS_BUCKET
|
||||||
|
region: $AWS_DEFAULT_REGION
|
||||||
|
detect_encoding: true
|
||||||
|
cache_control: "max-age=31536000"
|
||||||
|
skip_cleanup: true
|
||||||
|
acl: public_read
|
||||||
|
local_dir: artifacts
|
||||||
|
on:
|
||||||
|
condition: "$DEPLOYMENT == 1"
|
||||||
|
repo: Nheko-Reborn/nheko
|
||||||
|
tags: false
|
||||||
|
all_branches: true
|
||||||
- provider: bintray
|
- provider: bintray
|
||||||
user: "redsky17"
|
user: "redsky17"
|
||||||
key:
|
key:
|
||||||
|
|
19
CHANGELOG.md
|
@ -2,6 +2,25 @@
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### [0.7.0] -- Unreleased
|
||||||
|
|
||||||
|
0.7.0 *requires* mtxclient 0.3.0. Make sure you compile against 0.3.0
|
||||||
|
if you do not use the mtxclient bundled with nheko.
|
||||||
|
|
||||||
|
#### Features
|
||||||
|
- Make nheko session import / export format match riot. Fixes #48 (WIP)
|
||||||
|
- Implement proper replies (WIP)
|
||||||
|
- Add .well-known support for auto-completing homeserver information
|
||||||
|
- Add mentions viewer so you can see all the messages you have been mentioned in (WIP)
|
||||||
|
- Add emoji font selection preference
|
||||||
|
|
||||||
|
#### Improvements
|
||||||
|
- Add dedicated reply button to Timeline items. Add button for other options so
|
||||||
|
that right click isn't always required.
|
||||||
|
- Fix various things with regards to emoji rendering and the emoji picker (WIP)
|
||||||
|
- Lots and lots and lots of localization updates.
|
||||||
|
- Additional tweaks to the system theme
|
||||||
|
|
||||||
## [0.6.4] - 2019-05-22
|
## [0.6.4] - 2019-05-22
|
||||||
|
|
||||||
*Most* of the below fixes are due to updates in mtxclient. Make sure you compile against 0.2.1
|
*Most* of the below fixes are due to updates in mtxclient. Make sure you compile against 0.2.1
|
||||||
|
|
802
CMakeLists.txt
|
@ -1,22 +1,86 @@
|
||||||
cmake_minimum_required(VERSION 3.11)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
option(APPVEYOR_BUILD "Build on appveyor" OFF)
|
option(APPVEYOR_BUILD "Build on appveyor" OFF)
|
||||||
|
option(CI_BUILD "Set when building in CI. Enables -Werror where possible" OFF)
|
||||||
option(ASAN "Compile with address sanitizers" OFF)
|
option(ASAN "Compile with address sanitizers" OFF)
|
||||||
|
option(QML_DEBUGGING "Enable qml debugging" OFF)
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
set(
|
||||||
|
CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/toolchain.cmake"
|
||||||
|
CACHE
|
||||||
|
FILEPATH "Default toolchain"
|
||||||
|
)
|
||||||
|
|
||||||
add_definitions(-DBOOST_MPL_LIMIT_LIST_SIZE=30)
|
|
||||||
add_definitions(-DBOOST_MPL_CFG_NO_PREPROCESSED_HEADERS)
|
option(HUNTER_ENABLED "Enable Hunter package manager" OFF)
|
||||||
|
include("cmake/HunterGate.cmake")
|
||||||
|
HunterGate(
|
||||||
|
URL "https://github.com/cpp-pm/hunter/archive/v0.23.244.tar.gz"
|
||||||
|
SHA1 "2c0f491fd0b80f7b09e3d21adb97237161ef9835"
|
||||||
|
LOCAL
|
||||||
|
)
|
||||||
|
|
||||||
|
option(USE_BUNDLED_BOOST "Use the bundled version of Boost." ${HUNTER_ENABLED})
|
||||||
|
option(USE_BUNDLED_SPDLOG "Use the bundled version of spdlog."
|
||||||
|
${HUNTER_ENABLED})
|
||||||
|
option(USE_BUNDLED_OLM "Use the bundled version of libolm." ${HUNTER_ENABLED})
|
||||||
|
option(USE_BUNDLED_GTEST "Use the bundled version of Google Test."
|
||||||
|
${HUNTER_ENABLED})
|
||||||
|
option(USE_BUNDLED_CMARK "Use the bundled version of cmark."
|
||||||
|
${HUNTER_ENABLED})
|
||||||
|
option(USE_BUNDLED_JSON "Use the bundled version of nlohmann json."
|
||||||
|
${HUNTER_ENABLED})
|
||||||
|
option(USE_BUNDLED_OPENSSL "Use the bundled version of OpenSSL."
|
||||||
|
${HUNTER_ENABLED})
|
||||||
|
option(USE_BUNDLED_MTXCLIENT "Use the bundled version of the Matrix Client library." ${HUNTER_ENABLED})
|
||||||
|
option(USE_BUNDLED_SODIUM "Use the bundled version of libsodium."
|
||||||
|
${HUNTER_ENABLED})
|
||||||
|
option(USE_BUNDLED_ZLIB "Use the bundled version of zlib."
|
||||||
|
${HUNTER_ENABLED})
|
||||||
|
option(USE_BUNDLED_LMDB "Use the bundled version of lmdb."
|
||||||
|
${HUNTER_ENABLED})
|
||||||
|
option(USE_BUNDLED_LMDBXX "Use the bundled version of lmdb++."
|
||||||
|
${HUNTER_ENABLED})
|
||||||
|
option(USE_BUNDLED_TWEENY "Use the bundled version of tweeny."
|
||||||
|
${HUNTER_ENABLED})
|
||||||
|
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
||||||
|
|
||||||
|
if(${CMAKE_VERSION} VERSION_LESS "3.14.0")
|
||||||
|
message("Adding FetchContent_MakeAvailable")
|
||||||
|
# from cmakes sources
|
||||||
|
macro(FetchContent_MakeAvailable)
|
||||||
|
|
||||||
|
foreach(contentName IN ITEMS ${ARGV})
|
||||||
|
string(TOLOWER ${contentName} contentNameLower)
|
||||||
|
FetchContent_GetProperties(${contentName})
|
||||||
|
if(NOT ${contentNameLower}_POPULATED)
|
||||||
|
FetchContent_Populate(${contentName})
|
||||||
|
|
||||||
|
# Only try to call add_subdirectory() if the populated content
|
||||||
|
# can be treated that way. Protecting the call with the check
|
||||||
|
# allows this function to be used for projects that just want
|
||||||
|
# to ensure the content exists, such as to provide content at
|
||||||
|
# a known location.
|
||||||
|
if(EXISTS ${${contentNameLower}_SOURCE_DIR}/CMakeLists.txt)
|
||||||
|
add_subdirectory(${${contentNameLower}_SOURCE_DIR}
|
||||||
|
${${contentNameLower}_BINARY_DIR})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
endmacro()
|
||||||
|
endif()
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
# Include Qt basic functions
|
# Include Qt basic functions
|
||||||
include(QtCommon)
|
include(QtCommon)
|
||||||
|
|
||||||
project(nheko LANGUAGES C CXX)
|
project(nheko LANGUAGES CXX C)
|
||||||
set(CPACK_PACKAGE_VERSION_MAJOR "0")
|
set(CPACK_PACKAGE_VERSION_MAJOR "0")
|
||||||
set(CPACK_PACKAGE_VERSION_MINOR "6")
|
set(CPACK_PACKAGE_VERSION_MINOR "7")
|
||||||
set(CPACK_PACKAGE_VERSION_PATCH "4")
|
set(CPACK_PACKAGE_VERSION_PATCH "0")
|
||||||
set(PROJECT_VERSION_MAJOR ${CPACK_PACKAGE_VERSION_MAJOR})
|
set(PROJECT_VERSION_MAJOR ${CPACK_PACKAGE_VERSION_MAJOR})
|
||||||
set(PROJECT_VERSION_MINOR ${CPACK_PACKAGE_VERSION_MINOR})
|
set(PROJECT_VERSION_MINOR ${CPACK_PACKAGE_VERSION_MINOR})
|
||||||
set(PROJECT_VERSION_PATCH ${CPACK_PACKAGE_VERSION_PATCH})
|
set(PROJECT_VERSION_PATCH ${CPACK_PACKAGE_VERSION_PATCH})
|
||||||
|
@ -27,132 +91,125 @@ fix_project_version()
|
||||||
|
|
||||||
# Set additional project information
|
# Set additional project information
|
||||||
set(COMPANY "Nheko")
|
set(COMPANY "Nheko")
|
||||||
set(COPYRIGHT "Copyright (c) 2018 Nheko Contributors")
|
set(COPYRIGHT "Copyright (c) 2019 Nheko Contributors")
|
||||||
set(IDENTIFIER "com.github.mujx.nheko")
|
set(IDENTIFIER "com.github.mujx.nheko")
|
||||||
|
|
||||||
add_project_meta(META_FILES_TO_INCLUDE)
|
add_project_meta(META_FILES_TO_INCLUDE)
|
||||||
|
|
||||||
if(APPLE)
|
|
||||||
set(OPENSSL_ROOT_DIR /usr/local/opt/openssl)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT MSVC AND NOT APPLE)
|
if(NOT MSVC AND NOT APPLE)
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (BUILD_DOCS)
|
if (BUILD_DOCS)
|
||||||
find_package(Doxygen)
|
find_package(Doxygen)
|
||||||
|
|
||||||
if (DOXYGEN_FOUND)
|
if (DOXYGEN_FOUND)
|
||||||
set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Doxyfile.in)
|
set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Doxyfile.in)
|
||||||
set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
|
set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
|
||||||
|
|
||||||
configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT})
|
configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT})
|
||||||
|
|
||||||
add_custom_target(docs ALL
|
add_custom_target(docs ALL
|
||||||
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT}
|
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT}
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
COMMENT "Generating API documentation with Doxygen"
|
COMMENT "Generating API documentation with Doxygen"
|
||||||
VERBATIM )
|
VERBATIM )
|
||||||
else (DOXYGEN_FOUND)
|
else (DOXYGEN_FOUND)
|
||||||
message("Doxygen need to be installed to generate the doxygen documentation")
|
message("Doxygen need to be installed to generate the doxygen documentation")
|
||||||
endif (DOXYGEN_FOUND)
|
endif (DOXYGEN_FOUND)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# LMDB
|
# LMDB
|
||||||
#
|
#
|
||||||
include(LMDB)
|
#include(LMDB)
|
||||||
|
if(USE_BUNDLED_LMDB)
|
||||||
|
hunter_add_package(lmdb)
|
||||||
|
find_package(liblmdb CONFIG REQUIRED)
|
||||||
|
else()
|
||||||
|
find_package(LMDB)
|
||||||
|
endif()
|
||||||
|
|
||||||
#
|
#
|
||||||
# Discover Qt dependencies.
|
# Discover Qt dependencies.
|
||||||
#
|
#
|
||||||
find_package(Qt5 COMPONENTS Core Widgets LinguistTools Concurrent Svg Multimedia REQUIRED)
|
find_package(Qt5 COMPONENTS Core Widgets LinguistTools Concurrent Svg Multimedia Qml QuickControls2 QuickWidgets REQUIRED)
|
||||||
|
find_package(Qt5QuickCompiler)
|
||||||
find_package(Qt5DBus)
|
find_package(Qt5DBus)
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
find_package(Qt5MacExtras REQUIRED)
|
find_package(Qt5MacExtras REQUIRED)
|
||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|
||||||
if (Qt5Widgets_FOUND)
|
if (Qt5Widgets_FOUND)
|
||||||
if (Qt5Widgets_VERSION VERSION_LESS 5.7.0)
|
if (Qt5Widgets_VERSION VERSION_LESS 5.9.0)
|
||||||
message(STATUS "Qt version ${Qt5Widgets_VERSION}")
|
message(STATUS "Qt version ${Qt5Widgets_VERSION}")
|
||||||
message(WARNING "Minimum supported Qt5 version is 5.7!")
|
message(WARNING "Minimum supported Qt5 version is 5.9!")
|
||||||
endif()
|
endif()
|
||||||
endif(Qt5Widgets_FOUND)
|
endif(Qt5Widgets_FOUND)
|
||||||
|
|
||||||
#
|
|
||||||
# Set up compiler flags.
|
|
||||||
#
|
|
||||||
if (NOT MSVC)
|
|
||||||
set(CMAKE_C_COMPILER gcc)
|
|
||||||
endif(NOT MSVC)
|
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 14)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
||||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
if(NOT MSVC)
|
if(NOT MSVC)
|
||||||
set(
|
set(
|
||||||
CMAKE_CXX_FLAGS
|
CMAKE_CXX_FLAGS
|
||||||
"${CMAKE_CXX_FLAGS} \
|
"${CMAKE_CXX_FLAGS} \
|
||||||
-Wall \
|
-Wall \
|
||||||
-Wextra \
|
-Wextra \
|
||||||
-Werror \
|
-pipe \
|
||||||
-pipe \
|
-pedantic \
|
||||||
-pedantic \
|
-fsized-deallocation \
|
||||||
-fsized-deallocation \
|
-fdiagnostics-color=always \
|
||||||
-fdiagnostics-color=always \
|
-Wunreachable-code \
|
||||||
-Wunreachable-code \
|
-std=c++17"
|
||||||
-std=c++14"
|
)
|
||||||
)
|
if (NOT CMAKE_COMPILER_IS_GNUCXX)
|
||||||
if (NOT CMAKE_COMPILER_IS_GNUCXX)
|
# -Wshadow is buggy and broken in GCC, so do not enable it.
|
||||||
# -Wshadow is buggy and broken in GCC, so do not enable it.
|
# see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79328
|
||||||
# see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79328
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wshadow")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wshadow")
|
endif()
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
set(
|
set(
|
||||||
CMAKE_CXX_FLAGS
|
CMAKE_CXX_FLAGS
|
||||||
"${CMAKE_CXX_FLAGS} /bigobj"
|
"${CMAKE_CXX_FLAGS} /bigobj"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT (CMAKE_BUILD_TYPE OR CMAKE_CONFIGURATION_TYPES))
|
if(NOT (CMAKE_BUILD_TYPE OR CMAKE_CONFIGURATION_TYPES))
|
||||||
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING
|
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING
|
||||||
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
|
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
|
||||||
FORCE)
|
FORCE)
|
||||||
message("Setting build type to '${CMAKE_BUILD_TYPE}'")
|
message("Setting build type to '${CMAKE_BUILD_TYPE}'")
|
||||||
else(NOT (CMAKE_BUILD_TYPE OR CMAKE_CONFIGURATION_TYPES))
|
else(NOT (CMAKE_BUILD_TYPE OR CMAKE_CONFIGURATION_TYPES))
|
||||||
message("Build type set to '${CMAKE_BUILD_TYPE}'")
|
message("Build type set to '${CMAKE_BUILD_TYPE}'")
|
||||||
endif(NOT (CMAKE_BUILD_TYPE OR CMAKE_CONFIGURATION_TYPES))
|
endif(NOT (CMAKE_BUILD_TYPE OR CMAKE_CONFIGURATION_TYPES))
|
||||||
|
|
||||||
set(SPDLOG_DEBUG_ON false)
|
set(SPDLOG_DEBUG_ON false)
|
||||||
|
|
||||||
# Windows doesn't handle CMAKE_BUILD_TYPE.
|
# Windows doesn't handle CMAKE_BUILD_TYPE.
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
if(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
|
if(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
|
||||||
set(SPDLOG_DEBUG_ON true)
|
set(SPDLOG_DEBUG_ON true)
|
||||||
else()
|
else()
|
||||||
set(SPDLOG_DEBUG_ON false)
|
set(SPDLOG_DEBUG_ON false)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_program(GIT git)
|
find_program(GIT git)
|
||||||
if(GIT)
|
if(GIT)
|
||||||
execute_process(
|
execute_process(
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
COMMAND ${GIT} rev-parse --short HEAD
|
COMMAND ${GIT} rev-parse --short HEAD
|
||||||
OUTPUT_VARIABLE GIT_OUT OUTPUT_STRIP_TRAILING_WHITESPACE
|
OUTPUT_VARIABLE GIT_OUT OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
)
|
)
|
||||||
if(GIT_OUT)
|
if(GIT_OUT)
|
||||||
set(CPACK_PACKAGE_VERSION_PATCH "${CPACK_PACKAGE_VERSION_PATCH}-${GIT_OUT}")
|
set(CPACK_PACKAGE_VERSION_PATCH "${CPACK_PACKAGE_VERSION_PATCH}-${GIT_OUT}")
|
||||||
else()
|
else()
|
||||||
set(CPACK_PACKAGE_VERSION_PATCH "${CPACK_PACKAGE_VERSION_PATCH}")
|
set(CPACK_PACKAGE_VERSION_PATCH "${CPACK_PACKAGE_VERSION_PATCH}")
|
||||||
endif()
|
endif()
|
||||||
endif(GIT)
|
endif(GIT)
|
||||||
|
|
||||||
set(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH})
|
set(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH})
|
||||||
|
@ -169,221 +226,281 @@ configure_file(cmake/nheko.h config/nheko.h)
|
||||||
# Declare source and header files.
|
# Declare source and header files.
|
||||||
#
|
#
|
||||||
set(SRC_FILES
|
set(SRC_FILES
|
||||||
# Dialogs
|
# Dialogs
|
||||||
src/dialogs/CreateRoom.cpp
|
src/dialogs/CreateRoom.cpp
|
||||||
src/dialogs/ImageOverlay.cpp
|
src/dialogs/FallbackAuth.cpp
|
||||||
src/dialogs/PreviewUploadOverlay.cpp
|
src/dialogs/ImageOverlay.cpp
|
||||||
src/dialogs/InviteUsers.cpp
|
src/dialogs/InviteUsers.cpp
|
||||||
src/dialogs/JoinRoom.cpp
|
src/dialogs/JoinRoom.cpp
|
||||||
src/dialogs/MemberList.cpp
|
src/dialogs/LeaveRoom.cpp
|
||||||
src/dialogs/LeaveRoom.cpp
|
src/dialogs/Logout.cpp
|
||||||
src/dialogs/Logout.cpp
|
src/dialogs/MemberList.cpp
|
||||||
src/dialogs/UserProfile.cpp
|
src/dialogs/PreviewUploadOverlay.cpp
|
||||||
src/dialogs/ReadReceipts.cpp
|
src/dialogs/ReCaptcha.cpp
|
||||||
src/dialogs/ReCaptcha.cpp
|
src/dialogs/ReadReceipts.cpp
|
||||||
src/dialogs/RoomSettings.cpp
|
src/dialogs/RoomSettings.cpp
|
||||||
|
src/dialogs/UserProfile.cpp
|
||||||
|
|
||||||
# Emoji
|
# Emoji
|
||||||
src/emoji/Category.cpp
|
src/emoji/Category.cpp
|
||||||
src/emoji/ItemDelegate.cpp
|
src/emoji/ItemDelegate.cpp
|
||||||
src/emoji/Panel.cpp
|
src/emoji/Panel.cpp
|
||||||
src/emoji/PickButton.cpp
|
src/emoji/PickButton.cpp
|
||||||
src/emoji/Provider.cpp
|
src/emoji/Provider.cpp
|
||||||
|
|
||||||
# Timeline
|
# Timeline
|
||||||
src/timeline/TimelineViewManager.cpp
|
src/timeline/TimelineViewManager.cpp
|
||||||
src/timeline/TimelineItem.cpp
|
src/timeline/TimelineModel.cpp
|
||||||
src/timeline/TimelineView.cpp
|
src/timeline/DelegateChooser.cpp
|
||||||
src/timeline/widgets/AudioItem.cpp
|
|
||||||
src/timeline/widgets/FileItem.cpp
|
|
||||||
src/timeline/widgets/ImageItem.cpp
|
|
||||||
src/timeline/widgets/VideoItem.cpp
|
|
||||||
|
|
||||||
# UI components
|
# UI components
|
||||||
src/ui/Avatar.cpp
|
src/ui/Avatar.cpp
|
||||||
src/ui/Badge.cpp
|
src/ui/Badge.cpp
|
||||||
src/ui/LoadingIndicator.cpp
|
src/ui/DropShadow.cpp
|
||||||
src/ui/InfoMessage.cpp
|
src/ui/LoadingIndicator.cpp
|
||||||
src/ui/FlatButton.cpp
|
src/ui/InfoMessage.cpp
|
||||||
src/ui/FloatingButton.cpp
|
src/ui/FlatButton.cpp
|
||||||
src/ui/Label.cpp
|
src/ui/FloatingButton.cpp
|
||||||
src/ui/OverlayModal.cpp
|
src/ui/Label.cpp
|
||||||
src/ui/SnackBar.cpp
|
src/ui/OverlayModal.cpp
|
||||||
src/ui/RaisedButton.cpp
|
src/ui/SnackBar.cpp
|
||||||
src/ui/Ripple.cpp
|
src/ui/RaisedButton.cpp
|
||||||
src/ui/RippleOverlay.cpp
|
src/ui/Ripple.cpp
|
||||||
src/ui/OverlayWidget.cpp
|
src/ui/RippleOverlay.cpp
|
||||||
src/ui/TextField.cpp
|
src/ui/OverlayWidget.cpp
|
||||||
src/ui/TextLabel.cpp
|
src/ui/TextField.cpp
|
||||||
src/ui/ToggleButton.cpp
|
src/ui/TextLabel.cpp
|
||||||
src/ui/Theme.cpp
|
src/ui/ToggleButton.cpp
|
||||||
src/ui/ThemeManager.cpp
|
src/ui/Theme.cpp
|
||||||
|
src/ui/ThemeManager.cpp
|
||||||
|
|
||||||
src/AvatarProvider.cpp
|
src/AvatarProvider.cpp
|
||||||
src/Cache.cpp
|
src/Cache.cpp
|
||||||
src/ChatPage.cpp
|
src/ChatPage.cpp
|
||||||
src/CommunitiesListItem.cpp
|
src/CommunitiesListItem.cpp
|
||||||
src/CommunitiesList.cpp
|
src/CommunitiesList.cpp
|
||||||
src/InviteeItem.cpp
|
src/EventAccessors.cpp
|
||||||
src/LoginPage.cpp
|
src/InviteeItem.cpp
|
||||||
src/Logging.cpp
|
src/LoginPage.cpp
|
||||||
src/MainWindow.cpp
|
src/Logging.cpp
|
||||||
src/MatrixClient.cpp
|
src/MainWindow.cpp
|
||||||
src/QuickSwitcher.cpp
|
src/MatrixClient.cpp
|
||||||
src/Olm.cpp
|
src/MxcImageProvider.cpp
|
||||||
src/RegisterPage.cpp
|
src/ColorImageProvider.cpp
|
||||||
src/RoomInfoListItem.cpp
|
src/QuickSwitcher.cpp
|
||||||
src/RoomList.cpp
|
src/Olm.cpp
|
||||||
src/RunGuard.cpp
|
src/RegisterPage.cpp
|
||||||
src/SideBarActions.cpp
|
src/RoomInfoListItem.cpp
|
||||||
src/Splitter.cpp
|
src/RoomList.cpp
|
||||||
src/SuggestionsPopup.cpp
|
src/SideBarActions.cpp
|
||||||
src/TextInputWidget.cpp
|
src/Splitter.cpp
|
||||||
src/TopRoomBar.cpp
|
src/popups/SuggestionsPopup.cpp
|
||||||
src/TrayIcon.cpp
|
src/popups/PopupItem.cpp
|
||||||
src/TypingDisplay.cpp
|
src/popups/ReplyPopup.cpp
|
||||||
src/Utils.cpp
|
src/popups/UserMentions.cpp
|
||||||
src/UserInfoWidget.cpp
|
src/TextInputWidget.cpp
|
||||||
src/UserSettingsPage.cpp
|
src/TopRoomBar.cpp
|
||||||
src/WelcomePage.cpp
|
src/TrayIcon.cpp
|
||||||
src/main.cpp
|
src/Utils.cpp
|
||||||
)
|
src/UserInfoWidget.cpp
|
||||||
|
src/UserSettingsPage.cpp
|
||||||
|
src/WelcomePage.cpp
|
||||||
|
src/main.cpp
|
||||||
|
)
|
||||||
|
|
||||||
# ExternalProject dependencies
|
|
||||||
set(EXTERNAL_PROJECT_DEPS "")
|
|
||||||
|
|
||||||
include(FeatureSummary)
|
include(FeatureSummary)
|
||||||
|
|
||||||
set(Boost_USE_STATIC_LIBS OFF)
|
if(USE_BUNDLED_BOOST)
|
||||||
set(Boost_USE_STATIC_RUNTIME OFF)
|
hunter_add_package(Boost COMPONENTS iostreams system thread)
|
||||||
set(Boost_USE_MULTITHREADED ON)
|
endif()
|
||||||
find_package(Boost 1.66 REQUIRED
|
find_package(Boost 1.70 REQUIRED
|
||||||
COMPONENTS atomic
|
COMPONENTS iostreams
|
||||||
chrono
|
system
|
||||||
date_time
|
thread)
|
||||||
iostreams
|
if(USE_BUNDLED_ZLIB)
|
||||||
random
|
hunter_add_package(ZLIB)
|
||||||
regex
|
endif()
|
||||||
system
|
|
||||||
thread)
|
|
||||||
find_package(ZLIB REQUIRED)
|
find_package(ZLIB REQUIRED)
|
||||||
|
if(USE_BUNDLED_OPENSSL)
|
||||||
|
hunter_add_package(OpenSSL)
|
||||||
|
endif()
|
||||||
find_package(OpenSSL REQUIRED)
|
find_package(OpenSSL REQUIRED)
|
||||||
find_package(MatrixClient 0.1.0 REQUIRED)
|
if(USE_BUNDLED_MTXCLIENT)
|
||||||
find_package(Olm 2 REQUIRED)
|
include(FetchContent)
|
||||||
|
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
|
||||||
|
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")
|
||||||
|
FetchContent_Declare(
|
||||||
|
MatrixClient
|
||||||
|
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
|
||||||
|
GIT_TAG 7fc1d357afaabb134cb6d9c593f94915973d31fa
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(MatrixClient)
|
||||||
|
else()
|
||||||
|
find_package(MatrixClient 0.3.0 REQUIRED)
|
||||||
|
endif()
|
||||||
|
if(USE_BUNDLED_OLM)
|
||||||
|
include(FetchContent)
|
||||||
|
set(OLM_TESTS OFF CACHE INTERNAL "")
|
||||||
|
FetchContent_Declare(
|
||||||
|
Olm
|
||||||
|
GIT_REPOSITORY https://gitlab.matrix.org/matrix-org/olm.git
|
||||||
|
GIT_TAG 3.1.4
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(Olm)
|
||||||
|
else()
|
||||||
|
find_package(Olm 3)
|
||||||
|
set_package_properties(Olm PROPERTIES
|
||||||
|
DESCRIPTION "An implementation of the Double Ratchet cryptographic ratchet"
|
||||||
|
URL "https://git.matrix.org/git/olm/about/"
|
||||||
|
TYPE REQUIRED
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
if(USE_BUNDLED_SPDLOG)
|
||||||
|
hunter_add_package(spdlog)
|
||||||
|
endif()
|
||||||
find_package(spdlog 1.0.0 CONFIG REQUIRED)
|
find_package(spdlog 1.0.0 CONFIG REQUIRED)
|
||||||
find_package(cmark REQUIRED)
|
|
||||||
|
if(USE_BUNDLED_CMARK)
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(
|
||||||
|
cmark
|
||||||
|
GIT_REPOSITORY https://github.com/commonmark/cmark.git
|
||||||
|
GIT_TAG 242e277a661ec7e51f34dcaf86c1925d550b1498 #0.29.0 << doesn't work with fetch content yet
|
||||||
|
CMAKE_ARGS "CMARK_STATIC=ON CMARK_SHARED=OFF CMARK_TESTS=OFF CMARK_TESTS=OFF"
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(cmark)
|
||||||
|
if (MSVC)
|
||||||
|
add_library(cmark::cmark ALIAS libcmark)
|
||||||
|
else()
|
||||||
|
add_library(cmark::cmark ALIAS libcmark_static)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
find_package(cmark REQUIRED)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(USE_BUNDLED_JSON)
|
||||||
|
hunter_add_package(nlohmann_json)
|
||||||
|
endif()
|
||||||
find_package(nlohmann_json 3.2.0)
|
find_package(nlohmann_json 3.2.0)
|
||||||
set_package_properties(nlohmann_json PROPERTIES
|
set_package_properties(nlohmann_json PROPERTIES
|
||||||
DESCRIPTION "JSON for Modern C++, a C++11 header-only JSON class"
|
DESCRIPTION "JSON for Modern C++, a C++11 header-only JSON class"
|
||||||
URL "https://nlohmann.github.io/json/"
|
URL "https://nlohmann.github.io/json/"
|
||||||
TYPE REQUIRED
|
TYPE REQUIRED
|
||||||
)
|
)
|
||||||
|
|
||||||
if(NOT LMDBXX_INCLUDE_DIR)
|
if(USE_BUNDLED_LMDBXX)
|
||||||
find_path(LMDBXX_INCLUDE_DIR
|
hunter_add_package(lmdbxx)
|
||||||
NAMES lmdb++.h
|
find_package(lmdbxx CONFIG REQUIRED)
|
||||||
PATHS /usr/include
|
else()
|
||||||
/usr/local/include
|
if(NOT LMDBXX_INCLUDE_DIR)
|
||||||
$ENV{LIB_DIR}/include
|
find_path(LMDBXX_INCLUDE_DIR
|
||||||
$ENV{LIB_DIR}/include/lmdbxx)
|
NAMES lmdb++.h
|
||||||
|
PATHS /usr/include
|
||||||
|
/usr/local/include
|
||||||
|
$ENV{LIB_DIR}/include
|
||||||
|
$ENV{LIB_DIR}/include/lmdbxx)
|
||||||
|
|
||||||
|
endif()
|
||||||
|
add_library(lmdbxx INTERFACE)
|
||||||
|
target_include_directories(lmdbxx INTERFACE ${LMDBXX_INCLUDE_DIR})
|
||||||
|
add_library(lmdbxx::lmdbxx ALIAS lmdbxx)
|
||||||
endif()
|
endif()
|
||||||
include_directories(SYSTEM ${LMDBXX_INCLUDE_DIR})
|
|
||||||
|
|
||||||
if(NOT TWEENY_INCLUDE_DIR)
|
if(USE_BUNDLED_TWEENY)
|
||||||
find_path(TWEENY_INCLUDE_DIR
|
include(FetchContent)
|
||||||
NAMES tweeny/tweeny.h
|
FetchContent_Declare(
|
||||||
PATHS /usr/include/
|
Tweeny
|
||||||
/usr/local/include/
|
GIT_REPOSITORY https://github.com/mobius3/tweeny.git
|
||||||
$ENV{LIB_DIR}/include/
|
GIT_TAG 6a5033372fe53c4c731c66c8a2d56261746cd85c #v3 <- v3 has unfixed warnings
|
||||||
$ENV{LIB_DIR}/include/tweeny)
|
)
|
||||||
|
FetchContent_MakeAvailable(Tweeny)
|
||||||
|
else()
|
||||||
|
find_package(Tweeny REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
include_directories(SYSTEM ${TWEENY_INCLUDE_DIR})
|
|
||||||
|
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/src)
|
# single instance functionality
|
||||||
include_directories(${Boost_INCLUDE_DIRS})
|
set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication")
|
||||||
|
add_subdirectory(third_party/SingleApplication-3.0.19/)
|
||||||
# local inclue directory
|
|
||||||
include_directories(includes)
|
|
||||||
|
|
||||||
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
||||||
|
|
||||||
qt5_wrap_cpp(MOC_HEADERS
|
qt5_wrap_cpp(MOC_HEADERS
|
||||||
# Dialogs
|
# Dialogs
|
||||||
src/dialogs/CreateRoom.h
|
src/dialogs/CreateRoom.h
|
||||||
src/dialogs/ImageOverlay.h
|
src/dialogs/FallbackAuth.h
|
||||||
src/dialogs/PreviewUploadOverlay.h
|
src/dialogs/ImageOverlay.h
|
||||||
src/dialogs/InviteUsers.h
|
src/dialogs/InviteUsers.h
|
||||||
src/dialogs/JoinRoom.h
|
src/dialogs/JoinRoom.h
|
||||||
src/dialogs/MemberList.h
|
src/dialogs/LeaveRoom.h
|
||||||
src/dialogs/LeaveRoom.h
|
src/dialogs/Logout.h
|
||||||
src/dialogs/Logout.h
|
src/dialogs/MemberList.h
|
||||||
src/dialogs/UserProfile.h
|
src/dialogs/PreviewUploadOverlay.h
|
||||||
src/dialogs/RawMessage.h
|
src/dialogs/RawMessage.h
|
||||||
src/dialogs/ReadReceipts.h
|
src/dialogs/ReCaptcha.h
|
||||||
src/dialogs/ReCaptcha.h
|
src/dialogs/ReadReceipts.h
|
||||||
src/dialogs/RoomSettings.h
|
src/dialogs/RoomSettings.h
|
||||||
|
src/dialogs/UserProfile.h
|
||||||
|
|
||||||
# Emoji
|
# Emoji
|
||||||
src/emoji/Category.h
|
src/emoji/Category.h
|
||||||
src/emoji/ItemDelegate.h
|
src/emoji/ItemDelegate.h
|
||||||
src/emoji/Panel.h
|
src/emoji/Panel.h
|
||||||
src/emoji/PickButton.h
|
src/emoji/PickButton.h
|
||||||
|
|
||||||
# Timeline
|
# Timeline
|
||||||
src/timeline/TimelineItem.h
|
src/timeline/TimelineViewManager.h
|
||||||
src/timeline/TimelineView.h
|
src/timeline/TimelineModel.h
|
||||||
src/timeline/TimelineViewManager.h
|
src/timeline/DelegateChooser.h
|
||||||
src/timeline/widgets/AudioItem.h
|
|
||||||
src/timeline/widgets/FileItem.h
|
|
||||||
src/timeline/widgets/ImageItem.h
|
|
||||||
src/timeline/widgets/VideoItem.h
|
|
||||||
|
|
||||||
# UI components
|
# UI components
|
||||||
src/ui/Avatar.h
|
src/ui/Avatar.h
|
||||||
src/ui/Badge.h
|
src/ui/Badge.h
|
||||||
src/ui/LoadingIndicator.h
|
src/ui/LoadingIndicator.h
|
||||||
src/ui/InfoMessage.h
|
src/ui/InfoMessage.h
|
||||||
src/ui/FlatButton.h
|
src/ui/FlatButton.h
|
||||||
src/ui/Label.h
|
src/ui/Label.h
|
||||||
src/ui/FloatingButton.h
|
src/ui/FloatingButton.h
|
||||||
src/ui/Menu.h
|
src/ui/Menu.h
|
||||||
src/ui/OverlayWidget.h
|
src/ui/OverlayWidget.h
|
||||||
src/ui/SnackBar.h
|
src/ui/SnackBar.h
|
||||||
src/ui/RaisedButton.h
|
src/ui/RaisedButton.h
|
||||||
src/ui/Ripple.h
|
src/ui/Ripple.h
|
||||||
src/ui/RippleOverlay.h
|
src/ui/RippleOverlay.h
|
||||||
src/ui/TextField.h
|
src/ui/TextField.h
|
||||||
src/ui/TextLabel.h
|
src/ui/TextLabel.h
|
||||||
src/ui/ToggleButton.h
|
src/ui/ToggleButton.h
|
||||||
src/ui/Theme.h
|
src/ui/Theme.h
|
||||||
src/ui/ThemeManager.h
|
src/ui/ThemeManager.h
|
||||||
|
|
||||||
src/notifications/Manager.h
|
src/notifications/Manager.h
|
||||||
|
|
||||||
src/AvatarProvider.h
|
src/AvatarProvider.h
|
||||||
src/Cache.h
|
src/Cache_p.h
|
||||||
src/ChatPage.h
|
src/ChatPage.h
|
||||||
src/CommunitiesListItem.h
|
src/CommunitiesListItem.h
|
||||||
src/CommunitiesList.h
|
src/CommunitiesList.h
|
||||||
src/LoginPage.h
|
src/LoginPage.h
|
||||||
src/MainWindow.h
|
src/MainWindow.h
|
||||||
src/MatrixClient.h
|
src/MxcImageProvider.h
|
||||||
src/InviteeItem.h
|
src/InviteeItem.h
|
||||||
src/QuickSwitcher.h
|
src/QuickSwitcher.h
|
||||||
src/RegisterPage.h
|
src/RegisterPage.h
|
||||||
src/RoomInfoListItem.h
|
src/RoomInfoListItem.h
|
||||||
src/RoomList.h
|
src/RoomList.h
|
||||||
src/SideBarActions.h
|
src/SideBarActions.h
|
||||||
src/Splitter.h
|
src/Splitter.h
|
||||||
src/SuggestionsPopup.h
|
src/popups/SuggestionsPopup.h
|
||||||
src/TextInputWidget.h
|
src/popups/ReplyPopup.h
|
||||||
src/TopRoomBar.h
|
src/popups/PopupItem.h
|
||||||
src/TrayIcon.h
|
src/popups/UserMentions.h
|
||||||
src/TypingDisplay.h
|
src/TextInputWidget.h
|
||||||
src/UserInfoWidget.h
|
src/TopRoomBar.h
|
||||||
src/UserSettingsPage.h
|
src/TrayIcon.h
|
||||||
src/WelcomePage.h
|
src/UserInfoWidget.h
|
||||||
)
|
src/UserSettingsPage.h
|
||||||
|
src/WelcomePage.h
|
||||||
|
)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Bundle translations.
|
# Bundle translations.
|
||||||
|
@ -391,85 +508,104 @@ qt5_wrap_cpp(MOC_HEADERS
|
||||||
include(Translations)
|
include(Translations)
|
||||||
set(TRANSLATION_DEPS ${LANG_QRC} ${QRC} ${QM_SRC})
|
set(TRANSLATION_DEPS ${LANG_QRC} ${QRC} ${QM_SRC})
|
||||||
|
|
||||||
set(COMMON_LIBS
|
|
||||||
MatrixClient::MatrixClient
|
|
||||||
${Boost_LIBRARIES}
|
|
||||||
cmark::cmark
|
|
||||||
Qt5::Widgets
|
|
||||||
Qt5::Svg
|
|
||||||
Qt5::Concurrent
|
|
||||||
Qt5::Multimedia
|
|
||||||
nlohmann_json::nlohmann_json)
|
|
||||||
|
|
||||||
if(APPVEYOR_BUILD)
|
|
||||||
set(NHEKO_LIBS ${COMMON_LIBS} lmdb)
|
|
||||||
else()
|
|
||||||
set(NHEKO_LIBS ${COMMON_LIBS} ${LMDB_LIBRARY})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework Foundation -framework Cocoa")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework Foundation -framework Cocoa")
|
||||||
set(SRC_FILES ${SRC_FILES} src/notifications/ManagerMac.mm src/emoji/MacHelper.mm)
|
set(SRC_FILES ${SRC_FILES} src/notifications/ManagerMac.mm src/emoji/MacHelper.mm)
|
||||||
elseif (WIN32)
|
elseif (WIN32)
|
||||||
file(DOWNLOAD
|
file(DOWNLOAD
|
||||||
"https://raw.githubusercontent.com/mohabouje/WinToast/41ed1c58d5dce0ee9c01dbdeac05be45358d4f57/src/wintoastlib.cpp"
|
"https://raw.githubusercontent.com/mohabouje/WinToast/41ed1c58d5dce0ee9c01dbdeac05be45358d4f57/src/wintoastlib.cpp"
|
||||||
${PROJECT_SOURCE_DIR}/src/wintoastlib.cpp
|
${PROJECT_SOURCE_DIR}/src/wintoastlib.cpp
|
||||||
EXPECTED_HASH SHA256=1A1A7CE41C1052B12946798F4A6C67CE1FAD209C967F5ED4D720B173527E2073)
|
EXPECTED_HASH SHA256=1A1A7CE41C1052B12946798F4A6C67CE1FAD209C967F5ED4D720B173527E2073)
|
||||||
|
|
||||||
file(DOWNLOAD
|
file(DOWNLOAD
|
||||||
"https://raw.githubusercontent.com/mohabouje/WinToast/41ed1c58d5dce0ee9c01dbdeac05be45358d4f57/src/wintoastlib.h"
|
"https://raw.githubusercontent.com/mohabouje/WinToast/41ed1c58d5dce0ee9c01dbdeac05be45358d4f57/src/wintoastlib.h"
|
||||||
${PROJECT_SOURCE_DIR}/src/wintoastlib.h
|
${PROJECT_SOURCE_DIR}/src/wintoastlib.h
|
||||||
EXPECTED_HASH SHA256=b4481023c5782733795838be22bf1a75f45d87458cd4d9a5a75f664a146eea11)
|
EXPECTED_HASH SHA256=b4481023c5782733795838be22bf1a75f45d87458cd4d9a5a75f664a146eea11)
|
||||||
|
|
||||||
set(SRC_FILES ${SRC_FILES} src/notifications/ManagerWin.cpp src/wintoastlib.cpp)
|
set(SRC_FILES ${SRC_FILES} src/notifications/ManagerWin.cpp src/wintoastlib.cpp)
|
||||||
else ()
|
else ()
|
||||||
set(SRC_FILES ${SRC_FILES} src/notifications/ManagerLinux.cpp)
|
set(SRC_FILES ${SRC_FILES} src/notifications/ManagerLinux.cpp)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set(NHEKO_DEPS
|
set(NHEKO_DEPS
|
||||||
${SRC_FILES}
|
${SRC_FILES}
|
||||||
${UI_HEADERS}
|
${UI_HEADERS}
|
||||||
${MOC_HEADERS}
|
${MOC_HEADERS}
|
||||||
${TRANSLATION_DEPS}
|
${TRANSLATION_DEPS}
|
||||||
${META_FILES_TO_INCLUDE})
|
${META_FILES_TO_INCLUDE})
|
||||||
|
|
||||||
if(ASAN)
|
if(ASAN)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address,undefined")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address,undefined")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_executable (nheko ${OS_BUNDLE} ${NHEKO_DEPS})
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
add_executable (nheko ${OS_BUNDLE} ${NHEKO_DEPS})
|
target_link_libraries (nheko PRIVATE Qt5::MacExtras)
|
||||||
target_link_libraries (nheko ${NHEKO_LIBS} Qt5::MacExtras)
|
|
||||||
elseif(WIN32)
|
elseif(WIN32)
|
||||||
add_executable (nheko ${OS_BUNDLE} ${ICON_FILE} ${NHEKO_DEPS})
|
target_compile_definitions(nheko PRIVATE WIN32_LEAN_AND_MEAN)
|
||||||
target_link_libraries (nheko ${NTDLIB} ${NHEKO_LIBS} Qt5::WinMain)
|
target_link_libraries (nheko PRIVATE ${NTDLIB} Qt5::WinMain)
|
||||||
else()
|
else()
|
||||||
add_executable (nheko ${OS_BUNDLE} ${NHEKO_DEPS})
|
target_link_libraries (nheko PRIVATE Qt5::DBus)
|
||||||
target_link_libraries (nheko ${NHEKO_LIBS} Qt5::DBus)
|
endif()
|
||||||
|
target_include_directories(nheko PRIVATE src includes)
|
||||||
|
|
||||||
|
target_link_libraries(nheko PRIVATE
|
||||||
|
MatrixClient::MatrixClient
|
||||||
|
Boost::iostreams
|
||||||
|
Boost::system
|
||||||
|
Boost::thread
|
||||||
|
cmark::cmark
|
||||||
|
spdlog::spdlog
|
||||||
|
Qt5::Widgets
|
||||||
|
Qt5::Svg
|
||||||
|
Qt5::Concurrent
|
||||||
|
Qt5::Multimedia
|
||||||
|
Qt5::Qml
|
||||||
|
Qt5::QuickControls2
|
||||||
|
Qt5::QuickWidgets
|
||||||
|
nlohmann_json::nlohmann_json
|
||||||
|
lmdbxx::lmdbxx
|
||||||
|
liblmdb::lmdb
|
||||||
|
tweeny
|
||||||
|
SingleApplication::SingleApplication)
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
target_link_libraries(nheko PRIVATE ntdll)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(EXTERNAL_PROJECT_DEPS)
|
|
||||||
add_dependencies(nheko ${EXTERNAL_PROJECT_DEPS})
|
if(QML_DEBUGGING)
|
||||||
|
target_compile_definitions(nheko PRIVATE QML_DEBUGGING)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
if(NOT MSVC)
|
||||||
|
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug" OR CI_BUILD)
|
||||||
|
target_compile_options(nheko PRIVATE "-Werror")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set_target_properties(nheko PROPERTIES SKIP_BUILD_RPATH TRUE)
|
||||||
|
|
||||||
if(UNIX AND NOT APPLE)
|
if(UNIX AND NOT APPLE)
|
||||||
install (TARGETS nheko RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
install (TARGETS nheko RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
||||||
install (FILES "resources/nheko-16.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/16x16/apps" RENAME "nheko.png")
|
install (FILES "resources/nheko-16.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/16x16/apps" RENAME "nheko.png")
|
||||||
install (FILES "resources/nheko-32.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/32x32/apps" RENAME "nheko.png")
|
install (FILES "resources/nheko-32.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/32x32/apps" RENAME "nheko.png")
|
||||||
install (FILES "resources/nheko-48.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps" RENAME "nheko.png")
|
install (FILES "resources/nheko-48.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps" RENAME "nheko.png")
|
||||||
install (FILES "resources/nheko-64.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/64x64/apps" RENAME "nheko.png")
|
install (FILES "resources/nheko-64.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/64x64/apps" RENAME "nheko.png")
|
||||||
install (FILES "resources/nheko-128.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/128x128/apps" RENAME "nheko.png")
|
install (FILES "resources/nheko-128.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/128x128/apps" RENAME "nheko.png")
|
||||||
install (FILES "resources/nheko-256.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/256x256/apps" RENAME "nheko.png")
|
install (FILES "resources/nheko-256.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/256x256/apps" RENAME "nheko.png")
|
||||||
install (FILES "resources/nheko-512.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/512x512/apps" RENAME "nheko.png")
|
install (FILES "resources/nheko-512.png" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/512x512/apps" RENAME "nheko.png")
|
||||||
install (FILES "resources/nheko.desktop" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications")
|
install (FILES "resources/nheko.svg" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/apps" RENAME "nheko.svg")
|
||||||
install (FILES "resources/nheko.appdata.xml" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo")
|
install (FILES "resources/nheko.desktop" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications")
|
||||||
|
install (FILES "resources/nheko.appdata.xml" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo")
|
||||||
|
|
||||||
if(NOT TARGET uninstall)
|
if(NOT TARGET uninstall)
|
||||||
configure_file(
|
configure_file(
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
|
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
|
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
|
||||||
IMMEDIATE @ONLY)
|
IMMEDIATE @ONLY)
|
||||||
add_custom_target(uninstall
|
add_custom_target(uninstall
|
||||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -7,7 +7,7 @@ RUN \
|
||||||
add-apt-repository -y ppa:ubuntu-toolchain-r/test && \
|
add-apt-repository -y ppa:ubuntu-toolchain-r/test && \
|
||||||
apt-get update -qq && \
|
apt-get update -qq && \
|
||||||
apt-get install -y \
|
apt-get install -y \
|
||||||
qt510base qt510tools qt510svg qt510multimedia \
|
qt510base qt510tools qt510svg qt510multimedia qt510quickcontrols2 qt510graphicaleffects \
|
||||||
gcc-5 g++-5
|
gcc-5 g++-5
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
|
@ -44,4 +44,4 @@ ENV PATH=/opt/qt510/bin:$PATH
|
||||||
|
|
||||||
RUN mkdir /build
|
RUN mkdir /build
|
||||||
|
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
|
|
2
Makefile
|
@ -68,7 +68,7 @@ update-translations:
|
||||||
-locations relative \
|
-locations relative \
|
||||||
-Iinclude/dialogs \
|
-Iinclude/dialogs \
|
||||||
-Iinclude \
|
-Iinclude \
|
||||||
src/ -ts resources/langs/nheko_*.ts -no-obsolete
|
src/ resources/qml/ -ts resources/langs/nheko_*.ts -no-obsolete
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf build
|
rm -rf build
|
||||||
|
|
153
README.md
|
@ -3,7 +3,7 @@ nheko
|
||||||
[![Build Status](https://travis-ci.org/Nheko-Reborn/nheko.svg?branch=master)](https://travis-ci.org/Nheko-Reborn/nheko)
|
[![Build Status](https://travis-ci.org/Nheko-Reborn/nheko.svg?branch=master)](https://travis-ci.org/Nheko-Reborn/nheko)
|
||||||
[![Build status](https://ci.appveyor.com/api/projects/status/07qrqbfylsg4hw2h/branch/master?svg=true)](https://ci.appveyor.com/project/redsky17/nheko/branch/master)
|
[![Build status](https://ci.appveyor.com/api/projects/status/07qrqbfylsg4hw2h/branch/master?svg=true)](https://ci.appveyor.com/project/redsky17/nheko/branch/master)
|
||||||
[![Stable Version](https://img.shields.io/badge/download-stable-green.svg)](https://github.com/Nheko-Reborn/nheko/releases/v0.6.4)
|
[![Stable Version](https://img.shields.io/badge/download-stable-green.svg)](https://github.com/Nheko-Reborn/nheko/releases/v0.6.4)
|
||||||
[![Nightly](https://img.shields.io/badge/download-nightly-green.svg)](https://bintray.com/nheko-reborn/nheko/nheko)
|
[![Nightly](https://img.shields.io/badge/download-nightly-green.svg)](https://nheko-reborn-artifacts.s3.us-east-2.amazonaws.com/list.html)
|
||||||
[![#nheko-reborn:matrix.org](https://img.shields.io/matrix/nheko-reborn:matrix.org.svg?label=%23nheko-reborn:matrix.org)](https://matrix.to/#/#nheko-reborn:matrix.org)
|
[![#nheko-reborn:matrix.org](https://img.shields.io/matrix/nheko-reborn:matrix.org.svg?label=%23nheko-reborn:matrix.org)](https://matrix.to/#/#nheko-reborn:matrix.org)
|
||||||
[![AUR: nheko](https://img.shields.io/badge/AUR-nheko-blue.svg)](https://aur.archlinux.org/packages/nheko)
|
[![AUR: nheko](https://img.shields.io/badge/AUR-nheko-blue.svg)](https://aur.archlinux.org/packages/nheko)
|
||||||
<a href='https://flathub.org/apps/details/io.github.NhekoReborn.Nheko'><img width='240' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-en.png'/></a>
|
<a href='https://flathub.org/apps/details/io.github.NhekoReborn.Nheko'><img width='240' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-en.png'/></a>
|
||||||
|
@ -11,21 +11,28 @@ nheko
|
||||||
The motivation behind the project is to provide a native desktop app for [Matrix] that
|
The motivation behind the project is to provide a native desktop app for [Matrix] that
|
||||||
feels more like a mainstream chat app ([Riot], Telegram etc) and less like an IRC client.
|
feels more like a mainstream chat app ([Riot], Telegram etc) and less like an IRC client.
|
||||||
|
|
||||||
|
### Translations ###
|
||||||
|
[![Translation status](http://weblate.nheko.im/widgets/nheko/-/nheko-master/svg-badge.svg)](http://weblate.nheko.im/engage/nheko/?utm_source=widget)
|
||||||
|
|
||||||
|
Help us with translations so as many people as possible will be able to use nheko!
|
||||||
|
|
||||||
### Note regarding End-to-End encryption
|
### Note regarding End-to-End encryption
|
||||||
|
|
||||||
Currently the implementation is at best a **proof of concept** and it should only be used for
|
Currently the implementation is at best a **proof of concept** and it should only be used for
|
||||||
testing purposes.
|
testing purposes. Most importantly, it is missing device verification, so while your messages
|
||||||
|
and media are encrypted, nheko doesn't verify who gets the messages.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
Most of the features you would expect from a chat application are missing right now
|
Most of the features you would expect from a chat application are missing right now
|
||||||
but we are getting close to a more feature complete client.
|
but we are getting close to a more feature complete client.
|
||||||
Specifically there is support for:
|
Specifically there is support for:
|
||||||
- E2E encryption (text messages only: attachments are currently sent unencrypted).
|
- E2E encryption.
|
||||||
- User registration.
|
- User registration.
|
||||||
- Creating, joining & leaving rooms.
|
- Creating, joining & leaving rooms.
|
||||||
- Sending & receiving invites.
|
- Sending & receiving invites.
|
||||||
- Sending & receiving files and emoji (inline widgets for images, audio and file messages).
|
- Sending & receiving files and emoji (inline widgets for images, audio and file messages).
|
||||||
|
- Replies with text, images and other media (and actually render them as inline widgets).
|
||||||
- Typing notifications.
|
- Typing notifications.
|
||||||
- Username auto-completion.
|
- Username auto-completion.
|
||||||
- Message & mention notifications.
|
- Message & mention notifications.
|
||||||
|
@ -62,7 +69,7 @@ sudo dnf install nheko
|
||||||
|
|
||||||
#### Gentoo Linux
|
#### Gentoo Linux
|
||||||
```bash
|
```bash
|
||||||
sudo layman -a matrix
|
sudo eselect repository enable matrix
|
||||||
sudo emerge -a nheko
|
sudo emerge -a nheko
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -86,7 +93,8 @@ flatpak install flathub io.github.NhekoReborn.Nheko
|
||||||
guix install nheko
|
guix install nheko
|
||||||
```
|
```
|
||||||
|
|
||||||
#### macOS (10.12 and above)
|
#### macOS (10.14 and above)
|
||||||
|
|
||||||
|
|
||||||
with [macports](https://www.macports.org/) :
|
with [macports](https://www.macports.org/) :
|
||||||
|
|
||||||
|
@ -96,21 +104,43 @@ sudo port install nheko
|
||||||
|
|
||||||
### Build Requirements
|
### Build Requirements
|
||||||
|
|
||||||
- Qt5 (5.7 or greater). Qt 5.7 adds support for color font rendering with
|
- Qt5 (5.10 or greater). Qt 5.7 adds support for color font rendering with
|
||||||
Freetype, which is essential to properly support emoji.
|
Freetype, which is essential to properly support emoji, 5.8 adds some features
|
||||||
- CMake 3.1 or greater.
|
to make interopability with Qml easier, 5.10 makes sliders actually visible with different palettes.
|
||||||
|
- CMake 3.15 or greater. (Lower version may work, but may break boost linking)
|
||||||
- [mtxclient](https://github.com/Nheko-Reborn/mtxclient)
|
- [mtxclient](https://github.com/Nheko-Reborn/mtxclient)
|
||||||
- [LMDB](https://symas.com/lightning-memory-mapped-database/)
|
- [LMDB](https://symas.com/lightning-memory-mapped-database/)
|
||||||
- [cmark](https://github.com/commonmark/cmark)
|
- [cmark](https://github.com/commonmark/cmark) 0.29 or greater.
|
||||||
- Boost 1.66 or greater.
|
- Boost 1.70 or greater.
|
||||||
- [libolm](https://git.matrix.org/git/olm)
|
- [libolm](https://git.matrix.org/git/olm)
|
||||||
- [libsodium](https://github.com/jedisct1/libsodium)
|
- [libsodium](https://github.com/jedisct1/libsodium)
|
||||||
- [spdlog](https://github.com/gabime/spdlog)
|
- [spdlog](https://github.com/gabime/spdlog)
|
||||||
- A compiler that supports C++ 14:
|
- A compiler that supports C++ 17:
|
||||||
- Clang 5 (tested on Travis CI)
|
- Clang 6 (tested on Travis CI)
|
||||||
- GCC 7 (tested on Travis CI)
|
- GCC 7 (tested on Travis CI)
|
||||||
- MSVC 19.13 (tested on AppVeyor)
|
- MSVC 19.13 (tested on AppVeyor)
|
||||||
|
|
||||||
|
Nheko can use bundled version for most of those libraries automatically, if the versions in your distro are too old.
|
||||||
|
To use them, you can enable the hunter integration by passing `-DHUNTER_ENABLED=ON`.
|
||||||
|
It is probably wise to link those dependencies statically by passing `-DBUILD_SHARED_LIBS=OFF`
|
||||||
|
You can select which bundled dependencies you want to use py passing various `-DUSE_BUNDLED_*` flags. By default all dependencies are bundled *if* you enable hunter.
|
||||||
|
|
||||||
|
The bundle flags are currently:
|
||||||
|
|
||||||
|
- USE_BUNDLED_BOOST
|
||||||
|
- USE_BUNDLED_SPDLOG
|
||||||
|
- USE_BUNDLED_OLM
|
||||||
|
- USE_BUNDLED_GTEST
|
||||||
|
- USE_BUNDLED_CMARK
|
||||||
|
- USE_BUNDLED_JSON
|
||||||
|
- USE_BUNDLED_OPENSSL
|
||||||
|
- USE_BUNDLED_MTXCLIENT
|
||||||
|
- USE_BUNDLED_SODIUM
|
||||||
|
- USE_BUNDLED_ZLIB
|
||||||
|
- USE_BUNDLED_LMDB
|
||||||
|
- USE_BUNDLED_LMDBXX
|
||||||
|
- USE_BUNDLED_TWEENY
|
||||||
|
|
||||||
#### Linux
|
#### Linux
|
||||||
|
|
||||||
If you don't want to install any external dependencies, you can generate an AppImage locally using docker.
|
If you don't want to install any external dependencies, you can generate an AppImage locally using docker.
|
||||||
|
@ -138,26 +168,45 @@ sudo pacman -S qt5-base \
|
||||||
##### Gentoo Linux
|
##### Gentoo Linux
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo emerge -a ">=dev-qt/qtgui-5.7.1" media-libs/fontconfig
|
sudo emerge -a ">=dev-qt/qtgui-5.9.0" media-libs/fontconfig
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Ubuntu (e.g 14.04)
|
##### Ubuntu 16.04
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo add-apt-repository ppa:beineri/opt-qt592-trusty
|
sudo add-apt-repository ppa:beineri/opt-qt592-xenial
|
||||||
sudo add-apt-repository ppa:george-edison55/cmake-3.x
|
sudo add-apt-repository ppa:george-edison55/cmake-3.x
|
||||||
sudo add-apt-repository ppa:ubuntu-toolchain-r-test
|
sudo add-apt-repository ppa:ubuntu-toolchain-r-test
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y g++-7 qt59base qt59svg qt59tools qt59multimedia cmake liblmdb-dev libsodium-dev
|
sudo apt-get install -y g++-7 qt59base qt59svg qt59tools qt59multimedia cmake liblmdb-dev libsodium-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##### Ubuntu 19.10
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build requirements + qml modules needed at runtime (you may not need all of them, but the following seem to work according to reports):
|
||||||
|
sudo apt install g++-7 cmake liblmdb-dev libsodium-dev qt{base,tools,multimedia}5-dev qml-module-qt{gstreamer,multimedia,quick-extras} libqt5svg5-dev qt{script,quickcontrols2-}5-dev
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Debian Buster (or higher probably)
|
||||||
|
|
||||||
|
(User report, not sure if all of those are needed)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install cmake gcc make automake liblmdb-dev libsodium-dev \
|
||||||
|
qt5-default libssl-dev libqt5multimedia5-plugins libqt5multimediagsttools5 libqt5multimediaquick5 libqt5svg5-dev \
|
||||||
|
qml-module-qtgstreamer qtmultimedia5-dev qtquickcontrols2-5-dev qttools5-dev qttools5-dev-tools \
|
||||||
|
qml-module-qtgraphicaleffects qml-module-qtmultimedia qml-module-qtquick-controls2 qml-module-qtquick-layouts
|
||||||
|
```
|
||||||
|
|
||||||
##### Guix
|
##### Guix
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
guix environment nheko
|
guix environment nheko
|
||||||
```
|
```
|
||||||
|
|
||||||
##### macOS (Xcode 8 or later)
|
##### macOS (Xcode 10.2 or later)
|
||||||
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
brew update
|
brew update
|
||||||
|
@ -170,61 +219,29 @@ brew install qt5 lmdb cmake llvm libsodium spdlog boost cmark
|
||||||
(for the CMake integration) workloads.
|
(for the CMake integration) workloads.
|
||||||
|
|
||||||
2. Download the latest Qt for windows installer and install it somewhere.
|
2. Download the latest Qt for windows installer and install it somewhere.
|
||||||
Make sure to install the `MSVC 2017 64-bit` toolset for at least Qt 5.9
|
Make sure to install the `MSVC 2017 64-bit` toolset for at least Qt 5.10
|
||||||
(lower versions does not support VS2017).
|
(lower versions does not support VS2017).
|
||||||
|
|
||||||
3. Install dependencies with `vcpkg`. You can simply clone it into a subfolder
|
3. If you don't have openssl installed, you will need to install perl to build it (i.e. Strawberry Perl).
|
||||||
of the root nheko source directory.
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
git clone http:\\github.com\Microsoft\vcpkg
|
|
||||||
cd vcpkg
|
|
||||||
.\bootstrap-vcpkg.bat
|
|
||||||
.\vcpkg install --triplet x64-windows \
|
|
||||||
boost-asio \
|
|
||||||
boost-beast \
|
|
||||||
boost-iostreams \
|
|
||||||
boost-random \
|
|
||||||
boost-signals2 \
|
|
||||||
boost-system \
|
|
||||||
boost-thread \
|
|
||||||
cmark \
|
|
||||||
libsodium \
|
|
||||||
lmdb \
|
|
||||||
openssl \
|
|
||||||
zlib
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Install dependencies not managed by vcpkg. (libolm, libmtxclient, libmatrix_structs)
|
|
||||||
|
|
||||||
Inside the project root run the following (replacing the path to vcpkg as necessary).
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cmake -G "Visual Studio 15 2017 Win64" -Hdeps -B.deps
|
|
||||||
-DCMAKE_TOOLCHAIN_FILE=C:/Users/<your-path>/vcpkg/scripts/buildsystems/vcpkg.cmake
|
|
||||||
-DUSE_BUNDLED_BOOST=OFF
|
|
||||||
cmake --build .deps --config Release
|
|
||||||
cmake --build .deps --config Debug
|
|
||||||
```
|
|
||||||
|
|
||||||
### Building
|
### Building
|
||||||
|
|
||||||
First we need to install the rest of the dependencies that are not available in our system
|
We can now build nheko:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cmake -Hdeps -B.deps \
|
cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release
|
||||||
-DUSE_BUNDLED_BOOST=OFF # if we already have boost & spdlog installed.
|
|
||||||
-DUSE_BUNDLED_SPDLOG=OFF
|
|
||||||
cmake --build .deps
|
|
||||||
```
|
|
||||||
|
|
||||||
We can now build nheko by pointing it to the path that we installed the dependencies.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=.deps/usr
|
|
||||||
cmake --build build
|
cmake --build build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To use bundled dependencies you can use hunter, i.e.:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake -H. -Bbuild -DHUNTER_ENABLED=ON -DBUILD_SHARED_LIBS=OFF -DUSE_BUNDLED_OPENSSL=OFF
|
||||||
|
cmake --build build --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
Adapt the USE_BUNDLED_* as needed.
|
||||||
|
|
||||||
If the build fails with the following error
|
If the build fails with the following error
|
||||||
```
|
```
|
||||||
Could not find a package configuration file provided by "Qt5Widgets" with
|
Could not find a package configuration file provided by "Qt5Widgets" with
|
||||||
|
@ -249,13 +266,14 @@ The `nheko` binary will be located in the `build` directory.
|
||||||
After installing all dependencies, you need to edit the `CMakeSettings.json` to
|
After installing all dependencies, you need to edit the `CMakeSettings.json` to
|
||||||
be able to load and compile nheko within Visual Studio.
|
be able to load and compile nheko within Visual Studio.
|
||||||
|
|
||||||
You need to fill out the paths for the `CMAKE_TOOLCHAIN_FILE` and the `Qt5_DIR`.
|
You need to fill out the paths for the `Qt5_DIR`.
|
||||||
The toolchain file should point to the `vcpkg.cmake` and the Qt5 dir to the `lib\cmake\Qt5` dir.
|
The Qt5 dir should point to the `lib\cmake\Qt5` dir.
|
||||||
|
|
||||||
Examples for the paths are:
|
Examples for the paths are:
|
||||||
- `C:\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake`
|
|
||||||
- `C:\\Qt\\5.10.1\\msvc2017_64\\lib\\cmake\\Qt5`
|
- `C:\\Qt\\5.10.1\\msvc2017_64\\lib\\cmake\\Qt5`
|
||||||
|
|
||||||
|
You should also enable hunter by setting `HUNTER_ENABLED` to `ON` and `BUILD_SHARED_LIBS` to `OFF`.
|
||||||
|
|
||||||
Now right click into the root nheko source directory and choose `Open in Visual Studio`.
|
Now right click into the root nheko source directory and choose `Open in Visual Studio`.
|
||||||
You can choose the build type Release and Debug in the top toolbar.
|
You can choose the build type Release and Debug in the top toolbar.
|
||||||
After a successful CMake generation you can select the `nheko.exe` as the run target.
|
After a successful CMake generation you can select the `nheko.exe` as the run target.
|
||||||
|
@ -273,6 +291,9 @@ windeployqt nheko.exe
|
||||||
The final binary will be located inside `build-vc\Release\Release` for the Release build
|
The final binary will be located inside `build-vc\Release\Release` for the Release build
|
||||||
and `build-vc\Debug\Debug` for the Debug build.
|
and `build-vc\Debug\Debug` for the Debug build.
|
||||||
|
|
||||||
|
Also copy the respective cmark.dll to the binary dir from `build/cmark-build/src/Release` (or Debug).
|
||||||
|
|
||||||
|
|
||||||
### Contributing
|
### Contributing
|
||||||
|
|
||||||
See [CONTRIBUTING](.github/CONTRIBUTING.md)
|
See [CONTRIBUTING](.github/CONTRIBUTING.md)
|
||||||
|
@ -288,9 +309,7 @@ Here are some screen shots to get a feel for the UI, but things will probably ch
|
||||||
|
|
||||||
### Third party
|
### Third party
|
||||||
|
|
||||||
- [Emoji One](http://emojione.com)
|
[Single Application for Qt](https://github.com/itay-grudev/SingleApplication)
|
||||||
- [Font Awesome](http://fontawesome.io/)
|
|
||||||
- [Open Sans](https://fonts.google.com/specimen/Open+Sans)
|
|
||||||
|
|
||||||
[Matrix]:https://matrix.org
|
[Matrix]:https://matrix.org
|
||||||
[Riot]:https://riot.im
|
[Riot]:https://riot.im
|
||||||
|
|
77
appveyor.yml
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
|
|
||||||
version: 0.6.4-{build}
|
version: 0.7.0-{build}
|
||||||
|
|
||||||
configuration: Release
|
configuration: Release
|
||||||
image: Visual Studio 2017
|
image: Visual Studio 2017
|
||||||
|
@ -10,30 +10,17 @@ environment:
|
||||||
BINTRAY_APIKEY:
|
BINTRAY_APIKEY:
|
||||||
secure: "iGl5mzE9/ta9kFELUxDw9XtlYMSCMai9xowXIkYzU8WKHz7NfW0mLwMJZvblZFXJ"
|
secure: "iGl5mzE9/ta9kFELUxDw9XtlYMSCMai9xowXIkYzU8WKHz7NfW0mLwMJZvblZFXJ"
|
||||||
|
|
||||||
cache: c:\tools\vcpkg\installed\
|
cache:
|
||||||
|
- c:\hunter\ -> appveyor.yml
|
||||||
|
- build\_deps -> appveyor.yml,deps\CMakeLists.txt
|
||||||
|
|
||||||
build:
|
build:
|
||||||
verbosity: minimal
|
verbosity: minimal
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- set QT_DIR=C:\Qt\5.10.1\msvc2017_64
|
- set QT_DIR=C:\Qt\5.13\msvc2017_64
|
||||||
- set PATH=%PATH%;%QT_DIR%\bin;C:\MinGW\bin
|
- set PATH=%PATH%;%QT_DIR%\bin
|
||||||
- set PATH=%PATH%;C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin
|
|
||||||
- call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat"
|
- call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat"
|
||||||
- cd "C:\Tools\vcpkg"&& git pull && .\bootstrap-vcpkg.bat && cd %APPVEYOR_BUILD_FOLDER%
|
|
||||||
- vcpkg install
|
|
||||||
nlohmann-json:%PLATFORM%-windows
|
|
||||||
boost-asio:%PLATFORM%-windows
|
|
||||||
boost-beast:%PLATFORM%-windows
|
|
||||||
boost-iostreams:%PLATFORM%-windows
|
|
||||||
boost-random:%PLATFORM%-windows
|
|
||||||
boost-signals2:%PLATFORM%-windows
|
|
||||||
boost-system:%PLATFORM%-windows
|
|
||||||
boost-thread:%PLATFORM%-windows
|
|
||||||
libsodium:%PLATFORM%-windows
|
|
||||||
lmdb:%PLATFORM%-windows
|
|
||||||
openssl:%PLATFORM%-windows
|
|
||||||
zlib:%PLATFORM%-windows
|
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
# VERSION format: branch-master/branch-1.2
|
# VERSION format: branch-master/branch-1.2
|
||||||
|
@ -54,23 +41,13 @@ build_script:
|
||||||
- echo %INSTVERSION%
|
- echo %INSTVERSION%
|
||||||
- echo %DATE%
|
- echo %DATE%
|
||||||
|
|
||||||
# Build & install the dependencies
|
|
||||||
- cmake -G "Visual Studio 15 2017 Win64" -Hdeps -B.deps
|
|
||||||
-DCMAKE_TOOLCHAIN_FILE=C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake
|
|
||||||
-DUSE_BUNDLED_BOOST=OFF
|
|
||||||
-DUSE_BUNDLED_JSON=OFF
|
|
||||||
-DMTX_STATIC=ON
|
|
||||||
- cmake --build .deps --config Release
|
|
||||||
|
|
||||||
# Build nheko
|
# Build nheko
|
||||||
- rm -f cmake/FindOlm.cmake
|
#- cmake -G "Visual Studio 16 2019" -A x64 -H. -Bbuild
|
||||||
- cmake -G "Visual Studio 15 2017 Win64" -H. -Bbuild
|
- cmake -G "Visual Studio 15 2017 Win64" -H. -Bbuild
|
||||||
-DCMAKE_TOOLCHAIN_FILE=C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake
|
-DHUNTER_ROOT="C:\hunter"
|
||||||
-DLMDBXX_INCLUDE_DIR=.deps/usr/include
|
-DHUNTER_ENABLED=ON -DBUILD_SHARED_LIBS=OFF
|
||||||
-DTWEENY_INCLUDE_DIR=.deps/usr/include
|
-DCMAKE_BUILD_TYPE=Release -DHUNTER_CONFIGURATION_TYPES=Release
|
||||||
-DCMARK_INCLUDE_DIR=C:/projects/nheko/.deps/usr/include
|
|
||||||
-DCMARK_LIBRARY=C:/projects/nheko/.deps/usr/lib/cmark.lib
|
|
||||||
-DJSON_INCLUDE_DIR=.deps/usr/include
|
|
||||||
- cmake --build build --config Release
|
- cmake --build build --config Release
|
||||||
|
|
||||||
after_build:
|
after_build:
|
||||||
|
@ -79,14 +56,9 @@ after_build:
|
||||||
- echo %BUILD%
|
- echo %BUILD%
|
||||||
- mkdir NhekoRelease
|
- mkdir NhekoRelease
|
||||||
- copy build\Release\nheko.exe NhekoRelease\nheko.exe
|
- copy build\Release\nheko.exe NhekoRelease\nheko.exe
|
||||||
|
- copy build\_deps\cmark-build\src\Release\cmark.dll NhekoRelease\cmark.dll
|
||||||
- windeployqt --qmldir %QT_DIR%\qml\ --release NhekoRelease\nheko.exe
|
- windeployqt --qmldir %QT_DIR%\qml\ --release NhekoRelease\nheko.exe
|
||||||
|
|
||||||
- copy C:\Tools\vcpkg\installed\x64-windows\lib\*.lib .\NhekoRelease\
|
|
||||||
- copy C:\Tools\vcpkg\installed\x64-windows\bin\*.dll .\NhekoRelease\
|
|
||||||
|
|
||||||
- copy C:\projects\nheko\.deps\usr\lib\cmark.lib .\NhekoRelease\
|
|
||||||
- copy C:\projects\nheko\.deps\usr\bin\cmark.dll .\NhekoRelease\
|
|
||||||
|
|
||||||
- 7z a nheko_win_64.zip .\NhekoRelease\*
|
- 7z a nheko_win_64.zip .\NhekoRelease\*
|
||||||
- ls -lh build\Release\
|
- ls -lh build\Release\
|
||||||
- ls -lh NhekoRelease\
|
- ls -lh NhekoRelease\
|
||||||
|
@ -135,15 +107,22 @@ on_success:
|
||||||
- if "%APPVEYOR_REPO_TAG%" == "true" (curl -T nheko-%APPVEYOR_REPO_TAG_NAME%-installer.exe -uredsky17:%BINTRAY_APIKEY% https://api.bintray.com/content/nheko-reborn/nheko/%APPVEYOR_REPO_TAG_NAME%/nheko/%APPVEYOR_REPO_TAG_NAME%/)
|
- if "%APPVEYOR_REPO_TAG%" == "true" (curl -T nheko-%APPVEYOR_REPO_TAG_NAME%-installer.exe -uredsky17:%BINTRAY_APIKEY% https://api.bintray.com/content/nheko-reborn/nheko/%APPVEYOR_REPO_TAG_NAME%/nheko/%APPVEYOR_REPO_TAG_NAME%/)
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
description: "Development builds"
|
- description: "Development builds"
|
||||||
provider: GitHub
|
provider: GitHub
|
||||||
auth_token:
|
auth_token:
|
||||||
secure: "ShStWeqp+TkYqJPQr7uFZb+B8ZTgC7Iwth+IkhjfRDCTLhy8gtWvlPzlQilder3E"
|
secure: "ShStWeqp+TkYqJPQr7uFZb+B8ZTgC7Iwth+IkhjfRDCTLhy8gtWvlPzlQilder3E"
|
||||||
artifact: nheko-${APPVEYOR_REPO_TAG_NAME}-installer.exe
|
artifact: nheko-${APPVEYOR_REPO_TAG_NAME}-installer.exe
|
||||||
force_update: true
|
force_update: true
|
||||||
prerelease: true
|
prerelease: true
|
||||||
on:
|
on:
|
||||||
appveyor_repo_tag: true
|
appveyor_repo_tag: true
|
||||||
|
- provider: S3
|
||||||
|
access_key_id: ${AWS_ACCESS_KEY}
|
||||||
|
secret_access_key: ${AWS_SECRET_KEY}
|
||||||
|
bucket: ${AWS_BUCKET_NAME}
|
||||||
|
region: ${AWS_DEFAULT_REGION}
|
||||||
|
set_public: true
|
||||||
|
artifact: nheko-$(APPVEYOR_REPO_TAG_NAME)-installer.exe, nheko_win_64.zip
|
||||||
|
|
||||||
artifacts:
|
artifacts:
|
||||||
- path: nheko_win_64.zip
|
- path: nheko_win_64.zip
|
||||||
|
|
15
cmake/FindLMDB.cmake
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#
|
||||||
|
# Find the lmdb library & include dir.
|
||||||
|
#
|
||||||
|
|
||||||
|
find_path (LMDB_INCLUDE_DIR NAMES lmdb.h PATHS "$ENV{LMDB_DIR}/include")
|
||||||
|
find_library (LMDB_LIBRARY NAMES lmdb PATHS "$ENV{LMDB_DIR}/lib" )
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(LMDB DEFAULT_MSG LMDB_INCLUDE_DIR LMDB_LIBRARY)
|
||||||
|
|
||||||
|
|
||||||
|
add_library(lmdb INTERFACE IMPORTED GLOBAL)
|
||||||
|
target_include_directories(lmdb INTERFACE ${LMDB_INCLUDE_DIR})
|
||||||
|
target_link_libraries(lmdb INTERFACE ${LMDB_LIBRARY})
|
||||||
|
|
||||||
|
add_library(liblmdb::lmdb ALIAS lmdb)
|
|
@ -1,44 +0,0 @@
|
||||||
#
|
|
||||||
# CMake module to search for the olm library
|
|
||||||
#
|
|
||||||
# On success, the macro sets the following variables:
|
|
||||||
# OLM_FOUND = if the library found
|
|
||||||
# OLM_LIBRARY = full path to the library
|
|
||||||
# OLM_INCLUDE_DIR = where to find the library headers
|
|
||||||
#
|
|
||||||
if(WIN32)
|
|
||||||
message(STATUS "FindOlm is not supported in Windows")
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_path(OLM_INCLUDE_DIR
|
|
||||||
NAMES olm/olm.h
|
|
||||||
PATHS /usr/include
|
|
||||||
/usr/local/include
|
|
||||||
$ENV{LIB_DIR}/include
|
|
||||||
$ENV{LIB_DIR}/include/olm)
|
|
||||||
|
|
||||||
find_library(OLM_LIBRARY
|
|
||||||
NAMES olm
|
|
||||||
PATHS /usr/lib /usr/local/lib $ENV{LIB_DIR}/lib)
|
|
||||||
|
|
||||||
if(OLM_FOUND)
|
|
||||||
set(OLM_INCLUDE_DIRS ${OLM_INCLUDE_DIR})
|
|
||||||
|
|
||||||
if(NOT OLM_LIBRARIES)
|
|
||||||
set(OLM_LIBRARIES ${OLM_LIBRARY})
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT TARGET Olm::Olm)
|
|
||||||
add_library(Olm::Olm UNKNOWN IMPORTED)
|
|
||||||
set_target_properties(Olm::Olm
|
|
||||||
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
|
|
||||||
${OLM_INCLUDE_DIR})
|
|
||||||
set_property(TARGET Olm::Olm APPEND PROPERTY IMPORTED_LOCATION ${OLM_LIBRARY})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
|
||||||
find_package_handle_standard_args(OLM DEFAULT_MSG OLM_INCLUDE_DIR OLM_LIBRARY)
|
|
||||||
|
|
||||||
mark_as_advanced(OLM_LIBRARY OLM_INCLUDE_DIR)
|
|
5
cmake/Hunter/config.cmake
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
hunter_config(
|
||||||
|
Boost
|
||||||
|
VERSION "1.70.0-p0"
|
||||||
|
CMAKE_ARGS IOSTREAMS_NO_BZIP2=1
|
||||||
|
)
|
528
cmake/HunterGate.cmake
Normal file
|
@ -0,0 +1,528 @@
|
||||||
|
# Copyright (c) 2013-2019, Ruslan Baratov
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright notice, this
|
||||||
|
# list of conditions and the following disclaimer.
|
||||||
|
#
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
# This is a gate file to Hunter package manager.
|
||||||
|
# Include this file using `include` command and add package you need, example:
|
||||||
|
#
|
||||||
|
# cmake_minimum_required(VERSION 3.2)
|
||||||
|
#
|
||||||
|
# include("cmake/HunterGate.cmake")
|
||||||
|
# HunterGate(
|
||||||
|
# URL "https://github.com/path/to/hunter/archive.tar.gz"
|
||||||
|
# SHA1 "798501e983f14b28b10cda16afa4de69eee1da1d"
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# project(MyProject)
|
||||||
|
#
|
||||||
|
# hunter_add_package(Foo)
|
||||||
|
# hunter_add_package(Boo COMPONENTS Bar Baz)
|
||||||
|
#
|
||||||
|
# Projects:
|
||||||
|
# * https://github.com/hunter-packages/gate/
|
||||||
|
# * https://github.com/ruslo/hunter
|
||||||
|
|
||||||
|
option(HUNTER_ENABLED "Enable Hunter package manager support" ON)
|
||||||
|
|
||||||
|
if(HUNTER_ENABLED)
|
||||||
|
if(CMAKE_VERSION VERSION_LESS "3.2")
|
||||||
|
message(
|
||||||
|
FATAL_ERROR
|
||||||
|
"At least CMake version 3.2 required for Hunter dependency management."
|
||||||
|
" Update CMake or set HUNTER_ENABLED to OFF."
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(CMakeParseArguments) # cmake_parse_arguments
|
||||||
|
|
||||||
|
option(HUNTER_STATUS_PRINT "Print working status" ON)
|
||||||
|
option(HUNTER_STATUS_DEBUG "Print a lot info" OFF)
|
||||||
|
option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON)
|
||||||
|
|
||||||
|
set(HUNTER_ERROR_PAGE "https://docs.hunter.sh/en/latest/reference/errors")
|
||||||
|
|
||||||
|
function(hunter_gate_status_print)
|
||||||
|
if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG)
|
||||||
|
foreach(print_message ${ARGV})
|
||||||
|
message(STATUS "[hunter] ${print_message}")
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(hunter_gate_status_debug)
|
||||||
|
if(HUNTER_STATUS_DEBUG)
|
||||||
|
foreach(print_message ${ARGV})
|
||||||
|
string(TIMESTAMP timestamp)
|
||||||
|
message(STATUS "[hunter *** DEBUG *** ${timestamp}] ${print_message}")
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(hunter_gate_error_page error_page)
|
||||||
|
message("------------------------------ ERROR ------------------------------")
|
||||||
|
message(" ${HUNTER_ERROR_PAGE}/${error_page}.html")
|
||||||
|
message("-------------------------------------------------------------------")
|
||||||
|
message("")
|
||||||
|
message(FATAL_ERROR "")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(hunter_gate_internal_error)
|
||||||
|
message("")
|
||||||
|
foreach(print_message ${ARGV})
|
||||||
|
message("[hunter ** INTERNAL **] ${print_message}")
|
||||||
|
endforeach()
|
||||||
|
message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
|
||||||
|
message("")
|
||||||
|
hunter_gate_error_page("error.internal")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(hunter_gate_fatal_error)
|
||||||
|
cmake_parse_arguments(hunter "" "ERROR_PAGE" "" "${ARGV}")
|
||||||
|
if("${hunter_ERROR_PAGE}" STREQUAL "")
|
||||||
|
hunter_gate_internal_error("Expected ERROR_PAGE")
|
||||||
|
endif()
|
||||||
|
message("")
|
||||||
|
foreach(x ${hunter_UNPARSED_ARGUMENTS})
|
||||||
|
message("[hunter ** FATAL ERROR **] ${x}")
|
||||||
|
endforeach()
|
||||||
|
message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
|
||||||
|
message("")
|
||||||
|
hunter_gate_error_page("${hunter_ERROR_PAGE}")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(hunter_gate_user_error)
|
||||||
|
hunter_gate_fatal_error(${ARGV} ERROR_PAGE "error.incorrect.input.data")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(hunter_gate_self root version sha1 result)
|
||||||
|
string(COMPARE EQUAL "${root}" "" is_bad)
|
||||||
|
if(is_bad)
|
||||||
|
hunter_gate_internal_error("root is empty")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(COMPARE EQUAL "${version}" "" is_bad)
|
||||||
|
if(is_bad)
|
||||||
|
hunter_gate_internal_error("version is empty")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(COMPARE EQUAL "${sha1}" "" is_bad)
|
||||||
|
if(is_bad)
|
||||||
|
hunter_gate_internal_error("sha1 is empty")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(SUBSTRING "${sha1}" 0 7 archive_id)
|
||||||
|
|
||||||
|
set(
|
||||||
|
hunter_self
|
||||||
|
"${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked"
|
||||||
|
)
|
||||||
|
|
||||||
|
set("${result}" "${hunter_self}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Set HUNTER_GATE_ROOT cmake variable to suitable value.
|
||||||
|
function(hunter_gate_detect_root)
|
||||||
|
# Check CMake variable
|
||||||
|
string(COMPARE NOTEQUAL "${HUNTER_ROOT}" "" not_empty)
|
||||||
|
if(not_empty)
|
||||||
|
set(HUNTER_GATE_ROOT "${HUNTER_ROOT}" PARENT_SCOPE)
|
||||||
|
hunter_gate_status_debug("HUNTER_ROOT detected by cmake variable")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check environment variable
|
||||||
|
string(COMPARE NOTEQUAL "$ENV{HUNTER_ROOT}" "" not_empty)
|
||||||
|
if(not_empty)
|
||||||
|
set(HUNTER_GATE_ROOT "$ENV{HUNTER_ROOT}" PARENT_SCOPE)
|
||||||
|
hunter_gate_status_debug("HUNTER_ROOT detected by environment variable")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check HOME environment variable
|
||||||
|
string(COMPARE NOTEQUAL "$ENV{HOME}" "" result)
|
||||||
|
if(result)
|
||||||
|
set(HUNTER_GATE_ROOT "$ENV{HOME}/.hunter" PARENT_SCOPE)
|
||||||
|
hunter_gate_status_debug("HUNTER_ROOT set using HOME environment variable")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check SYSTEMDRIVE and USERPROFILE environment variable (windows only)
|
||||||
|
if(WIN32)
|
||||||
|
string(COMPARE NOTEQUAL "$ENV{SYSTEMDRIVE}" "" result)
|
||||||
|
if(result)
|
||||||
|
set(HUNTER_GATE_ROOT "$ENV{SYSTEMDRIVE}/.hunter" PARENT_SCOPE)
|
||||||
|
hunter_gate_status_debug(
|
||||||
|
"HUNTER_ROOT set using SYSTEMDRIVE environment variable"
|
||||||
|
)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(COMPARE NOTEQUAL "$ENV{USERPROFILE}" "" result)
|
||||||
|
if(result)
|
||||||
|
set(HUNTER_GATE_ROOT "$ENV{USERPROFILE}/.hunter" PARENT_SCOPE)
|
||||||
|
hunter_gate_status_debug(
|
||||||
|
"HUNTER_ROOT set using USERPROFILE environment variable"
|
||||||
|
)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
hunter_gate_fatal_error(
|
||||||
|
"Can't detect HUNTER_ROOT"
|
||||||
|
ERROR_PAGE "error.detect.hunter.root"
|
||||||
|
)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(hunter_gate_download dir)
|
||||||
|
string(
|
||||||
|
COMPARE
|
||||||
|
NOTEQUAL
|
||||||
|
"$ENV{HUNTER_DISABLE_AUTOINSTALL}"
|
||||||
|
""
|
||||||
|
disable_autoinstall
|
||||||
|
)
|
||||||
|
if(disable_autoinstall AND NOT HUNTER_RUN_INSTALL)
|
||||||
|
hunter_gate_fatal_error(
|
||||||
|
"Hunter not found in '${dir}'"
|
||||||
|
"Set HUNTER_RUN_INSTALL=ON to auto-install it from '${HUNTER_GATE_URL}'"
|
||||||
|
"Settings:"
|
||||||
|
" HUNTER_ROOT: ${HUNTER_GATE_ROOT}"
|
||||||
|
" HUNTER_SHA1: ${HUNTER_GATE_SHA1}"
|
||||||
|
ERROR_PAGE "error.run.install"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
string(COMPARE EQUAL "${dir}" "" is_bad)
|
||||||
|
if(is_bad)
|
||||||
|
hunter_gate_internal_error("Empty 'dir' argument")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" is_bad)
|
||||||
|
if(is_bad)
|
||||||
|
hunter_gate_internal_error("HUNTER_GATE_SHA1 empty")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" is_bad)
|
||||||
|
if(is_bad)
|
||||||
|
hunter_gate_internal_error("HUNTER_GATE_URL empty")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(done_location "${dir}/DONE")
|
||||||
|
set(sha1_location "${dir}/SHA1")
|
||||||
|
|
||||||
|
set(build_dir "${dir}/Build")
|
||||||
|
set(cmakelists "${dir}/CMakeLists.txt")
|
||||||
|
|
||||||
|
hunter_gate_status_debug("Locking directory: ${dir}")
|
||||||
|
file(LOCK "${dir}" DIRECTORY GUARD FUNCTION)
|
||||||
|
hunter_gate_status_debug("Lock done")
|
||||||
|
|
||||||
|
if(EXISTS "${done_location}")
|
||||||
|
# while waiting for lock other instance can do all the job
|
||||||
|
hunter_gate_status_debug("File '${done_location}' found, skip install")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(REMOVE_RECURSE "${build_dir}")
|
||||||
|
file(REMOVE_RECURSE "${cmakelists}")
|
||||||
|
|
||||||
|
file(MAKE_DIRECTORY "${build_dir}") # check directory permissions
|
||||||
|
|
||||||
|
# Disabling languages speeds up a little bit, reduces noise in the output
|
||||||
|
# and avoids path too long windows error
|
||||||
|
file(
|
||||||
|
WRITE
|
||||||
|
"${cmakelists}"
|
||||||
|
"cmake_minimum_required(VERSION 3.2)\n"
|
||||||
|
"project(HunterDownload LANGUAGES NONE)\n"
|
||||||
|
"include(ExternalProject)\n"
|
||||||
|
"ExternalProject_Add(\n"
|
||||||
|
" Hunter\n"
|
||||||
|
" URL\n"
|
||||||
|
" \"${HUNTER_GATE_URL}\"\n"
|
||||||
|
" URL_HASH\n"
|
||||||
|
" SHA1=${HUNTER_GATE_SHA1}\n"
|
||||||
|
" DOWNLOAD_DIR\n"
|
||||||
|
" \"${dir}\"\n"
|
||||||
|
" TLS_VERIFY\n"
|
||||||
|
" ${HUNTER_TLS_VERIFY}\n"
|
||||||
|
" SOURCE_DIR\n"
|
||||||
|
" \"${dir}/Unpacked\"\n"
|
||||||
|
" CONFIGURE_COMMAND\n"
|
||||||
|
" \"\"\n"
|
||||||
|
" BUILD_COMMAND\n"
|
||||||
|
" \"\"\n"
|
||||||
|
" INSTALL_COMMAND\n"
|
||||||
|
" \"\"\n"
|
||||||
|
")\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(HUNTER_STATUS_DEBUG)
|
||||||
|
set(logging_params "")
|
||||||
|
else()
|
||||||
|
set(logging_params OUTPUT_QUIET)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
hunter_gate_status_debug("Run generate")
|
||||||
|
|
||||||
|
# Need to add toolchain file too.
|
||||||
|
# Otherwise on Visual Studio + MDD this will fail with error:
|
||||||
|
# "Could not find an appropriate version of the Windows 10 SDK installed on this machine"
|
||||||
|
if(EXISTS "${CMAKE_TOOLCHAIN_FILE}")
|
||||||
|
get_filename_component(absolute_CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE)
|
||||||
|
set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${absolute_CMAKE_TOOLCHAIN_FILE}")
|
||||||
|
else()
|
||||||
|
# 'toolchain_arg' can't be empty
|
||||||
|
set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(COMPARE EQUAL "${CMAKE_MAKE_PROGRAM}" "" no_make)
|
||||||
|
if(no_make)
|
||||||
|
set(make_arg "")
|
||||||
|
else()
|
||||||
|
# Test case: remove Ninja from PATH but set it via CMAKE_MAKE_PROGRAM
|
||||||
|
set(make_arg "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND
|
||||||
|
"${CMAKE_COMMAND}"
|
||||||
|
"-H${dir}"
|
||||||
|
"-B${build_dir}"
|
||||||
|
"-G${CMAKE_GENERATOR}"
|
||||||
|
"${toolchain_arg}"
|
||||||
|
${make_arg}
|
||||||
|
WORKING_DIRECTORY "${dir}"
|
||||||
|
RESULT_VARIABLE download_result
|
||||||
|
${logging_params}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT download_result EQUAL 0)
|
||||||
|
hunter_gate_internal_error(
|
||||||
|
"Configure project failed."
|
||||||
|
"To reproduce the error run: ${CMAKE_COMMAND} -H${dir} -B${build_dir} -G${CMAKE_GENERATOR} ${toolchain_arg} ${make_arg}"
|
||||||
|
"In directory ${dir}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
hunter_gate_status_print(
|
||||||
|
"Initializing Hunter workspace (${HUNTER_GATE_SHA1})"
|
||||||
|
" ${HUNTER_GATE_URL}"
|
||||||
|
" -> ${dir}"
|
||||||
|
)
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${CMAKE_COMMAND}" --build "${build_dir}"
|
||||||
|
WORKING_DIRECTORY "${dir}"
|
||||||
|
RESULT_VARIABLE download_result
|
||||||
|
${logging_params}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT download_result EQUAL 0)
|
||||||
|
hunter_gate_internal_error("Build project failed")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(REMOVE_RECURSE "${build_dir}")
|
||||||
|
file(REMOVE_RECURSE "${cmakelists}")
|
||||||
|
|
||||||
|
file(WRITE "${sha1_location}" "${HUNTER_GATE_SHA1}")
|
||||||
|
file(WRITE "${done_location}" "DONE")
|
||||||
|
|
||||||
|
hunter_gate_status_debug("Finished")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Must be a macro so master file 'cmake/Hunter' can
|
||||||
|
# apply all variables easily just by 'include' command
|
||||||
|
# (otherwise PARENT_SCOPE magic needed)
|
||||||
|
macro(HunterGate)
|
||||||
|
if(HUNTER_GATE_DONE)
|
||||||
|
# variable HUNTER_GATE_DONE set explicitly for external project
|
||||||
|
# (see `hunter_download`)
|
||||||
|
set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# First HunterGate command will init Hunter, others will be ignored
|
||||||
|
get_property(_hunter_gate_done GLOBAL PROPERTY HUNTER_GATE_DONE SET)
|
||||||
|
|
||||||
|
if(NOT HUNTER_ENABLED)
|
||||||
|
# Empty function to avoid error "unknown function"
|
||||||
|
function(hunter_add_package)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
set(
|
||||||
|
_hunter_gate_disabled_mode_dir
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/cmake/Hunter/disabled-mode"
|
||||||
|
)
|
||||||
|
if(EXISTS "${_hunter_gate_disabled_mode_dir}")
|
||||||
|
hunter_gate_status_debug(
|
||||||
|
"Adding \"disabled-mode\" modules: ${_hunter_gate_disabled_mode_dir}"
|
||||||
|
)
|
||||||
|
list(APPEND CMAKE_PREFIX_PATH "${_hunter_gate_disabled_mode_dir}")
|
||||||
|
endif()
|
||||||
|
elseif(_hunter_gate_done)
|
||||||
|
hunter_gate_status_debug("Secondary HunterGate (use old settings)")
|
||||||
|
hunter_gate_self(
|
||||||
|
"${HUNTER_CACHED_ROOT}"
|
||||||
|
"${HUNTER_VERSION}"
|
||||||
|
"${HUNTER_SHA1}"
|
||||||
|
_hunter_self
|
||||||
|
)
|
||||||
|
include("${_hunter_self}/cmake/Hunter")
|
||||||
|
else()
|
||||||
|
set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
|
||||||
|
string(COMPARE NOTEQUAL "${PROJECT_NAME}" "" _have_project_name)
|
||||||
|
if(_have_project_name)
|
||||||
|
hunter_gate_fatal_error(
|
||||||
|
"Please set HunterGate *before* 'project' command. "
|
||||||
|
"Detected project: ${PROJECT_NAME}"
|
||||||
|
ERROR_PAGE "error.huntergate.before.project"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
cmake_parse_arguments(
|
||||||
|
HUNTER_GATE "LOCAL" "URL;SHA1;GLOBAL;FILEPATH" "" ${ARGV}
|
||||||
|
)
|
||||||
|
|
||||||
|
string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" _empty_sha1)
|
||||||
|
string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" _empty_url)
|
||||||
|
string(
|
||||||
|
COMPARE
|
||||||
|
NOTEQUAL
|
||||||
|
"${HUNTER_GATE_UNPARSED_ARGUMENTS}"
|
||||||
|
""
|
||||||
|
_have_unparsed
|
||||||
|
)
|
||||||
|
string(COMPARE NOTEQUAL "${HUNTER_GATE_GLOBAL}" "" _have_global)
|
||||||
|
string(COMPARE NOTEQUAL "${HUNTER_GATE_FILEPATH}" "" _have_filepath)
|
||||||
|
|
||||||
|
if(_have_unparsed)
|
||||||
|
hunter_gate_user_error(
|
||||||
|
"HunterGate unparsed arguments: ${HUNTER_GATE_UNPARSED_ARGUMENTS}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
if(_empty_sha1)
|
||||||
|
hunter_gate_user_error("SHA1 suboption of HunterGate is mandatory")
|
||||||
|
endif()
|
||||||
|
if(_empty_url)
|
||||||
|
hunter_gate_user_error("URL suboption of HunterGate is mandatory")
|
||||||
|
endif()
|
||||||
|
if(_have_global)
|
||||||
|
if(HUNTER_GATE_LOCAL)
|
||||||
|
hunter_gate_user_error("Unexpected LOCAL (already has GLOBAL)")
|
||||||
|
endif()
|
||||||
|
if(_have_filepath)
|
||||||
|
hunter_gate_user_error("Unexpected FILEPATH (already has GLOBAL)")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if(HUNTER_GATE_LOCAL)
|
||||||
|
if(_have_global)
|
||||||
|
hunter_gate_user_error("Unexpected GLOBAL (already has LOCAL)")
|
||||||
|
endif()
|
||||||
|
if(_have_filepath)
|
||||||
|
hunter_gate_user_error("Unexpected FILEPATH (already has LOCAL)")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if(_have_filepath)
|
||||||
|
if(_have_global)
|
||||||
|
hunter_gate_user_error("Unexpected GLOBAL (already has FILEPATH)")
|
||||||
|
endif()
|
||||||
|
if(HUNTER_GATE_LOCAL)
|
||||||
|
hunter_gate_user_error("Unexpected LOCAL (already has FILEPATH)")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
hunter_gate_detect_root() # set HUNTER_GATE_ROOT
|
||||||
|
|
||||||
|
# Beautify path, fix probable problems with windows path slashes
|
||||||
|
get_filename_component(
|
||||||
|
HUNTER_GATE_ROOT "${HUNTER_GATE_ROOT}" ABSOLUTE
|
||||||
|
)
|
||||||
|
hunter_gate_status_debug("HUNTER_ROOT: ${HUNTER_GATE_ROOT}")
|
||||||
|
if(NOT HUNTER_ALLOW_SPACES_IN_PATH)
|
||||||
|
string(FIND "${HUNTER_GATE_ROOT}" " " _contain_spaces)
|
||||||
|
if(NOT _contain_spaces EQUAL -1)
|
||||||
|
hunter_gate_fatal_error(
|
||||||
|
"HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces."
|
||||||
|
"Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error"
|
||||||
|
"(Use at your own risk!)"
|
||||||
|
ERROR_PAGE "error.spaces.in.hunter.root"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(
|
||||||
|
REGEX
|
||||||
|
MATCH
|
||||||
|
"[0-9]+\\.[0-9]+\\.[0-9]+[-_a-z0-9]*"
|
||||||
|
HUNTER_GATE_VERSION
|
||||||
|
"${HUNTER_GATE_URL}"
|
||||||
|
)
|
||||||
|
string(COMPARE EQUAL "${HUNTER_GATE_VERSION}" "" _is_empty)
|
||||||
|
if(_is_empty)
|
||||||
|
set(HUNTER_GATE_VERSION "unknown")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
hunter_gate_self(
|
||||||
|
"${HUNTER_GATE_ROOT}"
|
||||||
|
"${HUNTER_GATE_VERSION}"
|
||||||
|
"${HUNTER_GATE_SHA1}"
|
||||||
|
_hunter_self
|
||||||
|
)
|
||||||
|
|
||||||
|
set(_master_location "${_hunter_self}/cmake/Hunter")
|
||||||
|
get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE)
|
||||||
|
set(_done_location "${_archive_id_location}/DONE")
|
||||||
|
set(_sha1_location "${_archive_id_location}/SHA1")
|
||||||
|
|
||||||
|
# Check Hunter already downloaded by HunterGate
|
||||||
|
if(NOT EXISTS "${_done_location}")
|
||||||
|
hunter_gate_download("${_archive_id_location}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT EXISTS "${_done_location}")
|
||||||
|
hunter_gate_internal_error("hunter_gate_download failed")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT EXISTS "${_sha1_location}")
|
||||||
|
hunter_gate_internal_error("${_sha1_location} not found")
|
||||||
|
endif()
|
||||||
|
file(READ "${_sha1_location}" _sha1_value)
|
||||||
|
string(COMPARE EQUAL "${_sha1_value}" "${HUNTER_GATE_SHA1}" _is_equal)
|
||||||
|
if(NOT _is_equal)
|
||||||
|
hunter_gate_internal_error(
|
||||||
|
"Short SHA1 collision:"
|
||||||
|
" ${_sha1_value} (from ${_sha1_location})"
|
||||||
|
" ${HUNTER_GATE_SHA1} (HunterGate)"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
if(NOT EXISTS "${_master_location}")
|
||||||
|
hunter_gate_user_error(
|
||||||
|
"Master file not found:"
|
||||||
|
" ${_master_location}"
|
||||||
|
"try to update Hunter/HunterGate"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
include("${_master_location}")
|
||||||
|
set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)
|
||||||
|
endif()
|
||||||
|
endmacro()
|
|
@ -1,29 +0,0 @@
|
||||||
#
|
|
||||||
# Find the lmdb library & include dir.
|
|
||||||
# Build lmdb on Appveyor.
|
|
||||||
#
|
|
||||||
|
|
||||||
if(APPVEYOR_BUILD)
|
|
||||||
set(LMDB_VERSION "LMDB_0.9.21")
|
|
||||||
set(NTDLIB "C:/WINDDK/7600.16385.1/lib/win7/amd64/ntdll.lib")
|
|
||||||
|
|
||||||
execute_process(
|
|
||||||
COMMAND git clone --depth=1 --branch ${LMDB_VERSION} https://github.com/LMDB/lmdb)
|
|
||||||
|
|
||||||
set(LMDB_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/lmdb/libraries/liblmdb)
|
|
||||||
|
|
||||||
add_library(lmdb
|
|
||||||
${CMAKE_SOURCE_DIR}/lmdb/libraries/liblmdb/lmdb.h
|
|
||||||
${CMAKE_SOURCE_DIR}/lmdb/libraries/liblmdb/mdb.c
|
|
||||||
${CMAKE_SOURCE_DIR}/lmdb/libraries/liblmdb/midl.h
|
|
||||||
${CMAKE_SOURCE_DIR}/lmdb/libraries/liblmdb/midl.c)
|
|
||||||
|
|
||||||
set(LMDB_LIBRARY lmdb)
|
|
||||||
else()
|
|
||||||
find_path (LMDB_INCLUDE_DIR NAMES lmdb.h PATHS "$ENV{LMDB_DIR}/include")
|
|
||||||
find_library (LMDB_LIBRARY NAMES lmdb PATHS "$ENV{LMDB_DIR}/lib" )
|
|
||||||
include(FindPackageHandleStandardArgs)
|
|
||||||
find_package_handle_standard_args(LMDB DEFAULT_MSG LMDB_INCLUDE_DIR LMDB_LIBRARY)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include_directories(${LMDB_INCLUDE_DIR})
|
|
|
@ -21,4 +21,8 @@ if(NOT EXISTS ${_qrc})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
qt5_add_resources(LANG_QRC ${_qrc})
|
qt5_add_resources(LANG_QRC ${_qrc})
|
||||||
qt5_add_resources(QRC resources/res.qrc)
|
if(Qt5QuickCompiler_FOUND)
|
||||||
|
qtquick_compiler_add_resources(QRC resources/res.qrc)
|
||||||
|
else()
|
||||||
|
qt5_add_resources(QRC resources/res.qrc)
|
||||||
|
endif()
|
||||||
|
|
125
deps/CMakeLists.txt
vendored
|
@ -1,125 +0,0 @@
|
||||||
cmake_minimum_required(VERSION 3.11)
|
|
||||||
project(NHEKO_DEPS)
|
|
||||||
|
|
||||||
# Point CMake at any custom modules we may ship
|
|
||||||
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
|
|
||||||
|
|
||||||
if(NOT CMAKE_BUILD_TYPE)
|
|
||||||
set(CMAKE_BUILD_TYPE Release)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(DEPS_INSTALL_DIR "${CMAKE_BINARY_DIR}/usr"
|
|
||||||
CACHE PATH "Dependencies install directory.")
|
|
||||||
set(DEPS_BIN_DIR "${DEPS_INSTALL_DIR}/bin"
|
|
||||||
CACHE PATH "Dependencies binary install directory.")
|
|
||||||
set(DEPS_LIB_DIR "${DEPS_INSTALL_DIR}/lib"
|
|
||||||
CACHE PATH "Dependencies library install directory.")
|
|
||||||
set(DEPS_BUILD_DIR "${CMAKE_BINARY_DIR}/build"
|
|
||||||
CACHE PATH "Dependencies build directory.")
|
|
||||||
set(DEPS_DOWNLOAD_DIR "${DEPS_BUILD_DIR}/downloads"
|
|
||||||
CACHE PATH "Dependencies download directory.")
|
|
||||||
|
|
||||||
option(USE_BUNDLED "Use bundled dependencies." ON)
|
|
||||||
|
|
||||||
option(USE_BUNDLED_BOOST "Use the bundled version of Boost." ${USE_BUNDLED})
|
|
||||||
option(USE_BUNDLED_CMARK "Use the bundled version of cmark." ${USE_BUNDLED})
|
|
||||||
option(USE_BUNDLED_SPDLOG "Use the bundled version of spdlog." ${USE_BUNDLED})
|
|
||||||
option(USE_BUNDLED_OLM "Use the bundled version of libolm." ${USE_BUNDLED})
|
|
||||||
option(USE_BUNDLED_TWEENY "Use the bundled version of Tweeny." ${USE_BUNDLED})
|
|
||||||
option(USE_BUNDLED_LMDBXX "Use the bundled version of lmdbxx." ${USE_BUNDLED})
|
|
||||||
option(USE_BUNDLED_MATRIX_CLIENT "Use the bundled version of mtxclient."
|
|
||||||
${USE_BUNDLED})
|
|
||||||
option(USE_BUNDLED_JSON "Use the bundled version of nlohmann json." ${USE_BUNDLED})
|
|
||||||
option(MTX_STATIC "Compile / link bundled mtx client statically" OFF)
|
|
||||||
|
|
||||||
if(USE_BUNDLED_BOOST)
|
|
||||||
# bundled boost is 1.68, which requires CMake 3.12 or greater.
|
|
||||||
cmake_minimum_required(VERSION 3.12)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include(ExternalProject)
|
|
||||||
|
|
||||||
set(BOOST_URL
|
|
||||||
https://dl.bintray.com/boostorg/release/1.69.0/source/boost_1_69_0.tar.bz2)
|
|
||||||
set(BOOST_SHA256
|
|
||||||
8f32d4617390d1c2d16f26a27ab60d97807b35440d45891fa340fc2648b04406)
|
|
||||||
|
|
||||||
set(
|
|
||||||
MTXCLIENT_URL
|
|
||||||
https://github.com/Nheko-Reborn/mtxclient/archive/975ce8906c42742dbb698fcf9fa15663c530df20.tar.gz)
|
|
||||||
set(MTXCLIENT_HASH
|
|
||||||
5e3169ef19b6e585069ceced42489574ce18380480628339bac015759fa1893e)
|
|
||||||
set(
|
|
||||||
TWEENY_URL
|
|
||||||
https://github.com/mobius3/tweeny/archive/b94ce07cfb02a0eb8ac8aaf66137dabdaea857cf.tar.gz
|
|
||||||
)
|
|
||||||
set(TWEENY_HASH
|
|
||||||
9a632b9da84823fae002ad5d9ba02c8d77c0a3810479974c6b637c5504165475)
|
|
||||||
|
|
||||||
set(
|
|
||||||
LMDBXX_HEADER_URL
|
|
||||||
https://raw.githubusercontent.com/bendiken/lmdbxx/0b43ca87d8cfabba392dfe884eb1edb83874de02/lmdb%2B%2B.h
|
|
||||||
)
|
|
||||||
set(LMDBXX_HASH
|
|
||||||
c57b501a4e8fa1187fa7fd348da415c7685a50a7cb25b17b3f257b9e9426f73d)
|
|
||||||
|
|
||||||
set(OLM_URL https://gitlab.matrix.org/matrix-org/olm.git)
|
|
||||||
set(OLM_TAG 4065c8e11a33ba41133a086ed3de4da94dcb6bae)
|
|
||||||
|
|
||||||
set(CMARK_URL https://github.com/commonmark/cmark/archive/0.28.3.tar.gz)
|
|
||||||
set(CMARK_HASH acc98685d3c1b515ff787ac7c994188dadaf28a2d700c10c1221da4199bae1fc)
|
|
||||||
|
|
||||||
set(SPDLOG_URL https://github.com/gabime/spdlog/archive/v1.1.0.tar.gz)
|
|
||||||
set(SPDLOG_HASH
|
|
||||||
3dbcbfd8c07e25f5e0d662b194d3a7772ef214358c49ada23c044c4747ce8b19)
|
|
||||||
|
|
||||||
set(JSON_URL
|
|
||||||
https://github.com/nlohmann/json.git)
|
|
||||||
set(JSON_TAG
|
|
||||||
v3.2.0)
|
|
||||||
|
|
||||||
if(USE_BUNDLED_JSON)
|
|
||||||
include(Json)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(USE_BUNDLED_BOOST)
|
|
||||||
include(Boost)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(USE_BUNDLED_SPDLOG)
|
|
||||||
include(SpdLog)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(USE_BUNDLED_OLM)
|
|
||||||
include(Olm)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(USE_BUNDLED_CMARK)
|
|
||||||
include(cmark)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(USE_BUNDLED_TWEENY)
|
|
||||||
include(Tweeny)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(USE_BUNDLED_LMDBXX)
|
|
||||||
file(DOWNLOAD ${LMDBXX_HEADER_URL} ${DEPS_INSTALL_DIR}/include/lmdb++.h
|
|
||||||
EXPECTED_HASH SHA256=${LMDBXX_HASH})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
if("${TARGET_ARCH}" STREQUAL "X86_64")
|
|
||||||
set(TARGET_ARCH x64)
|
|
||||||
elseif(TARGET_ARCH STREQUAL "X86")
|
|
||||||
set(TARGET_ARCH ia32)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_custom_target(third-party ALL
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E touch .third-party
|
|
||||||
DEPENDS ${THIRD_PARTY_DEPS})
|
|
||||||
|
|
||||||
if(USE_BUNDLED_MATRIX_CLIENT)
|
|
||||||
include(MatrixClient)
|
|
||||||
add_dependencies(MatrixClient third-party)
|
|
||||||
endif()
|
|
23
deps/cmake/Boost.cmake
vendored
|
@ -1,23 +0,0 @@
|
||||||
if(WIN32)
|
|
||||||
message(STATUS "Building Boost in Windows is not supported (skipping)")
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
ExternalProject_Add(
|
|
||||||
Boost
|
|
||||||
|
|
||||||
URL ${BOOST_URL}
|
|
||||||
URL_HASH SHA256=${BOOST_SHA256}
|
|
||||||
DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/boost
|
|
||||||
DOWNLOAD_NO_PROGRESS 0
|
|
||||||
|
|
||||||
BUILD_IN_SOURCE 1
|
|
||||||
SOURCE_DIR ${DEPS_BUILD_DIR}/boost
|
|
||||||
CONFIGURE_COMMAND ${DEPS_BUILD_DIR}/boost/bootstrap.sh
|
|
||||||
--with-libraries=random,thread,system,iostreams,atomic,chrono,date_time,regex
|
|
||||||
--prefix=${DEPS_INSTALL_DIR}
|
|
||||||
BUILD_COMMAND ${DEPS_BUILD_DIR}/boost/b2 -d0 cxxstd=14 variant=release link=shared runtime-link=shared threading=multi --layout=system
|
|
||||||
INSTALL_COMMAND ${DEPS_BUILD_DIR}/boost/b2 -d0 install
|
|
||||||
)
|
|
||||||
|
|
||||||
list(APPEND THIRD_PARTY_DEPS Boost)
|
|
19
deps/cmake/Json.cmake
vendored
|
@ -1,19 +0,0 @@
|
||||||
ExternalProject_Add(
|
|
||||||
Json
|
|
||||||
|
|
||||||
GIT_REPOSITORY ${JSON_URL}
|
|
||||||
GIT_TAG ${JSON_TAG}
|
|
||||||
|
|
||||||
BUILD_IN_SOURCE 1
|
|
||||||
SOURCE_DIR ${DEPS_BUILD_DIR}/json
|
|
||||||
|
|
||||||
CONFIGURE_COMMAND ${CMAKE_COMMAND}
|
|
||||||
-DJSON_BuildTests=OFF
|
|
||||||
-DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}
|
|
||||||
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
|
|
||||||
|
|
||||||
BUILD_COMMAND ${CMAKE_COMMAND} --build ${DEPS_BUILD_DIR}/json
|
|
||||||
INSTALL_COMMAND make install
|
|
||||||
)
|
|
||||||
|
|
||||||
list(APPEND THIRD_PARTY_DEPS Json)
|
|
43
deps/cmake/MatrixClient.cmake
vendored
|
@ -1,43 +0,0 @@
|
||||||
set(PLATFORM_FLAGS "")
|
|
||||||
|
|
||||||
if(MSVC)
|
|
||||||
set(PLATFORM_FLAGS "-DCMAKE_GENERATOR_PLATFORM=x64")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(APPLE)
|
|
||||||
set(PLATFORM_FLAGS "-DOPENSSL_ROOT_DIR=/usr/local/opt/openssl")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Force to build with the bundled version of Boost. This is necessary because
|
|
||||||
# if an outdated version of Boost is installed, then CMake will grab that
|
|
||||||
# instead of the bundled version of Boost, like we wanted.
|
|
||||||
set(BOOST_BUNDLE_ROOT "-DBOOST_ROOT=${DEPS_BUILD_DIR}/boost")
|
|
||||||
|
|
||||||
set (MTX_SHARED ON)
|
|
||||||
|
|
||||||
if (MTX_STATIC)
|
|
||||||
set (MTX_SHARED OFF)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
ExternalProject_Add(
|
|
||||||
MatrixClient
|
|
||||||
|
|
||||||
URL ${MTXCLIENT_URL}
|
|
||||||
URL_HASH SHA256=${MTXCLIENT_HASH}
|
|
||||||
|
|
||||||
BUILD_IN_SOURCE 1
|
|
||||||
SOURCE_DIR ${DEPS_BUILD_DIR}/mtxclient
|
|
||||||
CONFIGURE_COMMAND ${CMAKE_COMMAND}
|
|
||||||
-DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}
|
|
||||||
-DCMAKE_BUILD_TYPE=Release
|
|
||||||
-DBUILD_LIB_TESTS=OFF
|
|
||||||
-DBUILD_LIB_EXAMPLES=OFF
|
|
||||||
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
|
|
||||||
${BOOST_BUNDLE_ROOT}
|
|
||||||
-DBUILD_SHARED_LIBS=${MTX_SHARED}
|
|
||||||
${PLATFORM_FLAGS}
|
|
||||||
${DEPS_BUILD_DIR}/mtxclient
|
|
||||||
BUILD_COMMAND
|
|
||||||
${CMAKE_COMMAND} --build ${DEPS_BUILD_DIR}/mtxclient --config Release)
|
|
||||||
|
|
||||||
list(APPEND THIRD_PARTY_DEPS MatrixClient)
|
|
34
deps/cmake/Olm.cmake
vendored
|
@ -1,34 +0,0 @@
|
||||||
set(WINDOWS_FLAGS "")
|
|
||||||
|
|
||||||
if(MSVC)
|
|
||||||
set(WINDOWS_FLAGS "-DCMAKE_GENERATOR_PLATFORM=x64")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
ExternalProject_Add(
|
|
||||||
Olm
|
|
||||||
|
|
||||||
GIT_REPOSITORY ${OLM_URL}
|
|
||||||
GIT_TAG ${OLM_TAG}
|
|
||||||
|
|
||||||
BUILD_IN_SOURCE 1
|
|
||||||
SOURCE_DIR ${DEPS_BUILD_DIR}/olm
|
|
||||||
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E copy
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake/OlmCMakeLists.txt
|
|
||||||
${DEPS_BUILD_DIR}/olm/CMakeLists.txt
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake/OlmConfig.cmake.in
|
|
||||||
${DEPS_BUILD_DIR}/olm/cmake/OlmConfig.cmake.in
|
|
||||||
COMMAND ${CMAKE_COMMAND}
|
|
||||||
-DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}
|
|
||||||
-DCMAKE_BUILD_TYPE=Release
|
|
||||||
${DEPS_BUILD_DIR}/olm
|
|
||||||
${WINDOWS_FLAGS}
|
|
||||||
BUILD_COMMAND ${CMAKE_COMMAND}
|
|
||||||
--build ${DEPS_BUILD_DIR}/olm
|
|
||||||
--config Release
|
|
||||||
INSTALL_COMMAND ${CMAKE_COMMAND}
|
|
||||||
--build ${DEPS_BUILD_DIR}/olm
|
|
||||||
--config Release
|
|
||||||
--target install)
|
|
||||||
|
|
||||||
list(APPEND THIRD_PARTY_DEPS Olm)
|
|
107
deps/cmake/OlmCMakeLists.txt
vendored
|
@ -1,107 +0,0 @@
|
||||||
cmake_minimum_required(VERSION 3.1)
|
|
||||||
|
|
||||||
project(olm VERSION 2.2.2 LANGUAGES CXX C)
|
|
||||||
|
|
||||||
add_definitions(-DOLMLIB_VERSION_MAJOR=${PROJECT_VERSION_MAJOR})
|
|
||||||
add_definitions(-DOLMLIB_VERSION_MINOR=${PROJECT_VERSION_MINOR})
|
|
||||||
add_definitions(-DOLMLIB_VERSION_PATCH=${PROJECT_VERSION_PATCH})
|
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
||||||
set(CMAKE_C_STANDARD 99)
|
|
||||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
|
||||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
|
||||||
|
|
||||||
if(NOT CMAKE_BUILD_TYPE)
|
|
||||||
set(CMAKE_BUILD_TYPE Release)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_library(olm
|
|
||||||
src/account.cpp
|
|
||||||
src/base64.cpp
|
|
||||||
src/cipher.cpp
|
|
||||||
src/crypto.cpp
|
|
||||||
src/memory.cpp
|
|
||||||
src/message.cpp
|
|
||||||
src/pickle.cpp
|
|
||||||
src/ratchet.cpp
|
|
||||||
src/session.cpp
|
|
||||||
src/utility.cpp
|
|
||||||
|
|
||||||
src/ed25519.c
|
|
||||||
src/error.c
|
|
||||||
src/inbound_group_session.c
|
|
||||||
src/megolm.c
|
|
||||||
src/olm.cpp
|
|
||||||
src/outbound_group_session.c
|
|
||||||
src/pickle_encoding.c
|
|
||||||
|
|
||||||
lib/crypto-algorithms/aes.c
|
|
||||||
lib/crypto-algorithms/sha256.c
|
|
||||||
lib/curve25519-donna/curve25519-donna.c)
|
|
||||||
add_library(Olm::Olm ALIAS olm)
|
|
||||||
|
|
||||||
target_include_directories(olm
|
|
||||||
PUBLIC
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include>
|
|
||||||
$<INSTALL_INTERFACE:include>
|
|
||||||
PRIVATE
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/lib)
|
|
||||||
|
|
||||||
set_target_properties(olm PROPERTIES
|
|
||||||
SOVERSION ${PROJECT_VERSION_MAJOR}
|
|
||||||
VERSION ${PROJECT_VERSION})
|
|
||||||
|
|
||||||
set_target_properties(olm PROPERTIES
|
|
||||||
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}
|
|
||||||
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}
|
|
||||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
|
|
||||||
|
|
||||||
#
|
|
||||||
# Installation
|
|
||||||
#
|
|
||||||
include(GNUInstallDirs)
|
|
||||||
set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/Olm)
|
|
||||||
install(TARGETS olm
|
|
||||||
EXPORT olm-targets
|
|
||||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
||||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
|
||||||
|
|
||||||
# The exported target will be named Olm.
|
|
||||||
set_target_properties(olm PROPERTIES EXPORT_NAME Olm)
|
|
||||||
install(FILES
|
|
||||||
${CMAKE_SOURCE_DIR}/include/olm/olm.h
|
|
||||||
${CMAKE_SOURCE_DIR}/include/olm/outbound_group_session.h
|
|
||||||
${CMAKE_SOURCE_DIR}/include/olm/inbound_group_session.h
|
|
||||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/olm)
|
|
||||||
|
|
||||||
# Export the targets to a script.
|
|
||||||
install(EXPORT olm-targets
|
|
||||||
FILE OlmTargets.cmake
|
|
||||||
NAMESPACE Olm::
|
|
||||||
DESTINATION ${INSTALL_CONFIGDIR})
|
|
||||||
|
|
||||||
# Create a ConfigVersion.cmake file.
|
|
||||||
include(CMakePackageConfigHelpers)
|
|
||||||
write_basic_package_version_file(
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/OlmConfigVersion.cmake
|
|
||||||
VERSION ${PROJECT_VERSION}
|
|
||||||
COMPATIBILITY SameMajorVersion)
|
|
||||||
|
|
||||||
configure_package_config_file(
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/cmake/OlmConfig.cmake.in
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/OlmConfig.cmake
|
|
||||||
INSTALL_DESTINATION ${INSTALL_CONFIGDIR})
|
|
||||||
|
|
||||||
#Install the config & configversion.
|
|
||||||
install(FILES
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/OlmConfig.cmake
|
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/OlmConfigVersion.cmake
|
|
||||||
DESTINATION ${INSTALL_CONFIGDIR})
|
|
||||||
|
|
||||||
# Register package in user's package registry
|
|
||||||
export(EXPORT olm-targets
|
|
||||||
FILE ${CMAKE_CURRENT_BINARY_DIR}/OlmTargets.cmake
|
|
||||||
NAMESPACE Olm::)
|
|
||||||
export(PACKAGE Olm)
|
|
11
deps/cmake/OlmConfig.cmake.in
vendored
|
@ -1,11 +0,0 @@
|
||||||
get_filename_component(Olm_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
|
||||||
include(CMakeFindDependencyMacro)
|
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH ${Olm_CMAKE_DIR})
|
|
||||||
list(REMOVE_AT CMAKE_MODULE_PATH -1)
|
|
||||||
|
|
||||||
if(NOT TARGET Olm::Olm)
|
|
||||||
include("${Olm_CMAKE_DIR}/OlmTargets.cmake")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(Olm_LIBRARIES Olm::Olm)
|
|
23
deps/cmake/SpdLog.cmake
vendored
|
@ -1,23 +0,0 @@
|
||||||
set(WINDOWS_FLAGS "")
|
|
||||||
|
|
||||||
if(MSVC)
|
|
||||||
set(WINDOWS_FLAGS "-DCMAKE_GENERATOR_PLATFORM=x64")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
ExternalProject_Add(
|
|
||||||
SpdLog
|
|
||||||
|
|
||||||
URL ${SPDLOG_URL}
|
|
||||||
URL_HASH SHA256=${SPDLOG_HASH}
|
|
||||||
|
|
||||||
BUILD_IN_SOURCE 1
|
|
||||||
SOURCE_DIR ${DEPS_BUILD_DIR}/spdlog
|
|
||||||
CONFIGURE_COMMAND ${CMAKE_COMMAND}
|
|
||||||
-DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}
|
|
||||||
-DSPDLOG_BUILD_EXAMPLES=0
|
|
||||||
-DSPDLOG_BUILD_BENCH=0
|
|
||||||
-DSPDLOG_BUILD_TESTING=0
|
|
||||||
${DEPS_BUILD_DIR}/spdlog
|
|
||||||
${WINDOWS_FLAGS})
|
|
||||||
|
|
||||||
list(APPEND THIRD_PARTY_DEPS SpdLog)
|
|
22
deps/cmake/Tweeny.cmake
vendored
|
@ -1,22 +0,0 @@
|
||||||
set(WINDOWS_FLAGS "")
|
|
||||||
|
|
||||||
if(MSVC)
|
|
||||||
set(WINDOWS_FLAGS "-DCMAKE_GENERATOR_PLATFORM=x64")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
ExternalProject_Add(
|
|
||||||
Tweeny
|
|
||||||
|
|
||||||
URL ${TWEENY_URL}
|
|
||||||
URL_HASH SHA256=${TWEENY_HASH}
|
|
||||||
|
|
||||||
BUILD_IN_SOURCE 1
|
|
||||||
SOURCE_DIR ${DEPS_BUILD_DIR}/tweeny
|
|
||||||
CONFIGURE_COMMAND ${CMAKE_COMMAND}
|
|
||||||
-DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}
|
|
||||||
-DTWEENY_BUILD_EXAMPLES=OFF
|
|
||||||
-DTWEENY_BUILD_DOCUMENTATION=OFF
|
|
||||||
${DEPS_BUILD_DIR}/tweeny
|
|
||||||
${WINDOWS_FLAGS})
|
|
||||||
|
|
||||||
list(APPEND THIRD_PARTY_DEPS Tweeny)
|
|
21
deps/cmake/cmark.cmake
vendored
|
@ -1,21 +0,0 @@
|
||||||
set(WINDOWS_FLAGS "")
|
|
||||||
|
|
||||||
if(MSVC)
|
|
||||||
set(WINDOWS_FLAGS "-DCMAKE_GENERATOR_PLATFORM=x64")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
ExternalProject_Add(
|
|
||||||
cmark
|
|
||||||
|
|
||||||
URL ${CMARK_URL}
|
|
||||||
URL_HASH SHA256=${CMARK_HASH}
|
|
||||||
|
|
||||||
BUILD_IN_SOURCE 0
|
|
||||||
SOURCE_DIR ${DEPS_BUILD_DIR}/cmark
|
|
||||||
CONFIGURE_COMMAND ${CMAKE_COMMAND}
|
|
||||||
-DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}
|
|
||||||
-DCMARK_TESTS=OFF
|
|
||||||
${DEPS_BUILD_DIR}/cmark
|
|
||||||
${WINDOWS_FLAGS})
|
|
||||||
|
|
||||||
list(APPEND THIRD_PARTY_DEPS cmark)
|
|
194
io.github.NhekoReborn.Nheko.json
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
{
|
||||||
|
"id": "io.github.NhekoReborn.Nheko",
|
||||||
|
"command": "nheko",
|
||||||
|
"branch": "0.7.0-dev",
|
||||||
|
"runtime": "org.kde.Platform",
|
||||||
|
"runtime-version": "5.14",
|
||||||
|
"sdk": "org.kde.Sdk",
|
||||||
|
"rename-icon": "nheko",
|
||||||
|
"rename-desktop-file": "nheko.desktop",
|
||||||
|
"rename-appdata-file": "nheko.appdata.xml",
|
||||||
|
"finish-args": [
|
||||||
|
"--device=dri",
|
||||||
|
"--filesystem=home",
|
||||||
|
"--share=ipc",
|
||||||
|
"--share=network",
|
||||||
|
"--socket=pulseaudio",
|
||||||
|
"--socket=wayland",
|
||||||
|
"--socket=x11",
|
||||||
|
"--talk-name=org.freedesktop.Notifications",
|
||||||
|
"--talk-name=org.kde.StatusNotifierWatcher"
|
||||||
|
],
|
||||||
|
"cleanup": [
|
||||||
|
"/include",
|
||||||
|
"/bin/mdb*",
|
||||||
|
"*.a"
|
||||||
|
],
|
||||||
|
"build-options" : {
|
||||||
|
"arch": {
|
||||||
|
"aarch64": {
|
||||||
|
"cxxflags": "-DBOOST_ASIO_DISABLE_EPOLL"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"name": "lmdb",
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"sha256": "f3927859882eb608868c8c31586bb7eb84562a40a6bf5cc3e13b6b564641ea28",
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://github.com/LMDB/lmdb/archive/LMDB_0.9.22.tar.gz"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"make-install-args": [
|
||||||
|
"prefix=/app"
|
||||||
|
],
|
||||||
|
"no-autogen": true,
|
||||||
|
"subdir": "libraries/liblmdb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cmark",
|
||||||
|
"buildsystem": "cmake-ninja",
|
||||||
|
"builddir": true,
|
||||||
|
"config-opts": [
|
||||||
|
"-DCMAKE_BUILD_TYPE=Release",
|
||||||
|
"-DCMARK_TESTS=OFF"
|
||||||
|
],
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"sha256": "2558ace3cbeff85610de3bda32858f722b359acdadf0c4691851865bb84924a6",
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://github.com/commonmark/cmark/archive/0.29.0.tar.gz"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "spdlog",
|
||||||
|
"buildsystem": "cmake-ninja",
|
||||||
|
"config-opts": [
|
||||||
|
"-DCMAKE_BUILD_TYPE=Release",
|
||||||
|
"-DSPDLOG_BUILD_EXAMPLES=0",
|
||||||
|
"-DSPDLOG_BUILD_BENCH=0",
|
||||||
|
"-DSPDLOG_BUILD_TESTING=0"
|
||||||
|
],
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"sha256": "3dbcbfd8c07e25f5e0d662b194d3a7772ef214358c49ada23c044c4747ce8b19",
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://github.com/gabime/spdlog/archive/v1.1.0.tar.gz"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"config-opts": [
|
||||||
|
"-DCMAKE_BUILD_TYPE=Release"
|
||||||
|
],
|
||||||
|
"buildsystem": "cmake-ninja",
|
||||||
|
"name": "olm",
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"commit": "6753595300767dd70150831dbbe6f92d64e75038",
|
||||||
|
"disable-shallow-clone": true,
|
||||||
|
"tag": "3.1.4",
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://gitlab.matrix.org/matrix-org/olm.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"config-opts":[
|
||||||
|
"-DJSON_BuildTests=OFF"
|
||||||
|
],
|
||||||
|
"buildsystem":"cmake",
|
||||||
|
"name": "nlohmann",
|
||||||
|
"sources":[
|
||||||
|
{
|
||||||
|
"sha256": "d51a3a8d3efbb1139d7608e28782ea9efea7e7933157e8ff8184901efd8ee760",
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://github.com/nlohmann/json/archive/v3.7.0.tar.gz"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sodium",
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"sha256": "6f504490b342a4f8a4c4a02fc9b866cbef8622d5df4e5452b46be121e46636c1",
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://github.com/jedisct1/libsodium/releases/download/1.0.18-RELEASE/libsodium-1.0.18.tar.gz"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"build-commands": [
|
||||||
|
"./bootstrap.sh --with-libraries=thread,system,iostreams --prefix=/app",
|
||||||
|
"./b2 -d0 variant=release link=static threading=multi --layout=system",
|
||||||
|
"./b2 -d0 install"
|
||||||
|
],
|
||||||
|
"buildsystem": "simple",
|
||||||
|
"name": "boost",
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"sha256": "59c9b274bc451cf91a9ba1dd2c7fdcaf5d60b1b3aa83f2c9fa143417cc660722",
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://dl.bintray.com/boostorg/release/1.72.0/source/boost_1_72_0.tar.bz2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"config-opts": [
|
||||||
|
"-DBUILD_LIB_TESTS=OFF",
|
||||||
|
"-DBUILD_LIB_EXAMPLES=OFF",
|
||||||
|
"-DCMAKE_BUILD_TYPE=Release",
|
||||||
|
"-DBUILD_SHARED_LIBS=OFF"
|
||||||
|
],
|
||||||
|
"buildsystem": "cmake-ninja",
|
||||||
|
"name": "mtxclient",
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"sha256": "df3fe7e3d59b5fc52ee3ca9a132a55fc325aa799c676e9e420073c56daeb1848",
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://github.com/Nheko-Reborn/mtxclient/archive/5838f607d0e4c7595439249e8b9c213aec0667e9.tar.gz"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"config-opts": [
|
||||||
|
"-DCMAKE_BUILD_TYPE=Release",
|
||||||
|
"-DTWEENY_BUILD_DOCUMENTATION=OFF",
|
||||||
|
"-DTWEENY_BUILD_EXAMPLES=OFF"
|
||||||
|
],
|
||||||
|
"buildsystem": "cmake-ninja",
|
||||||
|
"name": "tweeny",
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"sha256": "482857256a7235646004682912badb6521d361ed6987c8ebdae7986bf64ce694",
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://github.com/mobius3/tweeny/archive/43f4130f7e4a67c19d870b60864bc2862c19b81f.tar.gz"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"config-opts": [
|
||||||
|
"-DCMAKE_BUILD_TYPE=Release",
|
||||||
|
"-DLMDBXX_INCLUDE_DIR=.deps/lmdbxx"
|
||||||
|
],
|
||||||
|
"buildsystem": "cmake-ninja",
|
||||||
|
"name": "nheko",
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"path": ".",
|
||||||
|
"type": "dir",
|
||||||
|
"skip": ["build-flatpak"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dest": ".deps/lmdbxx",
|
||||||
|
"sha256": "93721132bbf5045d38ad62de2997655e9984c48ea5c9886746d42128f4b26fbd",
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://github.com/bendiken/lmdbxx/archive/0b43ca87d8cfabba392dfe884eb1edb83874de02.tar.gz"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
4446
resources/emoji-test.txt
Normal file
|
@ -1,202 +0,0 @@
|
||||||
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
1
resources/icons/ui/at-solid.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="at" class="svg-inline--fa fa-at fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 8C118.941 8 8 118.919 8 256c0 137.059 110.919 248 248 248 48.154 0 95.342-14.14 135.408-40.223 12.005-7.815 14.625-24.288 5.552-35.372l-10.177-12.433c-7.671-9.371-21.179-11.667-31.373-5.129C325.92 429.757 291.314 440 256 440c-101.458 0-184-82.542-184-184S154.542 72 256 72c100.139 0 184 57.619 184 160 0 38.786-21.093 79.742-58.17 83.693-17.349-.454-16.91-12.857-13.476-30.024l23.433-121.11C394.653 149.75 383.308 136 368.225 136h-44.981a13.518 13.518 0 0 0-13.432 11.993l-.01.092c-14.697-17.901-40.448-21.775-59.971-21.775-74.58 0-137.831 62.234-137.831 151.46 0 65.303 36.785 105.87 96 105.87 26.984 0 57.369-15.637 74.991-38.333 9.522 34.104 40.613 34.103 70.71 34.103C462.609 379.41 504 307.798 504 232 504 95.653 394.023 8 256 8zm-21.68 304.43c-22.249 0-36.07-15.623-36.07-40.771 0-44.993 30.779-72.729 58.63-72.729 22.292 0 35.601 15.241 35.601 40.77 0 45.061-33.875 72.73-58.161 72.73z"></path></svg>
|
After Width: | Height: | Size: 1.1 KiB |
BIN
resources/icons/ui/mail-reply.png
Normal file
After Width: | Height: | Size: 373 B |
1369
resources/langs/nheko_fi.ts
Normal file
1368
resources/langs/nheko_ja.ts
Normal file
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 728 B After Width: | Height: | Size: 696 B |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
155
resources/nheko.svg
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="1024"
|
||||||
|
height="1024"
|
||||||
|
viewBox="0 0 270.93333 270.93333"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.4 5da689c313, 2019-01-14"
|
||||||
|
sodipodi:docname="nheko.svg"
|
||||||
|
inkscape:export-filename="/home/nicolas/Dokumente/devel/open-source/nheko/resources/nheko-rebuild-round-corners.svg.png"
|
||||||
|
inkscape:export-xdpi="130.048"
|
||||||
|
inkscape:export-ydpi="130.048">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="0.35355339"
|
||||||
|
inkscape:cx="852.07808"
|
||||||
|
inkscape:cy="-60.410565"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer2"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1019"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:snap-grids="true"
|
||||||
|
gridtolerance="10"
|
||||||
|
inkscape:snap-bbox="false"
|
||||||
|
inkscape:bbox-paths="true"
|
||||||
|
inkscape:snap-global="true"
|
||||||
|
inkscape:bbox-nodes="true"
|
||||||
|
inkscape:lockguides="false"
|
||||||
|
units="px">
|
||||||
|
<sodipodi:guide
|
||||||
|
position="0,0"
|
||||||
|
orientation="0,793.70079"
|
||||||
|
id="guide4797"
|
||||||
|
inkscape:locked="false" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="0,297"
|
||||||
|
orientation="1122.5197,0"
|
||||||
|
id="guide4803"
|
||||||
|
inkscape:locked="false" />
|
||||||
|
<inkscape:grid
|
||||||
|
type="axonomgrid"
|
||||||
|
id="grid4805"
|
||||||
|
units="px"
|
||||||
|
empspacing="2"
|
||||||
|
snapvisiblegridlinesonly="true"
|
||||||
|
spacingy="1.0583333" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="0,0"
|
||||||
|
orientation="0,755.90551"
|
||||||
|
id="guide4807"
|
||||||
|
inkscape:locked="false" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="200,0"
|
||||||
|
orientation="-755.90551,0"
|
||||||
|
id="guide4809"
|
||||||
|
inkscape:locked="false" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="200,200"
|
||||||
|
orientation="0,-755.90551"
|
||||||
|
id="guide4811"
|
||||||
|
inkscape:locked="false" />
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid871"
|
||||||
|
empspacing="2"
|
||||||
|
color="#d43fff"
|
||||||
|
opacity="0.1254902"
|
||||||
|
empcolor="#cf3fff"
|
||||||
|
empopacity="0.25098039"
|
||||||
|
units="px"
|
||||||
|
spacingx="1.0583333"
|
||||||
|
spacingy="1.0583333"
|
||||||
|
enabled="false" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer2"
|
||||||
|
inkscape:label="Logo"
|
||||||
|
style="display:inline"
|
||||||
|
transform="translate(0,-26.066668)">
|
||||||
|
<circle
|
||||||
|
id="path3792"
|
||||||
|
cx="135.46666"
|
||||||
|
cy="161.53333"
|
||||||
|
style="display:inline;fill:#333333;fill-opacity:1;stroke:none;stroke-width:0.3584221"
|
||||||
|
inkscape:transform-center-x="-57.929751"
|
||||||
|
inkscape:transform-center-y="532.03976"
|
||||||
|
inkscape:export-xdpi="96.000008"
|
||||||
|
inkscape:export-ydpi="96.000008"
|
||||||
|
r="135.46666" />
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.32663074px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="M 48.965212,110.73276 H 239.52342 c 4.88824,0 4.88824,0 0,8.46688 L 180.59519,221.2662 c -4.6188,8.00001 -4.6188,8.00001 -9.50702,8.00001 h -19.55294 c -4.88824,0 -4.88824,0 -0.26944,-8.00001 l 44.2635,-76.66608 h -29.41224 l -43.91123,76.19952 c -4.88823,8.46657 -4.88823,8.46657 -9.77646,8.46657 H 29.329398 l 49.299816,-84.66609 h -49.29982 z"
|
||||||
|
id="path4834"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccccccccccc"
|
||||||
|
inkscape:export-xdpi="96.000008"
|
||||||
|
inkscape:export-ydpi="96.000008" />
|
||||||
|
<path
|
||||||
|
style="fill:#c0def5;fill-opacity:1;stroke:none;stroke-width:0.3584221px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="M 97.764652,110.73276 H 127.09406 L 58.658797,229.26621 H 29.329398 Z"
|
||||||
|
id="path4836"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:export-xdpi="96.000008"
|
||||||
|
inkscape:export-ydpi="96.000008" />
|
||||||
|
<path
|
||||||
|
style="fill:#87aade;fill-opacity:1;stroke:none;stroke-width:0.3584221px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="M 58.658797,229.26621 127.09406,110.73276 h 29.3294 L 87.988193,229.26621 Z"
|
||||||
|
id="path4838"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccc"
|
||||||
|
inkscape:export-xdpi="96.000008"
|
||||||
|
inkscape:export-ydpi="96.000008" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
style="display:inline"
|
||||||
|
transform="translate(0,-26.066668)" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.2 KiB |
53
resources/qml/Avatar.qml
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import QtQuick 2.6
|
||||||
|
import QtGraphicalEffects 1.0
|
||||||
|
import Qt.labs.settings 1.0
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: avatar
|
||||||
|
width: 48
|
||||||
|
height: 48
|
||||||
|
radius: settings.avatar_circles ? height/2 : 3
|
||||||
|
|
||||||
|
Settings {
|
||||||
|
id: settings
|
||||||
|
category: "user"
|
||||||
|
property bool avatar_circles: true
|
||||||
|
}
|
||||||
|
|
||||||
|
property alias url: img.source
|
||||||
|
property string displayName
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.fill: parent
|
||||||
|
text: chat.model.escapeEmoji(String.fromCodePoint(displayName.codePointAt(0)))
|
||||||
|
textFormat: Text.RichText
|
||||||
|
color: colors.text
|
||||||
|
font.pixelSize: avatar.height/2
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
visible: img.status != Image.Ready
|
||||||
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: img
|
||||||
|
anchors.fill: parent
|
||||||
|
asynchronous: true
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
mipmap: true
|
||||||
|
smooth: false
|
||||||
|
|
||||||
|
sourceSize.width: avatar.width
|
||||||
|
sourceSize.height: avatar.height
|
||||||
|
|
||||||
|
layer.enabled: true
|
||||||
|
layer.effect: OpacityMask {
|
||||||
|
maskSource: Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
width: avatar.width
|
||||||
|
height: avatar.height
|
||||||
|
radius: settings.avatar_circles ? height/2 : 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
color: colors.base
|
||||||
|
}
|
26
resources/qml/EncryptionIndicator.qml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import QtQuick 2.5
|
||||||
|
import QtQuick.Controls 2.1
|
||||||
|
import im.nheko 1.0
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: indicator
|
||||||
|
color: "transparent"
|
||||||
|
width: 16
|
||||||
|
height: 16
|
||||||
|
|
||||||
|
ToolTip.visible: ma.containsMouse && indicator.visible
|
||||||
|
ToolTip.text: qsTr("Encrypted")
|
||||||
|
|
||||||
|
MouseArea{
|
||||||
|
id: ma
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: stateImg
|
||||||
|
anchors.fill: parent
|
||||||
|
source: "image://colorimage/:/icons/icons/ui/lock.png?"+colors.buttonText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
29
resources/qml/ImageButton.qml
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import QtQuick 2.3
|
||||||
|
import QtQuick.Controls 2.3
|
||||||
|
|
||||||
|
Button {
|
||||||
|
property string image: undefined
|
||||||
|
|
||||||
|
id: button
|
||||||
|
|
||||||
|
flat: true
|
||||||
|
|
||||||
|
// disable background, because we don't want a border on hover
|
||||||
|
background: Item {
|
||||||
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: buttonImg
|
||||||
|
// Workaround, can't get icon.source working for now...
|
||||||
|
anchors.fill: parent
|
||||||
|
source: "image://colorimage/" + image + "?" + (button.hovered ? colors.highlight : colors.buttonText)
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea
|
||||||
|
{
|
||||||
|
id: mouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
onPressed: mouse.accepted = false
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
}
|
||||||
|
}
|
32
resources/qml/MatrixText.qml
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import QtQuick 2.5
|
||||||
|
import QtQuick.Controls 2.3
|
||||||
|
|
||||||
|
TextEdit {
|
||||||
|
textFormat: TextEdit.RichText
|
||||||
|
readOnly: true
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
selectByMouse: true
|
||||||
|
color: colors.text
|
||||||
|
|
||||||
|
onLinkActivated: {
|
||||||
|
if (/^https:\/\/matrix.to\/#\/(@.*)$/.test(link)) chat.model.openUserProfile(/^https:\/\/matrix.to\/#\/(@.*)$/.exec(link)[1])
|
||||||
|
else if (/^https:\/\/matrix.to\/#\/(![^\/]*)$/.test(link)) timelineManager.setHistoryView(/^https:\/\/matrix.to\/#\/(!.*)$/.exec(link)[1])
|
||||||
|
else if (/^https:\/\/matrix.to\/#\/(![^\/]*)\/(\$.*)$/.test(link)) {
|
||||||
|
var match = /^https:\/\/matrix.to\/#\/(![^\/]*)\/(\$.*)$/.exec(link)
|
||||||
|
timelineManager.setHistoryView(match[1])
|
||||||
|
chat.positionViewAtIndex(chat.model.idToIndex(match[2]), ListView.Contain)
|
||||||
|
}
|
||||||
|
else Qt.openUrlExternally(link)
|
||||||
|
}
|
||||||
|
MouseArea
|
||||||
|
{
|
||||||
|
id: ma
|
||||||
|
anchors.fill: parent
|
||||||
|
propagateComposedEvents: true
|
||||||
|
acceptedButtons: Qt.NoButton
|
||||||
|
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolTip.visible: hoveredLink
|
||||||
|
ToolTip.text: hoveredLink
|
||||||
|
}
|
39
resources/qml/StatusIndicator.qml
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import QtQuick 2.5
|
||||||
|
import QtQuick.Controls 2.1
|
||||||
|
import im.nheko 1.0
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: indicator
|
||||||
|
property int state: 0
|
||||||
|
color: "transparent"
|
||||||
|
width: 16
|
||||||
|
height: 16
|
||||||
|
|
||||||
|
ToolTip.visible: ma.containsMouse && state != MtxEvent.Empty
|
||||||
|
ToolTip.text: switch (state) {
|
||||||
|
case MtxEvent.Failed: return qsTr("Failed")
|
||||||
|
case MtxEvent.Sent: return qsTr("Sent")
|
||||||
|
case MtxEvent.Received: return qsTr("Received")
|
||||||
|
case MtxEvent.Read: return qsTr("Read")
|
||||||
|
default: return ""
|
||||||
|
}
|
||||||
|
MouseArea{
|
||||||
|
id: ma
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: stateImg
|
||||||
|
// Workaround, can't get icon.source working for now...
|
||||||
|
anchors.fill: parent
|
||||||
|
source: switch (indicator.state) {
|
||||||
|
case MtxEvent.Failed: return "image://colorimage/:/icons/icons/ui/remove-symbol.png?" + colors.buttonText
|
||||||
|
case MtxEvent.Sent: return "image://colorimage/:/icons/icons/ui/clock.png?" + colors.buttonText
|
||||||
|
case MtxEvent.Received: return "image://colorimage/:/icons/icons/ui/checkmark.png?" + colors.buttonText
|
||||||
|
case MtxEvent.Read: return "image://colorimage/:/icons/icons/ui/double-tick-indicator.png?" + colors.buttonText
|
||||||
|
default: return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
134
resources/qml/TimelineRow.qml
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
import QtQuick 2.6
|
||||||
|
import QtQuick.Controls 2.3
|
||||||
|
import QtQuick.Layouts 1.2
|
||||||
|
import QtQuick.Window 2.2
|
||||||
|
|
||||||
|
import im.nheko 1.0
|
||||||
|
|
||||||
|
import "./delegates"
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: rowArea
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
height: row.height
|
||||||
|
|
||||||
|
hoverEnabled: true
|
||||||
|
preventStealing: true
|
||||||
|
propagateComposedEvents: true
|
||||||
|
acceptedButtons: Qt.NoButton
|
||||||
|
|
||||||
|
property bool showButtons: false
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
running: rowArea.containsMouse
|
||||||
|
interval: 150
|
||||||
|
onTriggered: rowArea.state = "showButtons"
|
||||||
|
}
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "hideButtons"
|
||||||
|
when: !rowArea.containsMouse
|
||||||
|
PropertyChanges { target: rowArea; showButtons: false; }
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "showButtons"
|
||||||
|
PropertyChanges { target: rowArea; showButtons: true; }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: row
|
||||||
|
|
||||||
|
anchors.leftMargin: avatarSize + 4
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
|
||||||
|
Column {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignTop
|
||||||
|
spacing: 4
|
||||||
|
|
||||||
|
// fancy reply, if this is a reply
|
||||||
|
Reply {
|
||||||
|
visible: model.replyTo
|
||||||
|
modelData: chat.model.getDump(model.replyTo)
|
||||||
|
userColor: timelineManager.userColor(modelData.userId, colors.window)
|
||||||
|
}
|
||||||
|
|
||||||
|
// actual message content
|
||||||
|
MessageDelegate {
|
||||||
|
id: contentItem
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
modelData: model
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageButton {
|
||||||
|
visible: rowArea.showButtons
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
||||||
|
Layout.preferredHeight: 16
|
||||||
|
width: 16
|
||||||
|
id: replyButton
|
||||||
|
hoverEnabled: true
|
||||||
|
|
||||||
|
|
||||||
|
image: ":/icons/icons/ui/mail-reply.png"
|
||||||
|
|
||||||
|
ToolTip.visible: hovered
|
||||||
|
ToolTip.text: qsTr("Reply")
|
||||||
|
|
||||||
|
onClicked: chat.model.replyAction(model.id)
|
||||||
|
}
|
||||||
|
ImageButton {
|
||||||
|
visible: rowArea.showButtons
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
||||||
|
Layout.preferredHeight: 16
|
||||||
|
width: 16
|
||||||
|
id: optionsButton
|
||||||
|
hoverEnabled: true
|
||||||
|
|
||||||
|
image: ":/icons/icons/ui/vertical-ellipsis.png"
|
||||||
|
|
||||||
|
ToolTip.visible: hovered
|
||||||
|
ToolTip.text: qsTr("Options")
|
||||||
|
|
||||||
|
onClicked: messageContextMenu.show(model.id, model.type, optionsButton)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusIndicator {
|
||||||
|
state: model.state
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
||||||
|
Layout.preferredHeight: 16
|
||||||
|
width: 16
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptionIndicator {
|
||||||
|
visible: model.isEncrypted
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
||||||
|
Layout.preferredHeight: 16
|
||||||
|
width: 16
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
||||||
|
text: model.timestamp.toLocaleTimeString("HH:mm")
|
||||||
|
color: inactiveColors.text
|
||||||
|
|
||||||
|
MouseArea{
|
||||||
|
id: ma
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolTip.visible: ma.containsMouse
|
||||||
|
ToolTip.text: Qt.formatDateTime(model.timestamp, Qt.DefaultLocaleLongDate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
309
resources/qml/TimelineView.qml
Normal file
|
@ -0,0 +1,309 @@
|
||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.3
|
||||||
|
import QtQuick.Layouts 1.2
|
||||||
|
import QtGraphicalEffects 1.0
|
||||||
|
import QtQuick.Window 2.2
|
||||||
|
|
||||||
|
import im.nheko 1.0
|
||||||
|
|
||||||
|
import "./delegates"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property var colors: currentActivePalette
|
||||||
|
property var systemInactive: SystemPalette { colorGroup: SystemPalette.Disabled }
|
||||||
|
property var inactiveColors: currentInactivePalette ? currentInactivePalette : systemInactive
|
||||||
|
property int avatarSize: 40
|
||||||
|
|
||||||
|
Menu {
|
||||||
|
id: messageContextMenu
|
||||||
|
palette: colors
|
||||||
|
modal: true
|
||||||
|
|
||||||
|
function show(eventId_, eventType_, showAt) {
|
||||||
|
eventId = eventId_
|
||||||
|
eventType = eventType_
|
||||||
|
popup(showAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
property string eventId
|
||||||
|
property int eventType
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: qsTr("Read receipts")
|
||||||
|
onTriggered: chat.model.readReceiptsAction(messageContextMenu.eventId)
|
||||||
|
}
|
||||||
|
MenuItem {
|
||||||
|
text: qsTr("Mark as read")
|
||||||
|
}
|
||||||
|
MenuItem {
|
||||||
|
text: qsTr("View raw message")
|
||||||
|
onTriggered: chat.model.viewRawMessage(messageContextMenu.eventId)
|
||||||
|
}
|
||||||
|
MenuItem {
|
||||||
|
text: qsTr("Redact message")
|
||||||
|
onTriggered: chat.model.redactEvent(messageContextMenu.eventId)
|
||||||
|
}
|
||||||
|
MenuItem {
|
||||||
|
visible: messageContextMenu.eventType == MtxEvent.ImageMessage || messageContextMenu.eventType == MtxEvent.VideoMessage || messageContextMenu.eventType == MtxEvent.AudioMessage || messageContextMenu.eventType == MtxEvent.FileMessage || messageContextMenu.eventType == MtxEvent.Sticker
|
||||||
|
text: qsTr("Save as")
|
||||||
|
onTriggered: timelineManager.timeline.saveMedia(messageContextMenu.eventId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
id: timelineRoot
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: colors.window
|
||||||
|
|
||||||
|
Text {
|
||||||
|
visible: !timelineManager.timeline && !timelineManager.isInitialSync
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: qsTr("No room open")
|
||||||
|
font.pointSize: 24
|
||||||
|
color: colors.windowText
|
||||||
|
}
|
||||||
|
|
||||||
|
BusyIndicator {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
running: timelineManager.isInitialSync
|
||||||
|
height: 200
|
||||||
|
width: 200
|
||||||
|
z: 3
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: chat
|
||||||
|
|
||||||
|
visible: timelineManager.timeline != null
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: chatFooter.top
|
||||||
|
|
||||||
|
anchors.leftMargin: 4
|
||||||
|
anchors.rightMargin: scrollbar.width
|
||||||
|
|
||||||
|
model: timelineManager.timeline
|
||||||
|
|
||||||
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
pixelAligned: true
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.NoButton
|
||||||
|
propagateComposedEvents: true
|
||||||
|
z: -1
|
||||||
|
onWheel: {
|
||||||
|
if (wheel.angleDelta != 0) {
|
||||||
|
chat.contentY = chat.contentY - wheel.angleDelta.y
|
||||||
|
wheel.accepted = true
|
||||||
|
chat.returnToBounds()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Shortcut {
|
||||||
|
sequence: StandardKey.MoveToPreviousPage
|
||||||
|
onActivated: { chat.contentY = chat.contentY - chat.height / 2; chat.returnToBounds(); }
|
||||||
|
}
|
||||||
|
Shortcut {
|
||||||
|
sequence: StandardKey.MoveToNextPage
|
||||||
|
onActivated: { chat.contentY = chat.contentY + chat.height / 2; chat.returnToBounds(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollBar.vertical: ScrollBar {
|
||||||
|
id: scrollbar
|
||||||
|
parent: chat.parent
|
||||||
|
anchors.top: chat.top
|
||||||
|
anchors.left: chat.right
|
||||||
|
anchors.bottom: chat.bottom
|
||||||
|
}
|
||||||
|
|
||||||
|
spacing: 4
|
||||||
|
verticalLayoutDirection: ListView.BottomToTop
|
||||||
|
|
||||||
|
onCountChanged: if (atYEnd) model.currentIndex = 0 // Mark last event as read, since we are at the bottom
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
// This would normally be previousSection, but our model's order is inverted.
|
||||||
|
property bool sectionBoundary: (ListView.nextSection != "" && ListView.nextSection !== ListView.section) || model.index === chat.count - 1
|
||||||
|
|
||||||
|
id: wrapper
|
||||||
|
property Item section
|
||||||
|
width: chat.width
|
||||||
|
height: section ? section.height + timelinerow.height : timelinerow.height
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
TimelineRow {
|
||||||
|
id: timelinerow
|
||||||
|
y: section ? section.y + section.height : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
onSectionBoundaryChanged: {
|
||||||
|
if (sectionBoundary) {
|
||||||
|
var properties = {
|
||||||
|
'modelData': model.dump,
|
||||||
|
'section': ListView.section,
|
||||||
|
'nextSection': ListView.nextSection
|
||||||
|
}
|
||||||
|
section = sectionHeader.createObject(wrapper, properties)
|
||||||
|
} else {
|
||||||
|
section.destroy()
|
||||||
|
section = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Binding {
|
||||||
|
target: chat.model
|
||||||
|
property: "currentIndex"
|
||||||
|
when: y + height + 2 * chat.spacing > chat.contentY + chat.height && y < chat.contentY + chat.height
|
||||||
|
value: index
|
||||||
|
delayed: true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
property: "section"
|
||||||
|
}
|
||||||
|
Component {
|
||||||
|
id: sectionHeader
|
||||||
|
Column {
|
||||||
|
property var modelData
|
||||||
|
property string section
|
||||||
|
property string nextSection
|
||||||
|
|
||||||
|
topPadding: 4
|
||||||
|
bottomPadding: 4
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
visible: !!modelData
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
height: (section.includes(" ") ? dateBubble.height + 8 + userName.height : userName.height) + 8
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: dateBubble
|
||||||
|
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
|
||||||
|
visible: section.includes(" ")
|
||||||
|
text: chat.model.formatDateSeparator(modelData.timestamp)
|
||||||
|
color: colors.windowText
|
||||||
|
|
||||||
|
height: contentHeight * 1.2
|
||||||
|
width: contentWidth * 1.2
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
background: Rectangle {
|
||||||
|
radius: parent.height / 2
|
||||||
|
color: colors.base
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Row {
|
||||||
|
height: userName.height
|
||||||
|
spacing: 4
|
||||||
|
Avatar {
|
||||||
|
width: avatarSize
|
||||||
|
height: avatarSize
|
||||||
|
url: chat.model.avatarUrl(modelData.userId).replace("mxc://", "image://MxcImage/")
|
||||||
|
displayName: modelData.userName
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: chat.model.openUserProfile(modelData.userId)
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: userName
|
||||||
|
text: chat.model.escapeEmoji(modelData.userName)
|
||||||
|
color: timelineManager.userColor(modelData.userId, colors.window)
|
||||||
|
textFormat: Text.RichText
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: chat.model.openUserProfile(section.split(" ")[0])
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: chatFooter
|
||||||
|
|
||||||
|
height: Math.max(16, footerContent.height)
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
z: 3
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: footerContent
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: typingDisplay
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.leftMargin: 10
|
||||||
|
anchors.rightMargin: 10
|
||||||
|
|
||||||
|
text: chat.model ? chat.model.formatTypingUsers(chat.model.typingUsers, colors.window) : ""
|
||||||
|
textFormat: Text.RichText
|
||||||
|
color: colors.windowText
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
id: replyPopup
|
||||||
|
|
||||||
|
visible: timelineManager.replyingEvent && chat.model
|
||||||
|
// Height of child, plus margins, plus border
|
||||||
|
height: replyPreview.height + 10
|
||||||
|
color: colors.base
|
||||||
|
|
||||||
|
|
||||||
|
Reply {
|
||||||
|
id: replyPreview
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 10
|
||||||
|
anchors.right: closeReplyButton.left
|
||||||
|
anchors.rightMargin: 20
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
|
modelData: chat.model ? chat.model.getDump(timelineManager.replyingEvent) : {}
|
||||||
|
userColor: timelineManager.userColor(modelData.userId, colors.window)
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageButton {
|
||||||
|
id: closeReplyButton
|
||||||
|
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 15
|
||||||
|
anchors.top: replyPreview.top
|
||||||
|
hoverEnabled: true
|
||||||
|
width: 16
|
||||||
|
height: 16
|
||||||
|
|
||||||
|
image: ":/icons/icons/ui/remove-symbol.png"
|
||||||
|
ToolTip.visible: closeReplyButton.hovered
|
||||||
|
ToolTip.text: qsTr("Close")
|
||||||
|
|
||||||
|
onClicked: timelineManager.closeReply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
resources/qml/delegates/FileMessage.qml
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
import QtQuick 2.6
|
||||||
|
import QtQuick.Layouts 1.2
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
radius: 10
|
||||||
|
color: colors.base
|
||||||
|
height: row.height + 24
|
||||||
|
width: parent ? parent.width : undefined
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: row
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: parent.width - 24
|
||||||
|
|
||||||
|
spacing: 15
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: button
|
||||||
|
color: colors.light
|
||||||
|
radius: 22
|
||||||
|
height: 44
|
||||||
|
width: 44
|
||||||
|
Image {
|
||||||
|
id: img
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
source: "qrc:/icons/icons/ui/arrow-pointing-down.png"
|
||||||
|
fillMode: Image.Pad
|
||||||
|
|
||||||
|
}
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: timelineManager.timeline.saveMedia(model.data.id)
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ColumnLayout {
|
||||||
|
id: col
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: model.data.body
|
||||||
|
textFormat: Text.PlainText
|
||||||
|
elide: Text.ElideRight
|
||||||
|
color: colors.text
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: model.data.filesize
|
||||||
|
textFormat: Text.PlainText
|
||||||
|
elide: Text.ElideRight
|
||||||
|
color: colors.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
resources/qml/delegates/ImageMessage.qml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import QtQuick 2.6
|
||||||
|
|
||||||
|
import im.nheko 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property double tempWidth: Math.min(parent ? parent.width : undefined, model.data.width)
|
||||||
|
property double tempHeight: tempWidth * model.data.proportionalHeight
|
||||||
|
|
||||||
|
property bool tooHigh: tempHeight > timelineRoot.height / 2
|
||||||
|
|
||||||
|
height: tooHigh ? timelineRoot.height / 2 : tempHeight
|
||||||
|
width: tooHigh ? (timelineRoot.height / 2) / model.data.proportionalHeight : tempWidth
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: img
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
source: model.data.url.replace("mxc://", "image://MxcImage/")
|
||||||
|
asynchronous: true
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
enabled: model.data.type == MtxEvent.ImageMessage
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: timelineManager.openImageOverlay(model.data.url, model.data.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
94
resources/qml/delegates/MessageDelegate.qml
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
import QtQuick 2.6
|
||||||
|
import im.nheko 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
// Workaround to have an assignable global property
|
||||||
|
Item {
|
||||||
|
id: model
|
||||||
|
property var data;
|
||||||
|
}
|
||||||
|
|
||||||
|
property alias modelData: model.data
|
||||||
|
|
||||||
|
height: chooser.childrenRect.height
|
||||||
|
|
||||||
|
DelegateChooser {
|
||||||
|
id: chooser
|
||||||
|
//role: "type" //< not supported in our custom implementation, have to use roleValue
|
||||||
|
roleValue: model.data.type
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: MtxEvent.UnknownMessage
|
||||||
|
Placeholder { text: "Unretrieved event" }
|
||||||
|
}
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: MtxEvent.TextMessage
|
||||||
|
TextMessage {}
|
||||||
|
}
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: MtxEvent.NoticeMessage
|
||||||
|
NoticeMessage {}
|
||||||
|
}
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: MtxEvent.EmoteMessage
|
||||||
|
NoticeMessage {
|
||||||
|
formatted: chat.model.escapeEmoji(modelData.userName) + " " + model.data.formattedBody
|
||||||
|
color: timelineManager.userColor(modelData.userId, colors.window)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: MtxEvent.ImageMessage
|
||||||
|
ImageMessage {}
|
||||||
|
}
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: MtxEvent.Sticker
|
||||||
|
ImageMessage {}
|
||||||
|
}
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: MtxEvent.FileMessage
|
||||||
|
FileMessage {}
|
||||||
|
}
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: MtxEvent.VideoMessage
|
||||||
|
PlayableMediaMessage {}
|
||||||
|
}
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: MtxEvent.AudioMessage
|
||||||
|
PlayableMediaMessage {}
|
||||||
|
}
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: MtxEvent.Redacted
|
||||||
|
Pill {
|
||||||
|
text: qsTr("redacted")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: MtxEvent.Encryption
|
||||||
|
Pill {
|
||||||
|
text: qsTr("Encryption enabled")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: MtxEvent.Name
|
||||||
|
NoticeMessage {
|
||||||
|
text: model.data.roomName ? qsTr("room name changed to: %1").arg(model.data.roomName) : qsTr("removed room name")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: MtxEvent.Topic
|
||||||
|
NoticeMessage {
|
||||||
|
text: model.data.roomTopic ? qsTr("topic changed to: %1").arg(model.data.roomTopic) : qsTr("removed topic")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: MtxEvent.Member
|
||||||
|
NoticeMessage {
|
||||||
|
text: timelineManager.timeline.formatMemberEvent(model.data.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DelegateChoice {
|
||||||
|
Placeholder {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
resources/qml/delegates/NoticeMessage.qml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
TextMessage {
|
||||||
|
font.italic: true
|
||||||
|
color: inactiveColors.text
|
||||||
|
}
|
14
resources/qml/delegates/Pill.qml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import QtQuick 2.5
|
||||||
|
import QtQuick.Controls 2.1
|
||||||
|
|
||||||
|
Label {
|
||||||
|
color: inactiveColors.text
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
|
||||||
|
height: contentHeight * 1.2
|
||||||
|
width: contentWidth * 1.2
|
||||||
|
background: Rectangle {
|
||||||
|
radius: parent.height / 2
|
||||||
|
color: colors.base
|
||||||
|
}
|
||||||
|
}
|
7
resources/qml/delegates/Placeholder.qml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import ".."
|
||||||
|
|
||||||
|
MatrixText {
|
||||||
|
text: qsTr("unimplemented event: ") + model.data.typeString
|
||||||
|
width: parent ? parent.width : undefined
|
||||||
|
color: inactiveColors.text
|
||||||
|
}
|
167
resources/qml/delegates/PlayableMediaMessage.qml
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
import QtQuick 2.6
|
||||||
|
import QtQuick.Layouts 1.2
|
||||||
|
import QtQuick.Controls 2.1
|
||||||
|
import QtMultimedia 5.6
|
||||||
|
|
||||||
|
import im.nheko 1.0
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: bg
|
||||||
|
radius: 10
|
||||||
|
color: colors.base
|
||||||
|
height: content.height + 24
|
||||||
|
width: parent ? parent.width : undefined
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: content
|
||||||
|
width: parent.width - 24
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: videoContainer
|
||||||
|
visible: model.data.type == MtxEvent.VideoMessage
|
||||||
|
width: Math.min(parent.width, model.data.width ? model.data.width : 400) // some media has 0 as size...
|
||||||
|
height: width*model.data.proportionalHeight
|
||||||
|
Image {
|
||||||
|
anchors.fill: parent
|
||||||
|
source: model.data.thumbnailUrl.replace("mxc://", "image://MxcImage/")
|
||||||
|
asynchronous: true
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
|
||||||
|
VideoOutput {
|
||||||
|
anchors.fill: parent
|
||||||
|
fillMode: VideoOutput.PreserveAspectFit
|
||||||
|
source: media
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
width: parent.width
|
||||||
|
Text {
|
||||||
|
id: positionText
|
||||||
|
text: "--:--:--"
|
||||||
|
color: colors.text
|
||||||
|
}
|
||||||
|
Slider {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
id: progress
|
||||||
|
value: media.position
|
||||||
|
from: 0
|
||||||
|
to: media.duration
|
||||||
|
|
||||||
|
onMoved: media.seek(value)
|
||||||
|
//indeterminate: true
|
||||||
|
function updatePositionTexts() {
|
||||||
|
function formatTime(date) {
|
||||||
|
var hh = date.getUTCHours();
|
||||||
|
var mm = date.getUTCMinutes();
|
||||||
|
var ss = date.getSeconds();
|
||||||
|
if (hh < 10) {hh = "0"+hh;}
|
||||||
|
if (mm < 10) {mm = "0"+mm;}
|
||||||
|
if (ss < 10) {ss = "0"+ss;}
|
||||||
|
return hh+":"+mm+":"+ss;
|
||||||
|
}
|
||||||
|
positionText.text = formatTime(new Date(media.position))
|
||||||
|
durationText.text = formatTime(new Date(media.duration))
|
||||||
|
}
|
||||||
|
onValueChanged: updatePositionTexts()
|
||||||
|
|
||||||
|
palette: colors
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
id: durationText
|
||||||
|
text: "--:--:--"
|
||||||
|
color: colors.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
spacing: 15
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: button
|
||||||
|
color: colors.window
|
||||||
|
radius: 22
|
||||||
|
height: 44
|
||||||
|
width: 44
|
||||||
|
Image {
|
||||||
|
id: img
|
||||||
|
anchors.centerIn: parent
|
||||||
|
z: 3
|
||||||
|
|
||||||
|
source: "image://colorimage/:/icons/icons/ui/arrow-pointing-down.png?"+colors.text
|
||||||
|
fillMode: Image.Pad
|
||||||
|
|
||||||
|
}
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
switch (button.state) {
|
||||||
|
case "": timelineManager.timeline.cacheMedia(model.data.id); break;
|
||||||
|
case "stopped":
|
||||||
|
media.play(); console.log("play");
|
||||||
|
button.state = "playing"
|
||||||
|
break
|
||||||
|
case "playing":
|
||||||
|
media.pause(); console.log("pause");
|
||||||
|
button.state = "stopped"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
}
|
||||||
|
MediaPlayer {
|
||||||
|
id: media
|
||||||
|
onError: console.log(errorString)
|
||||||
|
onStatusChanged: if(status == MediaPlayer.Loaded) progress.updatePositionTexts()
|
||||||
|
onStopped: button.state = "stopped"
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: timelineManager.timeline
|
||||||
|
onMediaCached: {
|
||||||
|
if (mxcUrl == model.data.url) {
|
||||||
|
media.source = "file://" + cacheUrl
|
||||||
|
button.state = "stopped"
|
||||||
|
console.log("media loaded: " + mxcUrl + " at " + cacheUrl)
|
||||||
|
}
|
||||||
|
console.log("media cached: " + mxcUrl + " at " + cacheUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
name: "stopped"
|
||||||
|
PropertyChanges { target: img; source: "image://colorimage/:/icons/icons/ui/play-sign.png?"+colors.text }
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "playing"
|
||||||
|
PropertyChanges { target: img; source: "image://colorimage/:/icons/icons/ui/pause-symbol.png?"+colors.text }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
ColumnLayout {
|
||||||
|
id: col
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: model.data.body
|
||||||
|
textFormat: Text.PlainText
|
||||||
|
elide: Text.ElideRight
|
||||||
|
color: colors.text
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: model.data.filesize
|
||||||
|
textFormat: Text.PlainText
|
||||||
|
elide: Text.ElideRight
|
||||||
|
color: colors.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
58
resources/qml/delegates/Reply.qml
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import QtQuick 2.6
|
||||||
|
import QtQuick.Controls 2.3
|
||||||
|
import QtQuick.Layouts 1.2
|
||||||
|
import QtQuick.Window 2.2
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: replyComponent
|
||||||
|
|
||||||
|
property alias modelData: reply.modelData
|
||||||
|
property color userColor: "red"
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
height: replyContainer.height
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
preventStealing: true
|
||||||
|
onClicked: chat.positionViewAtIndex(chat.model.idToIndex(timelineManager.replyingEvent), ListView.Contain)
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: colorLine
|
||||||
|
|
||||||
|
anchors.top: replyContainer.top
|
||||||
|
anchors.bottom: replyContainer.bottom
|
||||||
|
width: 4
|
||||||
|
|
||||||
|
color: timelineManager.userColor(reply.modelData.userId, colors.window)
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: replyContainer
|
||||||
|
anchors.left: colorLine.right
|
||||||
|
anchors.leftMargin: 4
|
||||||
|
width: parent.width - 8
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: userName
|
||||||
|
text: chat.model ? chat.model.escapeEmoji(reply.modelData.userName) : ""
|
||||||
|
color: replyComponent.userColor
|
||||||
|
textFormat: Text.RichText
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: chat.model.openUserProfile(reply.modelData.userId)
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageDelegate {
|
||||||
|
id: reply
|
||||||
|
width: parent.width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
color: Qt.rgba(userColor.r, userColor.g, userColor.b, 0.2)
|
||||||
|
}
|
7
resources/qml/delegates/TextMessage.qml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import ".."
|
||||||
|
|
||||||
|
MatrixText {
|
||||||
|
property string formatted: model.data.formattedBody
|
||||||
|
text: "<style type=\"text/css\">a { color:"+colors.link+";}</style>" + formatted.replace("<pre>", "<pre style='white-space: pre-wrap'>")
|
||||||
|
width: parent ? parent.width : undefined
|
||||||
|
}
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
@ -1,5 +1,6 @@
|
||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/icons">
|
<qresource prefix="/icons">
|
||||||
|
<file>icons/ui/at-solid.svg</file>
|
||||||
<file>icons/ui/volume-off-indicator.png</file>
|
<file>icons/ui/volume-off-indicator.png</file>
|
||||||
<file>icons/ui/volume-off-indicator@2x.png</file>
|
<file>icons/ui/volume-off-indicator@2x.png</file>
|
||||||
<file>icons/ui/black-bubble-speech.png</file>
|
<file>icons/ui/black-bubble-speech.png</file>
|
||||||
|
@ -62,6 +63,8 @@
|
||||||
|
|
||||||
<file>icons/ui/edit.png</file>
|
<file>icons/ui/edit.png</file>
|
||||||
<file>icons/ui/edit@2x.png</file>
|
<file>icons/ui/edit@2x.png</file>
|
||||||
|
|
||||||
|
<file>icons/ui/mail-reply.png</file>
|
||||||
|
|
||||||
<file>icons/emoji-categories/people.png</file>
|
<file>icons/emoji-categories/people.png</file>
|
||||||
<file>icons/emoji-categories/people@2x.png</file>
|
<file>icons/emoji-categories/people@2x.png</file>
|
||||||
|
@ -82,6 +85,7 @@
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/logos">
|
<qresource prefix="/logos">
|
||||||
<file>nheko.png</file>
|
<file>nheko.png</file>
|
||||||
|
<file>nheko.svg</file>
|
||||||
|
|
||||||
<file>splash.png</file>
|
<file>splash.png</file>
|
||||||
<file>splash@2x.png</file>
|
<file>splash@2x.png</file>
|
||||||
|
@ -99,16 +103,27 @@
|
||||||
<file>nheko-32.png</file>
|
<file>nheko-32.png</file>
|
||||||
<file>nheko-16.png</file>
|
<file>nheko-16.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/fonts">
|
|
||||||
<file>fonts/OpenSans/OpenSans-Regular.ttf</file>
|
|
||||||
<file>fonts/OpenSans/OpenSans-Italic.ttf</file>
|
|
||||||
<file>fonts/OpenSans/OpenSans-Bold.ttf</file>
|
|
||||||
<file>fonts/OpenSans/OpenSans-Semibold.ttf</file>
|
|
||||||
<file>fonts/EmojiOne/emojione-android.ttf</file>
|
|
||||||
</qresource>
|
|
||||||
<qresource prefix="/styles">
|
<qresource prefix="/styles">
|
||||||
<file>styles/system.qss</file>
|
<file>styles/system.qss</file>
|
||||||
<file>styles/nheko.qss</file>
|
<file>styles/nheko.qss</file>
|
||||||
<file>styles/nheko-dark.qss</file>
|
<file>styles/nheko-dark.qss</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
|
<qresource prefix="/">
|
||||||
|
<file>qml/TimelineView.qml</file>
|
||||||
|
<file>qml/Avatar.qml</file>
|
||||||
|
<file>qml/ImageButton.qml</file>
|
||||||
|
<file>qml/MatrixText.qml</file>
|
||||||
|
<file>qml/StatusIndicator.qml</file>
|
||||||
|
<file>qml/EncryptionIndicator.qml</file>
|
||||||
|
<file>qml/TimelineRow.qml</file>
|
||||||
|
<file>qml/delegates/MessageDelegate.qml</file>
|
||||||
|
<file>qml/delegates/TextMessage.qml</file>
|
||||||
|
<file>qml/delegates/NoticeMessage.qml</file>
|
||||||
|
<file>qml/delegates/ImageMessage.qml</file>
|
||||||
|
<file>qml/delegates/PlayableMediaMessage.qml</file>
|
||||||
|
<file>qml/delegates/FileMessage.qml</file>
|
||||||
|
<file>qml/delegates/Pill.qml</file>
|
||||||
|
<file>qml/delegates/Placeholder.qml</file>
|
||||||
|
<file>qml/delegates/Reply.qml</file>
|
||||||
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 25 KiB |
|
@ -3,13 +3,75 @@ QLabel {
|
||||||
color: #caccd1;
|
color: #caccd1;
|
||||||
}
|
}
|
||||||
|
|
||||||
TimelineItem {
|
TextLabel::a {
|
||||||
qproperty-backgroundColor: #202228;
|
color: #38a3d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
QuickSwitcher,
|
||||||
|
ReplyPopup,
|
||||||
|
SuggestionsPopup,
|
||||||
|
UserSettingsPage,
|
||||||
|
#scroll_widget,
|
||||||
|
#UserSettingScrollWidget {
|
||||||
|
background-color: #202228;
|
||||||
}
|
}
|
||||||
|
|
||||||
#chatPage,
|
#chatPage,
|
||||||
#chatPage > * {
|
#chatPage > *,
|
||||||
|
CommunitiesList,
|
||||||
|
CommunitiesList > *,
|
||||||
|
RoomList,
|
||||||
|
RoomList > *,
|
||||||
|
TimelineView,
|
||||||
|
TimelineView > *,
|
||||||
|
UserMentionsWidget,
|
||||||
|
UserMentionsWidget > * {
|
||||||
|
background-color: #2d3139;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
QLineEdit,
|
||||||
|
QListWidget,
|
||||||
|
WelcomePage,
|
||||||
|
LoginPage,
|
||||||
|
RegisterPage,
|
||||||
|
EditModal,
|
||||||
|
emoji--Panel,
|
||||||
|
emoji--Panel > *,
|
||||||
|
dialogs--Logout,
|
||||||
|
dialogs--ReCaptcha,
|
||||||
|
dialogs--LeaveRoom,
|
||||||
|
dialogs--CreateRoom,
|
||||||
|
dialogs--RoomSettings,
|
||||||
|
dialogs--InviteUsers,
|
||||||
|
dialogs--ReadReceipts,
|
||||||
|
dialogs--JoinRoom,
|
||||||
|
dialogs--MemberList,
|
||||||
|
dialogs--PreviewUploadOverlay,
|
||||||
|
dialogs--UserProfile,
|
||||||
|
dialogs--CreateRoom > QLineEdit,
|
||||||
|
dialogs--InviteUsers > QLineEdit,
|
||||||
|
dialogs--JoinRoom > QLineEdit {
|
||||||
background-color: #202228;
|
background-color: #202228;
|
||||||
|
color: #caccd1;
|
||||||
|
}
|
||||||
|
|
||||||
|
emoji--Panel QWidget { border: none; }
|
||||||
|
emoji--Panel QScrollBar:vertical { width: 0px; margin: 0px; }
|
||||||
|
emoji--Panel QScrollBar::handle:vertical { min-height: 30px; }
|
||||||
|
|
||||||
|
emoji--Category,
|
||||||
|
emoji--Category > * {
|
||||||
|
background-color: #2d3139;
|
||||||
|
color: #727274;
|
||||||
|
}
|
||||||
|
|
||||||
|
emoji--Category QLabel {
|
||||||
|
margin: 20px 0 20px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
TimelineItem {
|
||||||
|
qproperty-backgroundColor: #202228;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sideBar {
|
#sideBar {
|
||||||
|
@ -18,18 +80,9 @@ TimelineItem {
|
||||||
border-left: 1px solid #202228;
|
border-left: 1px solid #202228;
|
||||||
}
|
}
|
||||||
|
|
||||||
TimelineView,
|
UserMentionsWidget > TimelineItem {
|
||||||
TimelineView > * {
|
qproperty-backgroundColor: #202228;
|
||||||
background-color: #202228;
|
qproperty-hoverColor: rgba(45, 49, 57, 120);
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#scroll_widget {
|
|
||||||
background-color: #202228;
|
|
||||||
}
|
|
||||||
|
|
||||||
QuickSwitcher {
|
|
||||||
background-color: #202228;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InfoMessage {
|
InfoMessage {
|
||||||
|
@ -37,21 +90,11 @@ InfoMessage {
|
||||||
qproperty-boxColor: rgba(45, 49, 57, 120);
|
qproperty-boxColor: rgba(45, 49, 57, 120);
|
||||||
}
|
}
|
||||||
|
|
||||||
SuggestionsPopup {
|
|
||||||
background-color: #202228;
|
|
||||||
}
|
|
||||||
|
|
||||||
PopupItem {
|
PopupItem {
|
||||||
background-color: #202228;
|
background-color: #202228;
|
||||||
qproperty-hoverColor: rgba(45, 49, 57, 120);
|
qproperty-hoverColor: rgba(45, 49, 57, 120);
|
||||||
}
|
}
|
||||||
|
|
||||||
RoomList,
|
|
||||||
RoomList > * {
|
|
||||||
background-color: #2d3139;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
TypingDisplay {
|
TypingDisplay {
|
||||||
qproperty-textColor: #caccd1;
|
qproperty-textColor: #caccd1;
|
||||||
qproperty-backgroundColor: #202228;
|
qproperty-backgroundColor: #202228;
|
||||||
|
@ -61,35 +104,26 @@ TypingDisplay {
|
||||||
background-color: #2d3139;
|
background-color: #2d3139;
|
||||||
}
|
}
|
||||||
|
|
||||||
CommunitiesList,
|
|
||||||
CommunitiesList > * {
|
|
||||||
background-color: #2d3139;
|
|
||||||
}
|
|
||||||
|
|
||||||
FlatButton {
|
FlatButton {
|
||||||
qproperty-foregroundColor: #727274;
|
qproperty-foregroundColor: #727274;
|
||||||
qproperty-backgroundColor: #333;
|
qproperty-backgroundColor: #333;
|
||||||
qproperty-disabledForegroundColor: #222;
|
qproperty-disabledForegroundColor: #222;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudioItem,
|
||||||
FileItem {
|
FileItem {
|
||||||
qproperty-textColor: #caccd1;
|
qproperty-textColor: #caccd1;
|
||||||
qproperty-backgroundColor: #2d3139;
|
qproperty-backgroundColor: #2d3139;
|
||||||
qproperty-iconColor: #caccd1;
|
qproperty-iconColor: #caccd1;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioItem {
|
|
||||||
qproperty-textColor: #caccd1;
|
|
||||||
qproperty-backgroundColor: #2d3139;
|
|
||||||
qproperty-iconColor: #caccd1;
|
|
||||||
}
|
|
||||||
|
|
||||||
RaisedButton {
|
RaisedButton {
|
||||||
qproperty-foregroundColor: #caccd1;
|
qproperty-foregroundColor: #caccd1;
|
||||||
qproperty-backgroundColor: #333;
|
qproperty-backgroundColor: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
RoomInfoListItem {
|
RoomInfoListItem,
|
||||||
|
UserMentionsWidget {
|
||||||
qproperty-mentionedColor: #a82353;
|
qproperty-mentionedColor: #a82353;
|
||||||
qproperty-highlightedBackgroundColor: #4d84c7;
|
qproperty-highlightedBackgroundColor: #4d84c7;
|
||||||
qproperty-hoverBackgroundColor: rgba(230, 230, 230, 30);
|
qproperty-hoverBackgroundColor: rgba(230, 230, 230, 30);
|
||||||
|
@ -111,13 +145,15 @@ RoomInfoListItem {
|
||||||
qproperty-highlightedTimestampColor: #e7e7e9;
|
qproperty-highlightedTimestampColor: #e7e7e9;
|
||||||
qproperty-hoverTimestampColor: #f4f5f8;
|
qproperty-hoverTimestampColor: #f4f5f8;
|
||||||
|
|
||||||
qproperty-avatarBgColor: #202228;
|
|
||||||
qproperty-avatarFgColor: white;
|
|
||||||
|
|
||||||
qproperty-bubbleFgColor: white;
|
qproperty-bubbleFgColor: white;
|
||||||
qproperty-bubbleBgColor: #4d84c7;
|
qproperty-bubbleBgColor: #4d84c7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RoomInfoListItem > Avatar {
|
||||||
|
qproperty-backgroundColor: #202228;
|
||||||
|
qproperty-textColor: white;
|
||||||
|
}
|
||||||
|
|
||||||
CommunitiesListItem {
|
CommunitiesListItem {
|
||||||
qproperty-highlightedBackgroundColor: #4d84c7;
|
qproperty-highlightedBackgroundColor: #4d84c7;
|
||||||
qproperty-hoverBackgroundColor: rgba(230, 230, 230, 30);
|
qproperty-hoverBackgroundColor: rgba(230, 230, 230, 30);
|
||||||
|
@ -141,12 +177,12 @@ UserInfoWidget {
|
||||||
border-bottom: 1px solid #202228;
|
border-bottom: 1px solid #202228;
|
||||||
}
|
}
|
||||||
|
|
||||||
UserSettingsPage {
|
#UserSettingScrollWidget > QComboBox {
|
||||||
background-color: #202228;
|
color: #202228;
|
||||||
}
|
}
|
||||||
|
|
||||||
#UserSettingScrollWidget {
|
#UserSettingScrollWidget > QComboBox {
|
||||||
background-color: #202228;
|
color: #202228;
|
||||||
}
|
}
|
||||||
|
|
||||||
Avatar {
|
Avatar {
|
||||||
|
@ -154,55 +190,17 @@ Avatar {
|
||||||
qproperty-backgroundColor: #2d3139;
|
qproperty-backgroundColor: #2d3139;
|
||||||
}
|
}
|
||||||
|
|
||||||
#displayNameLabel {
|
#displayNameLabel,
|
||||||
color: #f2f2f2;
|
|
||||||
}
|
|
||||||
|
|
||||||
#userIdLabel {
|
#userIdLabel {
|
||||||
color: #f2f2f2;
|
color: #f2f2f2;
|
||||||
}
|
}
|
||||||
|
|
||||||
dialogs--Logout,
|
|
||||||
dialogs--ReCaptcha,
|
|
||||||
dialogs--LeaveRoom,
|
|
||||||
dialogs--CreateRoom,
|
|
||||||
dialogs--RoomSettings,
|
|
||||||
dialogs--InviteUsers,
|
|
||||||
dialogs--ReadReceipts,
|
|
||||||
dialogs--JoinRoom,
|
|
||||||
dialogs--MemberList,
|
|
||||||
dialogs--PreviewUploadOverlay,
|
|
||||||
dialogs--UserProfile,
|
|
||||||
dialogs--CreateRoom > QLineEdit,
|
|
||||||
dialogs--InviteUsers > QLineEdit,
|
|
||||||
EditModal,
|
|
||||||
dialogs--JoinRoom > QLineEdit {
|
|
||||||
background-color: #202228;
|
|
||||||
color: #caccd1;
|
|
||||||
}
|
|
||||||
|
|
||||||
TopSection {
|
TopSection {
|
||||||
qproperty-textColor: #caccd1;
|
qproperty-textColor: #caccd1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QListWidget,
|
emoji--Category {
|
||||||
WelcomePage,
|
qproperty-hoverBackgroundColor: rgba(230, 230, 230, 30);
|
||||||
LoginPage,
|
|
||||||
RegisterPage {
|
|
||||||
background-color: #202228;
|
|
||||||
color: #caccd1;
|
|
||||||
}
|
|
||||||
|
|
||||||
emoji--Panel,
|
|
||||||
emoji--Panel > * {
|
|
||||||
background-color: #202228;
|
|
||||||
color: #caccd1;
|
|
||||||
}
|
|
||||||
|
|
||||||
emoji--Category,
|
|
||||||
emoji--Category > * {
|
|
||||||
background-color: #2d3139;
|
|
||||||
color: #caccd1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FloatingButton {
|
FloatingButton {
|
||||||
|
@ -221,23 +219,14 @@ ScrollBar {
|
||||||
qproperty-backgroundColor: #202228;
|
qproperty-backgroundColor: #202228;
|
||||||
}
|
}
|
||||||
|
|
||||||
SideBarActions {
|
SideBarActions,
|
||||||
|
TopRoomBar
|
||||||
|
{
|
||||||
border: none;
|
border: none;
|
||||||
border-top: 1px solid #202228;
|
border-top: 1px solid #202228;
|
||||||
background-color: #2d3139;
|
background-color: #2d3139;
|
||||||
}
|
}
|
||||||
|
|
||||||
TopRoomBar {
|
|
||||||
border: none;
|
|
||||||
border-bottom: 1px solid #202228;
|
|
||||||
background-color: #2d3139;
|
|
||||||
}
|
|
||||||
|
|
||||||
QLineEdit {
|
|
||||||
background-color: #202228;
|
|
||||||
color: #caccd1;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextInputWidget {
|
TextInputWidget {
|
||||||
border: none;
|
border: none;
|
||||||
border-top: 1px solid #2d3139;
|
border-top: 1px solid #2d3139;
|
||||||
|
@ -261,3 +250,5 @@ SnackBar {
|
||||||
qproperty-textColor: #caccd1;
|
qproperty-textColor: #caccd1;
|
||||||
qproperty-bgColor: #202228;
|
qproperty-bgColor: #202228;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSplitter::handle { image: none; }
|
||||||
|
|
|
@ -3,13 +3,38 @@ QLabel {
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
TimelineItem {
|
TextLabel::a {
|
||||||
qproperty-backgroundColor: white;
|
color: #0077b5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QuickSwitcher,
|
||||||
|
ReplyPopup,
|
||||||
|
SuggestionsPopup,
|
||||||
|
UserSettingsPage,
|
||||||
|
#scroll_widget,
|
||||||
|
#UserSettingScrollWidget {
|
||||||
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
#chatPage,
|
#chatPage,
|
||||||
#chatPage > * {
|
#chatPage > *,
|
||||||
|
CommunitiesList,
|
||||||
|
CommunitiesList > *,
|
||||||
|
RoomList,
|
||||||
|
RoomList > *,
|
||||||
|
TimelineView,
|
||||||
|
TimelineView > *,
|
||||||
|
UserMentionsWidget,
|
||||||
|
UserMentionsWidget > *,
|
||||||
|
TimelineView,
|
||||||
|
TimelineView > * {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
TimelineItem {
|
||||||
|
qproperty-backgroundColor: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sideBar {
|
#sideBar {
|
||||||
|
@ -18,18 +43,9 @@ TimelineItem {
|
||||||
border-left: 1px solid #dee1f3;
|
border-left: 1px solid #dee1f3;
|
||||||
}
|
}
|
||||||
|
|
||||||
TimelineView,
|
UserMentionsWidget > TimelineItem {
|
||||||
TimelineView > * {
|
qproperty-backgroundColor: white;
|
||||||
background-color: white;
|
qproperty-hoverColor: rgba(192, 193, 195, 120);
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#scroll_widget {
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
QuickSwitcher {
|
|
||||||
background-color: white;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InfoMessage {
|
InfoMessage {
|
||||||
|
@ -42,17 +58,15 @@ TypingDisplay {
|
||||||
qproperty-backgroundColor: white;
|
qproperty-backgroundColor: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
SuggestionsPopup {
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
PopupItem {
|
PopupItem {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
qproperty-hoverColor: rgba(192, 193, 195, 120);
|
qproperty-hoverColor: rgba(192, 193, 195, 120);
|
||||||
}
|
}
|
||||||
|
|
||||||
RoomList,
|
RoomList,
|
||||||
RoomList > * {
|
RoomList > *,
|
||||||
|
CommunitiesList,
|
||||||
|
CommunitiesList > * {
|
||||||
background-color: #2e3649;
|
background-color: #2e3649;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
@ -61,27 +75,17 @@ RoomList > * {
|
||||||
background-color: #2e3649;
|
background-color: #2e3649;
|
||||||
}
|
}
|
||||||
|
|
||||||
CommunitiesList,
|
|
||||||
CommunitiesList > * {
|
|
||||||
background-color: #2e3649;
|
|
||||||
}
|
|
||||||
|
|
||||||
FlatButton {
|
FlatButton {
|
||||||
qproperty-foregroundColor: #495057;
|
qproperty-foregroundColor: #495057;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudioItem,
|
||||||
FileItem {
|
FileItem {
|
||||||
qproperty-textColor: #333;
|
qproperty-textColor: #333;
|
||||||
qproperty-backgroundColor: #f2f2f2;
|
qproperty-backgroundColor: #f2f2f2;
|
||||||
qproperty-iconColor: white;
|
qproperty-iconColor: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioItem {
|
|
||||||
qproperty-textColor: #333;
|
|
||||||
qproperty-backgroundColor: #f2f2f2;
|
|
||||||
qproperty-iconColor: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
RaisedButton {
|
RaisedButton {
|
||||||
qproperty-foregroundColor: white;
|
qproperty-foregroundColor: white;
|
||||||
}
|
}
|
||||||
|
@ -89,7 +93,7 @@ RaisedButton {
|
||||||
RoomInfoListItem {
|
RoomInfoListItem {
|
||||||
qproperty-mentionedColor: #a82353;
|
qproperty-mentionedColor: #a82353;
|
||||||
qproperty-highlightedBackgroundColor: #38A3D8;
|
qproperty-highlightedBackgroundColor: #38A3D8;
|
||||||
qproperty-hoverBackgroundColor: rgba(200, 200, 200, 70);
|
qproperty-hoverBackgroundColor: rgba(200, 200, 200, 40);
|
||||||
qproperty-hoverTitleColor: #f2f5f8;
|
qproperty-hoverTitleColor: #f2f5f8;
|
||||||
qproperty-hoverSubtitleColor: white;
|
qproperty-hoverSubtitleColor: white;
|
||||||
qproperty-backgroundColor: #f2f5f8;
|
qproperty-backgroundColor: #f2f5f8;
|
||||||
|
@ -107,16 +111,18 @@ RoomInfoListItem {
|
||||||
qproperty-highlightedTimestampColor: #f4f4f5;
|
qproperty-highlightedTimestampColor: #f4f4f5;
|
||||||
qproperty-hoverTimestampColor: white;
|
qproperty-hoverTimestampColor: white;
|
||||||
|
|
||||||
qproperty-avatarBgColor: #eee;
|
|
||||||
qproperty-avatarFgColor: black;
|
|
||||||
|
|
||||||
qproperty-bubbleFgColor: white;
|
qproperty-bubbleFgColor: white;
|
||||||
qproperty-bubbleBgColor: #38A3D8;
|
qproperty-bubbleBgColor: #38A3D8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RoomInfoListItem > Avatar {
|
||||||
|
qproperty-backgroundColor: #eee;
|
||||||
|
qproperty-textColor: black;
|
||||||
|
}
|
||||||
|
|
||||||
CommunitiesListItem {
|
CommunitiesListItem {
|
||||||
qproperty-highlightedBackgroundColor: #38A3D8;
|
qproperty-highlightedBackgroundColor: #38A3D8;
|
||||||
qproperty-hoverBackgroundColor: rgba(200, 200, 200, 70);
|
qproperty-hoverBackgroundColor: rgba(200, 200, 200, 40);
|
||||||
qproperty-backgroundColor: #f2f5f8;
|
qproperty-backgroundColor: #f2f5f8;
|
||||||
|
|
||||||
qproperty-avatarBgColor: #eee;
|
qproperty-avatarBgColor: #eee;
|
||||||
|
@ -141,14 +147,6 @@ UserInfoWidget {
|
||||||
border-bottom: 2px solid #ccc;
|
border-bottom: 2px solid #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
UserSettingsPage {
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
#UserSettingScrollWidget {
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
Avatar {
|
Avatar {
|
||||||
qproperty-textColor: black;
|
qproperty-textColor: black;
|
||||||
qproperty-backgroundColor: #eee;
|
qproperty-backgroundColor: #eee;
|
||||||
|
@ -196,12 +194,22 @@ emoji--Panel > * {
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emoji--Panel QWidget { border: none; }
|
||||||
|
emoji--Panel QScrollBar:vertical { width: 0px; margin: 0px; }
|
||||||
|
emoji--Panel QScrollBar::handle:vertical { min-height: 30px; }
|
||||||
|
|
||||||
|
emoji--Category {
|
||||||
|
qproperty-hoverBackgroundColor: rgba(200, 200, 200, 70);
|
||||||
|
}
|
||||||
|
|
||||||
emoji--Category,
|
emoji--Category,
|
||||||
emoji--Category > * {
|
emoji--Category > * {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emoji--Category QLabel { margin: 20px 0 20px 8px; }
|
||||||
|
|
||||||
FloatingButton {
|
FloatingButton {
|
||||||
qproperty-backgroundColor: #efefef;
|
qproperty-backgroundColor: #efefef;
|
||||||
qproperty-foregroundColor: black;
|
qproperty-foregroundColor: black;
|
||||||
|
@ -244,3 +252,5 @@ SnackBar {
|
||||||
qproperty-textColor: white;
|
qproperty-textColor: white;
|
||||||
qproperty-bgColor: #495057;
|
qproperty-bgColor: #495057;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSplitter::handle { image: none; }
|
||||||
|
|
|
@ -1,3 +1,16 @@
|
||||||
|
#chatPage,
|
||||||
|
#chatPage > *,
|
||||||
|
CommunitiesList,
|
||||||
|
CommunitiesList > *,
|
||||||
|
RoomList,
|
||||||
|
RoomList > *,
|
||||||
|
TimelineView,
|
||||||
|
TimelineView > *,
|
||||||
|
UserMentionsWidget,
|
||||||
|
UserMentionsWidget > * {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
TypingDisplay {
|
TypingDisplay {
|
||||||
qproperty-textColor: palette(text);
|
qproperty-textColor: palette(text);
|
||||||
qproperty-backgroundColor: palette(window);
|
qproperty-backgroundColor: palette(window);
|
||||||
|
@ -7,21 +20,18 @@ TimelineItem {
|
||||||
qproperty-backgroundColor: palette(window);
|
qproperty-backgroundColor: palette(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimelineView,
|
UserMentionsWidget > TimelineItem {
|
||||||
TimelineView > * {
|
qproperty-backgroundColor: palette(window);
|
||||||
border: none;
|
qproperty-hoverColor: palette(base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SideBarActions,
|
||||||
TextInputWidget {
|
TextInputWidget {
|
||||||
border: none;
|
border: none;
|
||||||
border-top: 1px solid palette(mid);
|
border-top: 1px solid palette(mid);
|
||||||
}
|
}
|
||||||
|
|
||||||
SideBarActions {
|
UserInfoWidget,
|
||||||
border: none;
|
|
||||||
border-top: 1px solid palette(mid);
|
|
||||||
}
|
|
||||||
|
|
||||||
TopRoomBar {
|
TopRoomBar {
|
||||||
border: none;
|
border: none;
|
||||||
border-bottom: 1px solid palette(mid);
|
border-bottom: 1px solid palette(mid);
|
||||||
|
@ -33,11 +43,6 @@ RoomList > * {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
UserInfoWidget {
|
|
||||||
border: none;
|
|
||||||
border-bottom: 1px solid palette(mid);
|
|
||||||
}
|
|
||||||
|
|
||||||
#sideBar {
|
#sideBar {
|
||||||
border: none;
|
border: none;
|
||||||
border-right: 1px solid palette(mid);
|
border-right: 1px solid palette(mid);
|
||||||
|
@ -57,18 +62,13 @@ FlatButton {
|
||||||
qproperty-foregroundColor: palette(text);
|
qproperty-foregroundColor: palette(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudioItem,
|
||||||
FileItem {
|
FileItem {
|
||||||
qproperty-textColor: palette(text);
|
qproperty-textColor: palette(text);
|
||||||
qproperty-backgroundColor: palette(base);
|
qproperty-backgroundColor: palette(base);
|
||||||
qproperty-iconColor: palette(window);
|
qproperty-iconColor: palette(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioItem {
|
|
||||||
qproperty-textColor: palette(text);
|
|
||||||
qproperty-backgroundColor: palette(base);
|
|
||||||
qproperty-iconColor: palette(window);
|
|
||||||
}
|
|
||||||
|
|
||||||
RaisedButton {
|
RaisedButton {
|
||||||
qproperty-foregroundColor: palette(buttonText);
|
qproperty-foregroundColor: palette(buttonText);
|
||||||
}
|
}
|
||||||
|
@ -85,10 +85,11 @@ QListWidget {
|
||||||
background-color: palette(window);
|
background-color: palette(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
RoomInfoListItem {
|
RoomInfoListItem,
|
||||||
|
UserMentionsWidget {
|
||||||
qproperty-mentionedColor: palette(alternate-base);
|
qproperty-mentionedColor: palette(alternate-base);
|
||||||
qproperty-highlightedBackgroundColor: palette(highlight);
|
qproperty-highlightedBackgroundColor: palette(highlight);
|
||||||
qproperty-hoverBackgroundColor: palette(base);
|
qproperty-hoverBackgroundColor: palette(light);
|
||||||
qproperty-backgroundColor: palette(window);
|
qproperty-backgroundColor: palette(window);
|
||||||
|
|
||||||
qproperty-titleColor: palette(text);
|
qproperty-titleColor: palette(text);
|
||||||
|
@ -107,16 +108,19 @@ RoomInfoListItem {
|
||||||
qproperty-highlightedTimestampColor: palette(highlightedtext);
|
qproperty-highlightedTimestampColor: palette(highlightedtext);
|
||||||
qproperty-hoverTimestampColor: palette(highlightedtext);
|
qproperty-hoverTimestampColor: palette(highlightedtext);
|
||||||
|
|
||||||
qproperty-avatarBgColor: palette(base);
|
|
||||||
qproperty-avatarFgColor: palette(text);
|
|
||||||
|
|
||||||
qproperty-bubbleBgColor: palette(base);
|
qproperty-bubbleBgColor: palette(base);
|
||||||
qproperty-bubbleFgColor: palette(text);
|
qproperty-bubbleFgColor: palette(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RoomInfoListItem > Avatar {
|
||||||
|
qproperty-backgroundColor: palette(base);
|
||||||
|
qproperty-textColor: palette(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
CommunitiesListItem {
|
CommunitiesListItem {
|
||||||
qproperty-highlightedBackgroundColor: palette(highlight);
|
qproperty-highlightedBackgroundColor: palette(highlight);
|
||||||
qproperty-hoverBackgroundColor: palette(base);
|
qproperty-hoverBackgroundColor: palette(light);
|
||||||
qproperty-backgroundColor: palette(window);
|
qproperty-backgroundColor: palette(window);
|
||||||
|
|
||||||
qproperty-avatarBgColor: palette(base);
|
qproperty-avatarBgColor: palette(base);
|
||||||
|
@ -131,6 +135,30 @@ LoadingIndicator {
|
||||||
qproperty-color: palette(light);
|
qproperty-color: palette(light);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emoji--Panel,
|
||||||
|
emoji--Panel > * {
|
||||||
|
background-color: palette(base);
|
||||||
|
color: palette(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
emoji--Panel QWidget { border: none; }
|
||||||
|
emoji--Panel QScrollBar:vertical { width: 0px; margin: 0px; }
|
||||||
|
emoji--Panel QScrollBar::handle:vertical { min-height: 30px; }
|
||||||
|
|
||||||
|
emoji--Category {
|
||||||
|
qproperty-hoverBackgroundColor: palette(highlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
emoji--Category,
|
||||||
|
emoji--Category > * {
|
||||||
|
background-color: palette(window);
|
||||||
|
color: palette(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
emoji--Category QLabel {
|
||||||
|
margin: 20px 0 20px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
FloatingButton {
|
FloatingButton {
|
||||||
qproperty-backgroundColor: palette(base);
|
qproperty-backgroundColor: palette(base);
|
||||||
qproperty-foregroundColor: palette(text);
|
qproperty-foregroundColor: palette(text);
|
||||||
|
@ -141,13 +169,11 @@ SnackBar {
|
||||||
qproperty-bgColor: palette(base);
|
qproperty-bgColor: palette(base);
|
||||||
}
|
}
|
||||||
|
|
||||||
MemberItem {
|
|
||||||
background-color: palette(window);
|
|
||||||
}
|
|
||||||
|
|
||||||
Toggle {
|
Toggle {
|
||||||
qproperty-activeColor: palette(highlight);
|
qproperty-activeColor: palette(highlight);
|
||||||
qproperty-disabledColor: palette(dark);
|
qproperty-disabledColor: palette(dark);
|
||||||
qproperty-inactiveColor: palette(mid);
|
qproperty-inactiveColor: palette(mid);
|
||||||
qproperty-trackColor: palette(base);
|
qproperty-trackColor: palette(base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSplitter::handle { image: none; }
|
||||||
|
|
|
@ -1,31 +1,19 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import json
|
import re
|
||||||
|
|
||||||
from jinja2 import Template
|
from jinja2 import Template
|
||||||
|
|
||||||
|
|
||||||
class Emoji(object):
|
class Emoji(object):
|
||||||
def __init__(self, code, shortname, category, order):
|
def __init__(self, code, shortname):
|
||||||
self.code = ''.join(list(map(code_to_bytes, code.split('-'))))
|
self.code = repr(code.encode('utf-8'))[1:].strip("'")
|
||||||
self.shortname = shortname
|
self.shortname = shortname
|
||||||
self.category = category
|
|
||||||
self.order = int(order)
|
|
||||||
|
|
||||||
|
|
||||||
def code_to_bytes(codepoint):
|
|
||||||
'''
|
|
||||||
Convert hex unicode codepoint to hex byte array.
|
|
||||||
'''
|
|
||||||
bytes = chr(int(codepoint, 16)).encode('utf-8')
|
|
||||||
|
|
||||||
return str(bytes)[1:].strip("'")
|
|
||||||
|
|
||||||
|
|
||||||
def generate_code(emojis, category):
|
def generate_code(emojis, category):
|
||||||
tmpl = Template('''
|
tmpl = Template('''
|
||||||
const QList<Emoji> EmojiProvider::{{ category }} = {
|
const std::vector<Emoji> emoji::Provider::{{ category }} = {
|
||||||
{%- for e in emoji %}
|
{%- for e in emoji %}
|
||||||
Emoji{QString::fromUtf8("{{ e.code }}"), "{{ e.shortname }}"},
|
Emoji{QString::fromUtf8("{{ e.code }}"), "{{ e.shortname }}"},
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
|
@ -38,44 +26,56 @@ const QList<Emoji> EmojiProvider::{{ category }} = {
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if len(sys.argv) < 2:
|
if len(sys.argv) < 2:
|
||||||
print('usage: emoji_codegen.py /path/to/emoji.json')
|
print('usage: emoji_codegen.py /path/to/emoji-test.txt')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
filename = sys.argv[1]
|
filename = sys.argv[1]
|
||||||
data = {}
|
|
||||||
|
|
||||||
with open(filename, 'r') as filename:
|
people = []
|
||||||
data = json.loads(filename.read())
|
nature = []
|
||||||
|
food = []
|
||||||
|
activity = []
|
||||||
|
travel = []
|
||||||
|
objects = []
|
||||||
|
symbols = []
|
||||||
|
flags = []
|
||||||
|
|
||||||
emojis = []
|
categories = {
|
||||||
|
'Smileys & Emotion': people,
|
||||||
|
'People & Body': people,
|
||||||
|
'Animals & Nature': nature,
|
||||||
|
'Food & Drink': food,
|
||||||
|
'Travel & Places': travel,
|
||||||
|
'Activities': activity,
|
||||||
|
'Objects': objects,
|
||||||
|
'Symbols': symbols,
|
||||||
|
'Flags': flags
|
||||||
|
}
|
||||||
|
|
||||||
for emoji_name in data:
|
current_category = ''
|
||||||
tmp = data[emoji_name]
|
for line in open(filename, 'r'):
|
||||||
|
if line.startswith('# group:'):
|
||||||
|
current_category = line.split(':', 1)[1].strip()
|
||||||
|
|
||||||
l = len(tmp['unicode'].split('-'))
|
if not line or line.startswith('#'):
|
||||||
|
|
||||||
if l > 1 and tmp['category'] == 'people':
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
emojis.append(
|
segments = re.split(r'\s+[#;] ', line.strip())
|
||||||
Emoji(
|
if len(segments) != 3:
|
||||||
tmp['unicode'],
|
continue
|
||||||
tmp['shortname'],
|
|
||||||
tmp['category'],
|
|
||||||
tmp['emoji_order']
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
emojis.sort(key=lambda x: x.order)
|
code, qualification, charAndName = segments
|
||||||
|
|
||||||
people = list(filter(lambda x: x.category == "people", emojis))
|
# skip fully qualified versions of same unicode
|
||||||
nature = list(filter(lambda x: x.category == "nature", emojis))
|
if code.endswith('FE0F'):
|
||||||
food = list(filter(lambda x: x.category == "food", emojis))
|
continue
|
||||||
activity = list(filter(lambda x: x.category == "activity", emojis))
|
|
||||||
travel = list(filter(lambda x: x.category == "travel", emojis))
|
if qualification == 'component':
|
||||||
objects = list(filter(lambda x: x.category == "objects", emojis))
|
continue
|
||||||
symbols = list(filter(lambda x: x.category == "symbols", emojis))
|
|
||||||
flags = list(filter(lambda x: x.category == "flags", emojis))
|
char, name = re.match(r'^(\S+) E\d+\.\d+ (.*)$', charAndName).groups()
|
||||||
|
|
||||||
|
categories[current_category].append(Emoji(char, name))
|
||||||
|
|
||||||
# Use xclip to pipe the output to clipboard.
|
# Use xclip to pipe the output to clipboard.
|
||||||
# e.g ./codegen.py emoji.json | xclip -sel clip
|
# e.g ./codegen.py emoji.json | xclip -sel clip
|
||||||
|
|
7
scripts/update_emoji.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# Updating emoji
|
||||||
|
|
||||||
|
1. Get the latest emoji-test.txt from here: https://unicode.org/Public/emoji/
|
||||||
|
2. Overwrite the existing resources/emoji-test.txt with the new one
|
||||||
|
3. Run `./scripts/emoji_codegen.py resources/emoji-test.txt` and replace the current tail of src/emoji/Provider.cpp with the new output
|
||||||
|
4. `make lint`
|
||||||
|
5. Compile and test
|
|
@ -16,30 +16,37 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
|
#include <QPixmapCache>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "AvatarProvider.h"
|
#include "AvatarProvider.h"
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
|
|
||||||
|
static QPixmapCache avatar_cache;
|
||||||
|
|
||||||
namespace AvatarProvider {
|
namespace AvatarProvider {
|
||||||
|
|
||||||
void
|
void
|
||||||
resolve(const QString &room_id, const QString &user_id, QObject *receiver, AvatarCallback callback)
|
resolve(const QString &avatarUrl, int size, QObject *receiver, AvatarCallback callback)
|
||||||
{
|
{
|
||||||
const auto key = QString("%1 %2").arg(room_id).arg(user_id);
|
const auto cacheKey = QString("%1_size_%2").arg(avatarUrl).arg(size);
|
||||||
const auto avatarUrl = Cache::avatarUrl(room_id, user_id);
|
|
||||||
|
|
||||||
if (!Cache::AvatarUrls.contains(key) || !cache::client())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (avatarUrl.isEmpty())
|
if (avatarUrl.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto data = cache::client()->image(avatarUrl);
|
QPixmap pixmap;
|
||||||
|
if (avatar_cache.find(cacheKey, &pixmap)) {
|
||||||
|
callback(pixmap);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto data = cache::image(cacheKey);
|
||||||
if (!data.isNull()) {
|
if (!data.isNull()) {
|
||||||
callback(QImage::fromData(data));
|
pixmap.loadFromData(data);
|
||||||
|
avatar_cache.insert(cacheKey, pixmap);
|
||||||
|
callback(pixmap);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,16 +54,22 @@ resolve(const QString &room_id, const QString &user_id, QObject *receiver, Avata
|
||||||
QObject::connect(proxy.get(),
|
QObject::connect(proxy.get(),
|
||||||
&AvatarProxy::avatarDownloaded,
|
&AvatarProxy::avatarDownloaded,
|
||||||
receiver,
|
receiver,
|
||||||
[callback](const QByteArray &data) { callback(QImage::fromData(data)); });
|
[callback, cacheKey](const QByteArray &data) {
|
||||||
|
QPixmap pm;
|
||||||
|
pm.loadFromData(data);
|
||||||
|
avatar_cache.insert(cacheKey, pm);
|
||||||
|
callback(pm);
|
||||||
|
});
|
||||||
|
|
||||||
mtx::http::ThumbOpts opts;
|
mtx::http::ThumbOpts opts;
|
||||||
opts.width = 256;
|
opts.width = size;
|
||||||
opts.height = 256;
|
opts.height = size;
|
||||||
opts.mxc_url = avatarUrl.toStdString();
|
opts.mxc_url = avatarUrl.toStdString();
|
||||||
|
|
||||||
http::client()->get_thumbnail(
|
http::client()->get_thumbnail(
|
||||||
opts,
|
opts,
|
||||||
[opts, proxy = std::move(proxy)](const std::string &res, mtx::http::RequestErr err) {
|
[opts, cacheKey, proxy = std::move(proxy)](const std::string &res,
|
||||||
|
mtx::http::RequestErr err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
nhlog::net()->warn("failed to download avatar: {} - ({} {})",
|
nhlog::net()->warn("failed to download avatar: {} - ({} {})",
|
||||||
opts.mxc_url,
|
opts.mxc_url,
|
||||||
|
@ -65,10 +78,21 @@ resolve(const QString &room_id, const QString &user_id, QObject *receiver, Avata
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cache::client()->saveImage(opts.mxc_url, res);
|
cache::saveImage(cacheKey.toStdString(), res);
|
||||||
|
|
||||||
auto data = QByteArray(res.data(), res.size());
|
emit proxy->avatarDownloaded(QByteArray(res.data(), res.size()));
|
||||||
emit proxy->avatarDownloaded(data);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
resolve(const QString &room_id,
|
||||||
|
const QString &user_id,
|
||||||
|
int size,
|
||||||
|
QObject *receiver,
|
||||||
|
AvatarCallback callback)
|
||||||
|
{
|
||||||
|
const auto avatarUrl = cache::avatarUrl(room_id, user_id);
|
||||||
|
|
||||||
|
resolve(avatarUrl, size, receiver, callback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QImage>
|
#include <QPixmap>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
class AvatarProxy : public QObject
|
class AvatarProxy : public QObject
|
||||||
|
@ -28,9 +28,15 @@ signals:
|
||||||
void avatarDownloaded(const QByteArray &data);
|
void avatarDownloaded(const QByteArray &data);
|
||||||
};
|
};
|
||||||
|
|
||||||
using AvatarCallback = std::function<void(QImage)>;
|
using AvatarCallback = std::function<void(QPixmap)>;
|
||||||
|
|
||||||
namespace AvatarProvider {
|
namespace AvatarProvider {
|
||||||
void
|
void
|
||||||
resolve(const QString &room_id, const QString &user_id, QObject *receiver, AvatarCallback cb);
|
resolve(const QString &avatarUrl, int size, QObject *receiver, AvatarCallback cb);
|
||||||
|
void
|
||||||
|
resolve(const QString &room_id,
|
||||||
|
const QString &user_id,
|
||||||
|
int size,
|
||||||
|
QObject *receiver,
|
||||||
|
AvatarCallback cb);
|
||||||
}
|
}
|
||||||
|
|
878
src/Cache.cpp
962
src/Cache.h
|
@ -17,716 +17,280 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <boost/optional.hpp>
|
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
|
#if __has_include(<lmdbxx/lmdb++.h>)
|
||||||
|
#include <lmdbxx/lmdb++.h>
|
||||||
|
#else
|
||||||
#include <lmdb++.h>
|
#include <lmdb++.h>
|
||||||
#include <mtx/events/join_rules.hpp>
|
#endif
|
||||||
|
|
||||||
#include <mtx/responses.hpp>
|
#include <mtx/responses.hpp>
|
||||||
#include <mtxclient/crypto/client.hpp>
|
|
||||||
#include <mutex>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
#include "Logging.h"
|
#include "CacheCryptoStructs.h"
|
||||||
|
#include "CacheStructs.h"
|
||||||
using mtx::events::state::JoinRule;
|
|
||||||
|
|
||||||
struct RoomMember
|
|
||||||
{
|
|
||||||
QString user_id;
|
|
||||||
QString display_name;
|
|
||||||
QImage avatar;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SearchResult
|
|
||||||
{
|
|
||||||
QString user_id;
|
|
||||||
QString display_name;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
|
||||||
numeric_key_comparison(const MDB_val *a, const MDB_val *b)
|
|
||||||
{
|
|
||||||
auto lhs = std::stoull(std::string((char *)a->mv_data, a->mv_size));
|
|
||||||
auto rhs = std::stoull(std::string((char *)b->mv_data, b->mv_size));
|
|
||||||
|
|
||||||
if (lhs < rhs)
|
|
||||||
return 1;
|
|
||||||
else if (lhs == rhs)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(SearchResult)
|
|
||||||
Q_DECLARE_METATYPE(QVector<SearchResult>)
|
|
||||||
Q_DECLARE_METATYPE(RoomMember)
|
|
||||||
Q_DECLARE_METATYPE(mtx::responses::Timeline)
|
|
||||||
|
|
||||||
//! Used to uniquely identify a list of read receipts.
|
|
||||||
struct ReadReceiptKey
|
|
||||||
{
|
|
||||||
std::string event_id;
|
|
||||||
std::string room_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void
|
|
||||||
to_json(json &j, const ReadReceiptKey &key)
|
|
||||||
{
|
|
||||||
j = json{{"event_id", key.event_id}, {"room_id", key.room_id}};
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
from_json(const json &j, ReadReceiptKey &key)
|
|
||||||
{
|
|
||||||
key.event_id = j.at("event_id").get<std::string>();
|
|
||||||
key.room_id = j.at("room_id").get<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DescInfo
|
|
||||||
{
|
|
||||||
QString event_id;
|
|
||||||
QString username;
|
|
||||||
QString userid;
|
|
||||||
QString body;
|
|
||||||
QString timestamp;
|
|
||||||
QDateTime datetime;
|
|
||||||
};
|
|
||||||
|
|
||||||
//! UI info associated with a room.
|
|
||||||
struct RoomInfo
|
|
||||||
{
|
|
||||||
//! The calculated name of the room.
|
|
||||||
std::string name;
|
|
||||||
//! The topic of the room.
|
|
||||||
std::string topic;
|
|
||||||
//! The calculated avatar url of the room.
|
|
||||||
std::string avatar_url;
|
|
||||||
//! Whether or not the room is an invite.
|
|
||||||
bool is_invite = false;
|
|
||||||
//! Total number of members in the room.
|
|
||||||
int16_t member_count = 0;
|
|
||||||
//! Who can access to the room.
|
|
||||||
JoinRule join_rule = JoinRule::Public;
|
|
||||||
bool guest_access = false;
|
|
||||||
//! Metadata describing the last message in the timeline.
|
|
||||||
DescInfo msgInfo;
|
|
||||||
//! The list of tags associated with this room
|
|
||||||
std::vector<std::string> tags;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void
|
|
||||||
to_json(json &j, const RoomInfo &info)
|
|
||||||
{
|
|
||||||
j["name"] = info.name;
|
|
||||||
j["topic"] = info.topic;
|
|
||||||
j["avatar_url"] = info.avatar_url;
|
|
||||||
j["is_invite"] = info.is_invite;
|
|
||||||
j["join_rule"] = info.join_rule;
|
|
||||||
j["guest_access"] = info.guest_access;
|
|
||||||
|
|
||||||
if (info.member_count != 0)
|
|
||||||
j["member_count"] = info.member_count;
|
|
||||||
|
|
||||||
if (info.tags.size() != 0)
|
|
||||||
j["tags"] = info.tags;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
from_json(const json &j, RoomInfo &info)
|
|
||||||
{
|
|
||||||
info.name = j.at("name");
|
|
||||||
info.topic = j.at("topic");
|
|
||||||
info.avatar_url = j.at("avatar_url");
|
|
||||||
info.is_invite = j.at("is_invite");
|
|
||||||
info.join_rule = j.at("join_rule");
|
|
||||||
info.guest_access = j.at("guest_access");
|
|
||||||
|
|
||||||
if (j.count("member_count"))
|
|
||||||
info.member_count = j.at("member_count");
|
|
||||||
|
|
||||||
if (j.count("tags"))
|
|
||||||
info.tags = j.at("tags").get<std::vector<std::string>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Basic information per member;
|
|
||||||
struct MemberInfo
|
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
std::string avatar_url;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void
|
|
||||||
to_json(json &j, const MemberInfo &info)
|
|
||||||
{
|
|
||||||
j["name"] = info.name;
|
|
||||||
j["avatar_url"] = info.avatar_url;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
from_json(const json &j, MemberInfo &info)
|
|
||||||
{
|
|
||||||
info.name = j.at("name");
|
|
||||||
info.avatar_url = j.at("avatar_url");
|
|
||||||
}
|
|
||||||
|
|
||||||
struct RoomSearchResult
|
|
||||||
{
|
|
||||||
std::string room_id;
|
|
||||||
RoomInfo info;
|
|
||||||
QImage img;
|
|
||||||
};
|
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(RoomSearchResult)
|
|
||||||
Q_DECLARE_METATYPE(RoomInfo)
|
|
||||||
|
|
||||||
// Extra information associated with an outbound megolm session.
|
|
||||||
struct OutboundGroupSessionData
|
|
||||||
{
|
|
||||||
std::string session_id;
|
|
||||||
std::string session_key;
|
|
||||||
uint64_t message_index = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void
|
|
||||||
to_json(nlohmann::json &obj, const OutboundGroupSessionData &msg)
|
|
||||||
{
|
|
||||||
obj["session_id"] = msg.session_id;
|
|
||||||
obj["session_key"] = msg.session_key;
|
|
||||||
obj["message_index"] = msg.message_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
from_json(const nlohmann::json &obj, OutboundGroupSessionData &msg)
|
|
||||||
{
|
|
||||||
msg.session_id = obj.at("session_id");
|
|
||||||
msg.session_key = obj.at("session_key");
|
|
||||||
msg.message_index = obj.at("message_index");
|
|
||||||
}
|
|
||||||
|
|
||||||
struct OutboundGroupSessionDataRef
|
|
||||||
{
|
|
||||||
OlmOutboundGroupSession *session;
|
|
||||||
OutboundGroupSessionData data;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DevicePublicKeys
|
|
||||||
{
|
|
||||||
std::string ed25519;
|
|
||||||
std::string curve25519;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void
|
|
||||||
to_json(nlohmann::json &obj, const DevicePublicKeys &msg)
|
|
||||||
{
|
|
||||||
obj["ed25519"] = msg.ed25519;
|
|
||||||
obj["curve25519"] = msg.curve25519;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
from_json(const nlohmann::json &obj, DevicePublicKeys &msg)
|
|
||||||
{
|
|
||||||
msg.ed25519 = obj.at("ed25519");
|
|
||||||
msg.curve25519 = obj.at("curve25519");
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Represents a unique megolm session identifier.
|
|
||||||
struct MegolmSessionIndex
|
|
||||||
{
|
|
||||||
//! The room in which this session exists.
|
|
||||||
std::string room_id;
|
|
||||||
//! The session_id of the megolm session.
|
|
||||||
std::string session_id;
|
|
||||||
//! The curve25519 public key of the sender.
|
|
||||||
std::string sender_key;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void
|
|
||||||
to_json(nlohmann::json &obj, const MegolmSessionIndex &msg)
|
|
||||||
{
|
|
||||||
obj["room_id"] = msg.room_id;
|
|
||||||
obj["session_id"] = msg.session_id;
|
|
||||||
obj["sender_key"] = msg.sender_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
from_json(const nlohmann::json &obj, MegolmSessionIndex &msg)
|
|
||||||
{
|
|
||||||
msg.room_id = obj.at("room_id");
|
|
||||||
msg.session_id = obj.at("session_id");
|
|
||||||
msg.sender_key = obj.at("sender_key");
|
|
||||||
}
|
|
||||||
|
|
||||||
struct OlmSessionStorage
|
|
||||||
{
|
|
||||||
// Megolm sessions
|
|
||||||
std::map<std::string, mtx::crypto::InboundGroupSessionPtr> group_inbound_sessions;
|
|
||||||
std::map<std::string, mtx::crypto::OutboundGroupSessionPtr> group_outbound_sessions;
|
|
||||||
std::map<std::string, OutboundGroupSessionData> group_outbound_session_data;
|
|
||||||
|
|
||||||
// Guards for accessing megolm sessions.
|
|
||||||
std::mutex group_outbound_mtx;
|
|
||||||
std::mutex group_inbound_mtx;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Cache : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
Cache(const QString &userId, QObject *parent = nullptr);
|
|
||||||
|
|
||||||
static QHash<QString, QString> DisplayNames;
|
|
||||||
static QHash<QString, QString> AvatarUrls;
|
|
||||||
static QHash<QString, QString> UserColors;
|
|
||||||
|
|
||||||
static std::string displayName(const std::string &room_id, const std::string &user_id);
|
|
||||||
static QString displayName(const QString &room_id, const QString &user_id);
|
|
||||||
static QString avatarUrl(const QString &room_id, const QString &user_id);
|
|
||||||
static QString userColor(const QString &user_id);
|
|
||||||
|
|
||||||
static void removeDisplayName(const QString &room_id, const QString &user_id);
|
|
||||||
static void removeAvatarUrl(const QString &room_id, const QString &user_id);
|
|
||||||
static void removeUserColor(const QString &user_id);
|
|
||||||
|
|
||||||
static void insertDisplayName(const QString &room_id,
|
|
||||||
const QString &user_id,
|
|
||||||
const QString &display_name);
|
|
||||||
static void insertAvatarUrl(const QString &room_id,
|
|
||||||
const QString &user_id,
|
|
||||||
const QString &avatar_url);
|
|
||||||
static void insertUserColor(const QString &user_id, const QString &color_name);
|
|
||||||
|
|
||||||
static void clearUserColors();
|
|
||||||
|
|
||||||
//! Load saved data for the display names & avatars.
|
|
||||||
void populateMembers();
|
|
||||||
std::vector<std::string> joinedRooms();
|
|
||||||
|
|
||||||
QMap<QString, RoomInfo> roomInfo(bool withInvites = true);
|
|
||||||
std::map<QString, bool> invites();
|
|
||||||
|
|
||||||
//! Calculate & return the name of the room.
|
|
||||||
QString getRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
|
|
||||||
//! Get room join rules
|
|
||||||
JoinRule getRoomJoinRule(lmdb::txn &txn, lmdb::dbi &statesdb);
|
|
||||||
bool getRoomGuestAccess(lmdb::txn &txn, lmdb::dbi &statesdb);
|
|
||||||
//! Retrieve the topic of the room if any.
|
|
||||||
QString getRoomTopic(lmdb::txn &txn, lmdb::dbi &statesdb);
|
|
||||||
//! Retrieve the room avatar's url if any.
|
|
||||||
QString getRoomAvatarUrl(lmdb::txn &txn,
|
|
||||||
lmdb::dbi &statesdb,
|
|
||||||
lmdb::dbi &membersdb,
|
|
||||||
const QString &room_id);
|
|
||||||
|
|
||||||
//! Retrieve member info from a room.
|
|
||||||
std::vector<RoomMember> getMembers(const std::string &room_id,
|
|
||||||
std::size_t startIndex = 0,
|
|
||||||
std::size_t len = 30);
|
|
||||||
|
|
||||||
void saveState(const mtx::responses::Sync &res);
|
|
||||||
bool isInitialized() const;
|
|
||||||
|
|
||||||
std::string nextBatchToken() const;
|
|
||||||
|
|
||||||
void deleteData();
|
|
||||||
|
|
||||||
void removeInvite(lmdb::txn &txn, const std::string &room_id);
|
|
||||||
void removeInvite(const std::string &room_id);
|
|
||||||
void removeRoom(lmdb::txn &txn, const std::string &roomid);
|
|
||||||
void removeRoom(const std::string &roomid);
|
|
||||||
void removeRoom(const QString &roomid) { removeRoom(roomid.toStdString()); };
|
|
||||||
void setup();
|
|
||||||
|
|
||||||
bool isFormatValid();
|
|
||||||
void setCurrentFormat();
|
|
||||||
|
|
||||||
std::map<QString, mtx::responses::Timeline> roomMessages();
|
|
||||||
|
|
||||||
//! Retrieve all the user ids from a room.
|
|
||||||
std::vector<std::string> roomMembers(const std::string &room_id);
|
|
||||||
|
|
||||||
//! Check if the given user has power leve greater than than
|
|
||||||
//! lowest power level of the given events.
|
|
||||||
bool hasEnoughPowerLevel(const std::vector<mtx::events::EventType> &eventTypes,
|
|
||||||
const std::string &room_id,
|
|
||||||
const std::string &user_id);
|
|
||||||
|
|
||||||
//! Retrieves the saved room avatar.
|
|
||||||
QImage getRoomAvatar(const QString &id);
|
|
||||||
QImage getRoomAvatar(const std::string &id);
|
|
||||||
|
|
||||||
//! Adds a user to the read list for the given event.
|
|
||||||
//!
|
|
||||||
//! There should be only one user id present in a receipt list per room.
|
|
||||||
//! The user id should be removed from any other lists.
|
|
||||||
using Receipts = std::map<std::string, std::map<std::string, uint64_t>>;
|
|
||||||
void updateReadReceipt(lmdb::txn &txn,
|
|
||||||
const std::string &room_id,
|
|
||||||
const Receipts &receipts);
|
|
||||||
|
|
||||||
//! Retrieve all the read receipts for the given event id and room.
|
|
||||||
//!
|
|
||||||
//! Returns a map of user ids and the time of the read receipt in milliseconds.
|
|
||||||
using UserReceipts = std::multimap<uint64_t, std::string, std::greater<uint64_t>>;
|
|
||||||
UserReceipts readReceipts(const QString &event_id, const QString &room_id);
|
|
||||||
|
|
||||||
//! Filter the events that have at least one read receipt.
|
|
||||||
std::vector<QString> filterReadEvents(const QString &room_id,
|
|
||||||
const std::vector<QString> &event_ids,
|
|
||||||
const std::string &excluded_user);
|
|
||||||
//! Add event for which we are expecting some read receipts.
|
|
||||||
void addPendingReceipt(const QString &room_id, const QString &event_id);
|
|
||||||
void removePendingReceipt(lmdb::txn &txn,
|
|
||||||
const std::string &room_id,
|
|
||||||
const std::string &event_id);
|
|
||||||
void notifyForReadReceipts(const std::string &room_id);
|
|
||||||
std::vector<QString> pendingReceiptsEvents(lmdb::txn &txn, const std::string &room_id);
|
|
||||||
|
|
||||||
QByteArray image(const QString &url) const;
|
|
||||||
QByteArray image(lmdb::txn &txn, const std::string &url) const;
|
|
||||||
QByteArray image(const std::string &url) const
|
|
||||||
{
|
|
||||||
return image(QString::fromStdString(url));
|
|
||||||
}
|
|
||||||
void saveImage(const std::string &url, const std::string &data);
|
|
||||||
void saveImage(const QString &url, const QByteArray &data);
|
|
||||||
|
|
||||||
RoomInfo singleRoomInfo(const std::string &room_id);
|
|
||||||
std::vector<std::string> roomsWithStateUpdates(const mtx::responses::Sync &res);
|
|
||||||
std::vector<std::string> roomsWithTagUpdates(const mtx::responses::Sync &res);
|
|
||||||
std::map<QString, RoomInfo> getRoomInfo(const std::vector<std::string> &rooms);
|
|
||||||
std::map<QString, RoomInfo> roomUpdates(const mtx::responses::Sync &sync)
|
|
||||||
{
|
|
||||||
return getRoomInfo(roomsWithStateUpdates(sync));
|
|
||||||
}
|
|
||||||
std::map<QString, RoomInfo> roomTagUpdates(const mtx::responses::Sync &sync)
|
|
||||||
{
|
|
||||||
return getRoomInfo(roomsWithTagUpdates(sync));
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Calculates which the read status of a room.
|
|
||||||
//! Whether all the events in the timeline have been read.
|
|
||||||
bool calculateRoomReadStatus(const std::string &room_id);
|
|
||||||
void calculateRoomReadStatus();
|
|
||||||
|
|
||||||
QVector<SearchResult> searchUsers(const std::string &room_id,
|
|
||||||
const std::string &query,
|
|
||||||
std::uint8_t max_items = 5);
|
|
||||||
std::vector<RoomSearchResult> searchRooms(const std::string &query,
|
|
||||||
std::uint8_t max_items = 5);
|
|
||||||
|
|
||||||
void markSentNotification(const std::string &event_id);
|
|
||||||
//! Removes an event from the sent notifications.
|
|
||||||
void removeReadNotification(const std::string &event_id);
|
|
||||||
//! Check if we have sent a desktop notification for the given event id.
|
|
||||||
bool isNotificationSent(const std::string &event_id);
|
|
||||||
|
|
||||||
//! Remove old unused data.
|
|
||||||
void deleteOldMessages();
|
|
||||||
void deleteOldData() noexcept;
|
|
||||||
//! Retrieve all saved room ids.
|
|
||||||
std::vector<std::string> getRoomIds(lmdb::txn &txn);
|
|
||||||
|
|
||||||
//! Mark a room that uses e2e encryption.
|
|
||||||
void setEncryptedRoom(lmdb::txn &txn, const std::string &room_id);
|
|
||||||
bool isRoomEncrypted(const std::string &room_id);
|
|
||||||
|
|
||||||
//! Save the public keys for a device.
|
|
||||||
void saveDeviceKeys(const std::string &device_id);
|
|
||||||
void getDeviceKeys(const std::string &device_id);
|
|
||||||
|
|
||||||
//! Save the device list for a user.
|
|
||||||
void setDeviceList(const std::string &user_id, const std::vector<std::string> &devices);
|
|
||||||
std::vector<std::string> getDeviceList(const std::string &user_id);
|
|
||||||
|
|
||||||
//! Check if a user is a member of the room.
|
|
||||||
bool isRoomMember(const std::string &user_id, const std::string &room_id);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Outbound Megolm Sessions
|
|
||||||
//
|
|
||||||
void saveOutboundMegolmSession(const std::string &room_id,
|
|
||||||
const OutboundGroupSessionData &data,
|
|
||||||
mtx::crypto::OutboundGroupSessionPtr session);
|
|
||||||
OutboundGroupSessionDataRef getOutboundMegolmSession(const std::string &room_id);
|
|
||||||
bool outboundMegolmSessionExists(const std::string &room_id) noexcept;
|
|
||||||
void updateOutboundMegolmSession(const std::string &room_id, int message_index);
|
|
||||||
|
|
||||||
void importSessionKeys(const mtx::crypto::ExportedSessionKeys &keys);
|
|
||||||
mtx::crypto::ExportedSessionKeys exportSessionKeys();
|
|
||||||
|
|
||||||
//
|
|
||||||
// Inbound Megolm Sessions
|
|
||||||
//
|
|
||||||
void saveInboundMegolmSession(const MegolmSessionIndex &index,
|
|
||||||
mtx::crypto::InboundGroupSessionPtr session);
|
|
||||||
OlmInboundGroupSession *getInboundMegolmSession(const MegolmSessionIndex &index);
|
|
||||||
bool inboundMegolmSessionExists(const MegolmSessionIndex &index);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Olm Sessions
|
|
||||||
//
|
|
||||||
void saveOlmSession(const std::string &curve25519, mtx::crypto::OlmSessionPtr session);
|
|
||||||
std::vector<std::string> getOlmSessions(const std::string &curve25519);
|
|
||||||
boost::optional<mtx::crypto::OlmSessionPtr> getOlmSession(const std::string &curve25519,
|
|
||||||
const std::string &session_id);
|
|
||||||
|
|
||||||
void saveOlmAccount(const std::string &pickled);
|
|
||||||
std::string restoreOlmAccount();
|
|
||||||
|
|
||||||
void restoreSessions();
|
|
||||||
|
|
||||||
OlmSessionStorage session_storage;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void newReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
|
|
||||||
void roomReadStatus(const std::map<QString, bool> &status);
|
|
||||||
|
|
||||||
private:
|
|
||||||
//! Save an invited room.
|
|
||||||
void saveInvite(lmdb::txn &txn,
|
|
||||||
lmdb::dbi &statesdb,
|
|
||||||
lmdb::dbi &membersdb,
|
|
||||||
const mtx::responses::InvitedRoom &room);
|
|
||||||
|
|
||||||
QString getInviteRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
|
|
||||||
QString getInviteRoomTopic(lmdb::txn &txn, lmdb::dbi &statesdb);
|
|
||||||
QString getInviteRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
|
|
||||||
|
|
||||||
DescInfo getLastMessageInfo(lmdb::txn &txn, const std::string &room_id);
|
|
||||||
void saveTimelineMessages(lmdb::txn &txn,
|
|
||||||
const std::string &room_id,
|
|
||||||
const mtx::responses::Timeline &res);
|
|
||||||
|
|
||||||
mtx::responses::Timeline getTimelineMessages(lmdb::txn &txn, const std::string &room_id);
|
|
||||||
|
|
||||||
//! Remove a room from the cache.
|
|
||||||
// void removeLeftRoom(lmdb::txn &txn, const std::string &room_id);
|
|
||||||
template<class T>
|
|
||||||
void saveStateEvents(lmdb::txn &txn,
|
|
||||||
const lmdb::dbi &statesdb,
|
|
||||||
const lmdb::dbi &membersdb,
|
|
||||||
const std::string &room_id,
|
|
||||||
const std::vector<T> &events)
|
|
||||||
{
|
|
||||||
for (const auto &e : events)
|
|
||||||
saveStateEvent(txn, statesdb, membersdb, room_id, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
void saveStateEvent(lmdb::txn &txn,
|
|
||||||
const lmdb::dbi &statesdb,
|
|
||||||
const lmdb::dbi &membersdb,
|
|
||||||
const std::string &room_id,
|
|
||||||
const T &event)
|
|
||||||
{
|
|
||||||
using namespace mtx::events;
|
|
||||||
using namespace mtx::events::state;
|
|
||||||
|
|
||||||
if (boost::get<StateEvent<Member>>(&event) != nullptr) {
|
|
||||||
const auto e = boost::get<StateEvent<Member>>(event);
|
|
||||||
|
|
||||||
switch (e.content.membership) {
|
|
||||||
//
|
|
||||||
// We only keep users with invite or join membership.
|
|
||||||
//
|
|
||||||
case Membership::Invite:
|
|
||||||
case Membership::Join: {
|
|
||||||
auto display_name = e.content.display_name.empty()
|
|
||||||
? e.state_key
|
|
||||||
: e.content.display_name;
|
|
||||||
|
|
||||||
// Lightweight representation of a member.
|
|
||||||
MemberInfo tmp{display_name, e.content.avatar_url};
|
|
||||||
|
|
||||||
lmdb::dbi_put(txn,
|
|
||||||
membersdb,
|
|
||||||
lmdb::val(e.state_key),
|
|
||||||
lmdb::val(json(tmp).dump()));
|
|
||||||
|
|
||||||
insertDisplayName(QString::fromStdString(room_id),
|
|
||||||
QString::fromStdString(e.state_key),
|
|
||||||
QString::fromStdString(display_name));
|
|
||||||
|
|
||||||
insertAvatarUrl(QString::fromStdString(room_id),
|
|
||||||
QString::fromStdString(e.state_key),
|
|
||||||
QString::fromStdString(e.content.avatar_url));
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
lmdb::dbi_del(
|
|
||||||
txn, membersdb, lmdb::val(e.state_key), lmdb::val(""));
|
|
||||||
|
|
||||||
removeDisplayName(QString::fromStdString(room_id),
|
|
||||||
QString::fromStdString(e.state_key));
|
|
||||||
removeAvatarUrl(QString::fromStdString(room_id),
|
|
||||||
QString::fromStdString(e.state_key));
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
} else if (boost::get<StateEvent<Encryption>>(&event) != nullptr) {
|
|
||||||
setEncryptedRoom(txn, room_id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isStateEvent(event))
|
|
||||||
return;
|
|
||||||
|
|
||||||
boost::apply_visitor(
|
|
||||||
[&txn, &statesdb](auto e) {
|
|
||||||
lmdb::dbi_put(
|
|
||||||
txn, statesdb, lmdb::val(to_string(e.type)), lmdb::val(json(e).dump()));
|
|
||||||
},
|
|
||||||
event);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
bool isStateEvent(const T &e)
|
|
||||||
{
|
|
||||||
using namespace mtx::events;
|
|
||||||
using namespace mtx::events::state;
|
|
||||||
|
|
||||||
return boost::get<StateEvent<Aliases>>(&e) != nullptr ||
|
|
||||||
boost::get<StateEvent<state::Avatar>>(&e) != nullptr ||
|
|
||||||
boost::get<StateEvent<CanonicalAlias>>(&e) != nullptr ||
|
|
||||||
boost::get<StateEvent<Create>>(&e) != nullptr ||
|
|
||||||
boost::get<StateEvent<GuestAccess>>(&e) != nullptr ||
|
|
||||||
boost::get<StateEvent<HistoryVisibility>>(&e) != nullptr ||
|
|
||||||
boost::get<StateEvent<JoinRules>>(&e) != nullptr ||
|
|
||||||
boost::get<StateEvent<Name>>(&e) != nullptr ||
|
|
||||||
boost::get<StateEvent<Member>>(&e) != nullptr ||
|
|
||||||
boost::get<StateEvent<PowerLevels>>(&e) != nullptr ||
|
|
||||||
boost::get<StateEvent<Topic>>(&e) != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
bool containsStateUpdates(const T &e)
|
|
||||||
{
|
|
||||||
using namespace mtx::events;
|
|
||||||
using namespace mtx::events::state;
|
|
||||||
|
|
||||||
return boost::get<StateEvent<state::Avatar>>(&e) != nullptr ||
|
|
||||||
boost::get<StateEvent<CanonicalAlias>>(&e) != nullptr ||
|
|
||||||
boost::get<StateEvent<Name>>(&e) != nullptr ||
|
|
||||||
boost::get<StateEvent<Member>>(&e) != nullptr ||
|
|
||||||
boost::get<StateEvent<Topic>>(&e) != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool containsStateUpdates(const mtx::events::collections::StrippedEvents &e)
|
|
||||||
{
|
|
||||||
using namespace mtx::events;
|
|
||||||
using namespace mtx::events::state;
|
|
||||||
|
|
||||||
return boost::get<StrippedEvent<state::Avatar>>(&e) != nullptr ||
|
|
||||||
boost::get<StrippedEvent<CanonicalAlias>>(&e) != nullptr ||
|
|
||||||
boost::get<StrippedEvent<Name>>(&e) != nullptr ||
|
|
||||||
boost::get<StrippedEvent<Member>>(&e) != nullptr ||
|
|
||||||
boost::get<StrippedEvent<Topic>>(&e) != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void saveInvites(lmdb::txn &txn,
|
|
||||||
const std::map<std::string, mtx::responses::InvitedRoom> &rooms);
|
|
||||||
|
|
||||||
//! Sends signals for the rooms that are removed.
|
|
||||||
void removeLeftRooms(lmdb::txn &txn,
|
|
||||||
const std::map<std::string, mtx::responses::LeftRoom> &rooms)
|
|
||||||
{
|
|
||||||
for (const auto &room : rooms) {
|
|
||||||
removeRoom(txn, room.first);
|
|
||||||
|
|
||||||
// Clean up leftover invites.
|
|
||||||
removeInvite(txn, room.first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lmdb::dbi getPendingReceiptsDb(lmdb::txn &txn)
|
|
||||||
{
|
|
||||||
return lmdb::dbi::open(txn, "pending_receipts", MDB_CREATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
lmdb::dbi getMessagesDb(lmdb::txn &txn, const std::string &room_id)
|
|
||||||
{
|
|
||||||
auto db =
|
|
||||||
lmdb::dbi::open(txn, std::string(room_id + "/messages").c_str(), MDB_CREATE);
|
|
||||||
lmdb::dbi_set_compare(txn, db, numeric_key_comparison);
|
|
||||||
|
|
||||||
return db;
|
|
||||||
}
|
|
||||||
|
|
||||||
lmdb::dbi getInviteStatesDb(lmdb::txn &txn, const std::string &room_id)
|
|
||||||
{
|
|
||||||
return lmdb::dbi::open(
|
|
||||||
txn, std::string(room_id + "/invite_state").c_str(), MDB_CREATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
lmdb::dbi getInviteMembersDb(lmdb::txn &txn, const std::string &room_id)
|
|
||||||
{
|
|
||||||
return lmdb::dbi::open(
|
|
||||||
txn, std::string(room_id + "/invite_members").c_str(), MDB_CREATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
lmdb::dbi getStatesDb(lmdb::txn &txn, const std::string &room_id)
|
|
||||||
{
|
|
||||||
return lmdb::dbi::open(txn, std::string(room_id + "/state").c_str(), MDB_CREATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
lmdb::dbi getMembersDb(lmdb::txn &txn, const std::string &room_id)
|
|
||||||
{
|
|
||||||
return lmdb::dbi::open(txn, std::string(room_id + "/members").c_str(), MDB_CREATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Retrieves or creates the database that stores the open OLM sessions between our device
|
|
||||||
//! and the given curve25519 key which represents another device.
|
|
||||||
//!
|
|
||||||
//! Each entry is a map from the session_id to the pickled representation of the session.
|
|
||||||
lmdb::dbi getOlmSessionsDb(lmdb::txn &txn, const std::string &curve25519_key)
|
|
||||||
{
|
|
||||||
return lmdb::dbi::open(
|
|
||||||
txn, std::string("olm_sessions/" + curve25519_key).c_str(), MDB_CREATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString getDisplayName(const mtx::events::StateEvent<mtx::events::state::Member> &event)
|
|
||||||
{
|
|
||||||
if (!event.content.display_name.empty())
|
|
||||||
return QString::fromStdString(event.content.display_name);
|
|
||||||
|
|
||||||
return QString::fromStdString(event.state_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setNextBatchToken(lmdb::txn &txn, const std::string &token);
|
|
||||||
void setNextBatchToken(lmdb::txn &txn, const QString &token);
|
|
||||||
|
|
||||||
lmdb::env env_;
|
|
||||||
lmdb::dbi syncStateDb_;
|
|
||||||
lmdb::dbi roomsDb_;
|
|
||||||
lmdb::dbi invitesDb_;
|
|
||||||
lmdb::dbi mediaDb_;
|
|
||||||
lmdb::dbi readReceiptsDb_;
|
|
||||||
lmdb::dbi notificationsDb_;
|
|
||||||
|
|
||||||
lmdb::dbi devicesDb_;
|
|
||||||
lmdb::dbi deviceKeysDb_;
|
|
||||||
|
|
||||||
lmdb::dbi inboundMegolmSessionDb_;
|
|
||||||
lmdb::dbi outboundMegolmSessionDb_;
|
|
||||||
|
|
||||||
QString localUserId_;
|
|
||||||
QString cacheDirectory_;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace cache {
|
namespace cache {
|
||||||
void
|
void
|
||||||
init(const QString &user_id);
|
init(const QString &user_id);
|
||||||
|
|
||||||
Cache *
|
std::string
|
||||||
client();
|
displayName(const std::string &room_id, const std::string &user_id);
|
||||||
|
QString
|
||||||
|
displayName(const QString &room_id, const QString &user_id);
|
||||||
|
QString
|
||||||
|
avatarUrl(const QString &room_id, const QString &user_id);
|
||||||
|
|
||||||
|
void
|
||||||
|
removeDisplayName(const QString &room_id, const QString &user_id);
|
||||||
|
void
|
||||||
|
removeAvatarUrl(const QString &room_id, const QString &user_id);
|
||||||
|
|
||||||
|
void
|
||||||
|
insertDisplayName(const QString &room_id, const QString &user_id, const QString &display_name);
|
||||||
|
void
|
||||||
|
insertAvatarUrl(const QString &room_id, const QString &user_id, const QString &avatar_url);
|
||||||
|
|
||||||
|
//! Load saved data for the display names & avatars.
|
||||||
|
void
|
||||||
|
populateMembers();
|
||||||
|
std::vector<std::string>
|
||||||
|
joinedRooms();
|
||||||
|
|
||||||
|
QMap<QString, RoomInfo>
|
||||||
|
roomInfo(bool withInvites = true);
|
||||||
|
std::map<QString, bool>
|
||||||
|
invites();
|
||||||
|
|
||||||
|
//! Calculate & return the name of the room.
|
||||||
|
QString
|
||||||
|
getRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
|
||||||
|
//! Get room join rules
|
||||||
|
mtx::events::state::JoinRule
|
||||||
|
getRoomJoinRule(lmdb::txn &txn, lmdb::dbi &statesdb);
|
||||||
|
bool
|
||||||
|
getRoomGuestAccess(lmdb::txn &txn, lmdb::dbi &statesdb);
|
||||||
|
//! Retrieve the topic of the room if any.
|
||||||
|
QString
|
||||||
|
getRoomTopic(lmdb::txn &txn, lmdb::dbi &statesdb);
|
||||||
|
//! Retrieve the room avatar's url if any.
|
||||||
|
QString
|
||||||
|
getRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb, const QString &room_id);
|
||||||
|
//! Retrieve the version of the room if any.
|
||||||
|
QString
|
||||||
|
getRoomVersion(lmdb::txn &txn, lmdb::dbi &statesdb);
|
||||||
|
|
||||||
|
//! Retrieve member info from a room.
|
||||||
|
std::vector<RoomMember>
|
||||||
|
getMembers(const std::string &room_id, std::size_t startIndex = 0, std::size_t len = 30);
|
||||||
|
|
||||||
|
void
|
||||||
|
saveState(const mtx::responses::Sync &res);
|
||||||
|
bool
|
||||||
|
isInitialized();
|
||||||
|
|
||||||
|
std::string
|
||||||
|
nextBatchToken();
|
||||||
|
|
||||||
|
void
|
||||||
|
deleteData();
|
||||||
|
|
||||||
|
void
|
||||||
|
removeInvite(lmdb::txn &txn, const std::string &room_id);
|
||||||
|
void
|
||||||
|
removeInvite(const std::string &room_id);
|
||||||
|
void
|
||||||
|
removeRoom(lmdb::txn &txn, const std::string &roomid);
|
||||||
|
void
|
||||||
|
removeRoom(const std::string &roomid);
|
||||||
|
void
|
||||||
|
removeRoom(const QString &roomid);
|
||||||
|
void
|
||||||
|
setup();
|
||||||
|
|
||||||
|
bool
|
||||||
|
isFormatValid();
|
||||||
|
void
|
||||||
|
setCurrentFormat();
|
||||||
|
|
||||||
|
std::map<QString, mtx::responses::Timeline>
|
||||||
|
roomMessages();
|
||||||
|
|
||||||
|
QMap<QString, mtx::responses::Notifications>
|
||||||
|
getTimelineMentions();
|
||||||
|
|
||||||
|
//! Retrieve all the user ids from a room.
|
||||||
|
std::vector<std::string>
|
||||||
|
roomMembers(const std::string &room_id);
|
||||||
|
|
||||||
|
//! Check if the given user has power leve greater than than
|
||||||
|
//! lowest power level of the given events.
|
||||||
|
bool
|
||||||
|
hasEnoughPowerLevel(const std::vector<mtx::events::EventType> &eventTypes,
|
||||||
|
const std::string &room_id,
|
||||||
|
const std::string &user_id);
|
||||||
|
|
||||||
|
//! Retrieves the saved room avatar.
|
||||||
|
QImage
|
||||||
|
getRoomAvatar(const QString &id);
|
||||||
|
QImage
|
||||||
|
getRoomAvatar(const std::string &id);
|
||||||
|
|
||||||
|
//! Adds a user to the read list for the given event.
|
||||||
|
//!
|
||||||
|
//! There should be only one user id present in a receipt list per room.
|
||||||
|
//! The user id should be removed from any other lists.
|
||||||
|
using Receipts = std::map<std::string, std::map<std::string, uint64_t>>;
|
||||||
|
void
|
||||||
|
updateReadReceipt(lmdb::txn &txn, const std::string &room_id, const Receipts &receipts);
|
||||||
|
|
||||||
|
//! Retrieve all the read receipts for the given event id and room.
|
||||||
|
//!
|
||||||
|
//! Returns a map of user ids and the time of the read receipt in milliseconds.
|
||||||
|
using UserReceipts = std::multimap<uint64_t, std::string, std::greater<uint64_t>>;
|
||||||
|
UserReceipts
|
||||||
|
readReceipts(const QString &event_id, const QString &room_id);
|
||||||
|
|
||||||
|
//! Filter the events that have at least one read receipt.
|
||||||
|
std::vector<QString>
|
||||||
|
filterReadEvents(const QString &room_id,
|
||||||
|
const std::vector<QString> &event_ids,
|
||||||
|
const std::string &excluded_user);
|
||||||
|
//! Add event for which we are expecting some read receipts.
|
||||||
|
void
|
||||||
|
addPendingReceipt(const QString &room_id, const QString &event_id);
|
||||||
|
void
|
||||||
|
removePendingReceipt(lmdb::txn &txn, const std::string &room_id, const std::string &event_id);
|
||||||
|
void
|
||||||
|
notifyForReadReceipts(const std::string &room_id);
|
||||||
|
std::vector<QString>
|
||||||
|
pendingReceiptsEvents(lmdb::txn &txn, const std::string &room_id);
|
||||||
|
|
||||||
|
QByteArray
|
||||||
|
image(const QString &url);
|
||||||
|
QByteArray
|
||||||
|
image(lmdb::txn &txn, const std::string &url);
|
||||||
|
inline QByteArray
|
||||||
|
image(const std::string &url)
|
||||||
|
{
|
||||||
|
return image(QString::fromStdString(url));
|
||||||
|
}
|
||||||
|
void
|
||||||
|
saveImage(const std::string &url, const std::string &data);
|
||||||
|
void
|
||||||
|
saveImage(const QString &url, const QByteArray &data);
|
||||||
|
|
||||||
|
RoomInfo
|
||||||
|
singleRoomInfo(const std::string &room_id);
|
||||||
|
std::vector<std::string>
|
||||||
|
roomsWithStateUpdates(const mtx::responses::Sync &res);
|
||||||
|
std::vector<std::string>
|
||||||
|
roomsWithTagUpdates(const mtx::responses::Sync &res);
|
||||||
|
std::map<QString, RoomInfo>
|
||||||
|
getRoomInfo(const std::vector<std::string> &rooms);
|
||||||
|
inline std::map<QString, RoomInfo>
|
||||||
|
roomUpdates(const mtx::responses::Sync &sync)
|
||||||
|
{
|
||||||
|
return getRoomInfo(roomsWithStateUpdates(sync));
|
||||||
|
}
|
||||||
|
inline std::map<QString, RoomInfo>
|
||||||
|
roomTagUpdates(const mtx::responses::Sync &sync)
|
||||||
|
{
|
||||||
|
return getRoomInfo(roomsWithTagUpdates(sync));
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Calculates which the read status of a room.
|
||||||
|
//! Whether all the events in the timeline have been read.
|
||||||
|
bool
|
||||||
|
calculateRoomReadStatus(const std::string &room_id);
|
||||||
|
void
|
||||||
|
calculateRoomReadStatus();
|
||||||
|
|
||||||
|
std::vector<SearchResult>
|
||||||
|
searchUsers(const std::string &room_id, const std::string &query, std::uint8_t max_items = 5);
|
||||||
|
std::vector<RoomSearchResult>
|
||||||
|
searchRooms(const std::string &query, std::uint8_t max_items = 5);
|
||||||
|
|
||||||
|
void
|
||||||
|
markSentNotification(const std::string &event_id);
|
||||||
|
//! Removes an event from the sent notifications.
|
||||||
|
void
|
||||||
|
removeReadNotification(const std::string &event_id);
|
||||||
|
//! Check if we have sent a desktop notification for the given event id.
|
||||||
|
bool
|
||||||
|
isNotificationSent(const std::string &event_id);
|
||||||
|
|
||||||
|
//! Add all notifications containing a user mention to the db.
|
||||||
|
void
|
||||||
|
saveTimelineMentions(const mtx::responses::Notifications &res);
|
||||||
|
|
||||||
|
//! Remove old unused data.
|
||||||
|
void
|
||||||
|
deleteOldMessages();
|
||||||
|
void
|
||||||
|
deleteOldData() noexcept;
|
||||||
|
//! Retrieve all saved room ids.
|
||||||
|
std::vector<std::string>
|
||||||
|
getRoomIds(lmdb::txn &txn);
|
||||||
|
|
||||||
|
//! Mark a room that uses e2e encryption.
|
||||||
|
void
|
||||||
|
setEncryptedRoom(lmdb::txn &txn, const std::string &room_id);
|
||||||
|
bool
|
||||||
|
isRoomEncrypted(const std::string &room_id);
|
||||||
|
|
||||||
|
//! Check if a user is a member of the room.
|
||||||
|
bool
|
||||||
|
isRoomMember(const std::string &user_id, const std::string &room_id);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Outbound Megolm Sessions
|
||||||
|
//
|
||||||
|
void
|
||||||
|
saveOutboundMegolmSession(const std::string &room_id,
|
||||||
|
const OutboundGroupSessionData &data,
|
||||||
|
mtx::crypto::OutboundGroupSessionPtr session);
|
||||||
|
OutboundGroupSessionDataRef
|
||||||
|
getOutboundMegolmSession(const std::string &room_id);
|
||||||
|
bool
|
||||||
|
outboundMegolmSessionExists(const std::string &room_id) noexcept;
|
||||||
|
void
|
||||||
|
updateOutboundMegolmSession(const std::string &room_id, int message_index);
|
||||||
|
|
||||||
|
void
|
||||||
|
importSessionKeys(const mtx::crypto::ExportedSessionKeys &keys);
|
||||||
|
mtx::crypto::ExportedSessionKeys
|
||||||
|
exportSessionKeys();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Inbound Megolm Sessions
|
||||||
|
//
|
||||||
|
void
|
||||||
|
saveInboundMegolmSession(const MegolmSessionIndex &index,
|
||||||
|
mtx::crypto::InboundGroupSessionPtr session);
|
||||||
|
OlmInboundGroupSession *
|
||||||
|
getInboundMegolmSession(const MegolmSessionIndex &index);
|
||||||
|
bool
|
||||||
|
inboundMegolmSessionExists(const MegolmSessionIndex &index);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Olm Sessions
|
||||||
|
//
|
||||||
|
void
|
||||||
|
saveOlmSession(const std::string &curve25519, mtx::crypto::OlmSessionPtr session);
|
||||||
|
std::vector<std::string>
|
||||||
|
getOlmSessions(const std::string &curve25519);
|
||||||
|
std::optional<mtx::crypto::OlmSessionPtr>
|
||||||
|
getOlmSession(const std::string &curve25519, const std::string &session_id);
|
||||||
|
|
||||||
|
void
|
||||||
|
saveOlmAccount(const std::string &pickled);
|
||||||
|
std::string
|
||||||
|
restoreOlmAccount();
|
||||||
|
|
||||||
|
void
|
||||||
|
restoreSessions();
|
||||||
}
|
}
|
||||||
|
|
67
src/CacheCryptoStructs.h
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
//#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include <mtx/responses.hpp>
|
||||||
|
#include <mtxclient/crypto/client.hpp>
|
||||||
|
|
||||||
|
// Extra information associated with an outbound megolm session.
|
||||||
|
struct OutboundGroupSessionData
|
||||||
|
{
|
||||||
|
std::string session_id;
|
||||||
|
std::string session_key;
|
||||||
|
uint64_t message_index = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
to_json(nlohmann::json &obj, const OutboundGroupSessionData &msg);
|
||||||
|
void
|
||||||
|
from_json(const nlohmann::json &obj, OutboundGroupSessionData &msg);
|
||||||
|
|
||||||
|
struct OutboundGroupSessionDataRef
|
||||||
|
{
|
||||||
|
OlmOutboundGroupSession *session;
|
||||||
|
OutboundGroupSessionData data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DevicePublicKeys
|
||||||
|
{
|
||||||
|
std::string ed25519;
|
||||||
|
std::string curve25519;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
to_json(nlohmann::json &obj, const DevicePublicKeys &msg);
|
||||||
|
void
|
||||||
|
from_json(const nlohmann::json &obj, DevicePublicKeys &msg);
|
||||||
|
|
||||||
|
//! Represents a unique megolm session identifier.
|
||||||
|
struct MegolmSessionIndex
|
||||||
|
{
|
||||||
|
//! The room in which this session exists.
|
||||||
|
std::string room_id;
|
||||||
|
//! The session_id of the megolm session.
|
||||||
|
std::string session_id;
|
||||||
|
//! The curve25519 public key of the sender.
|
||||||
|
std::string sender_key;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
to_json(nlohmann::json &obj, const MegolmSessionIndex &msg);
|
||||||
|
void
|
||||||
|
from_json(const nlohmann::json &obj, MegolmSessionIndex &msg);
|
||||||
|
|
||||||
|
struct OlmSessionStorage
|
||||||
|
{
|
||||||
|
// Megolm sessions
|
||||||
|
std::map<std::string, mtx::crypto::InboundGroupSessionPtr> group_inbound_sessions;
|
||||||
|
std::map<std::string, mtx::crypto::OutboundGroupSessionPtr> group_outbound_sessions;
|
||||||
|
std::map<std::string, OutboundGroupSessionData> group_outbound_session_data;
|
||||||
|
|
||||||
|
// Guards for accessing megolm sessions.
|
||||||
|
std::mutex group_outbound_mtx;
|
||||||
|
std::mutex group_inbound_mtx;
|
||||||
|
};
|