(broken) Merge remote-tracking branch 'upstream/master' into communities
This commit is contained in:
commit
2d592b1408
20
.ci/linux/deploy.sh
Executable file
20
.ci/linux/deploy.sh
Executable file
@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
mkdir -p appdir
|
||||
cp build/nheko appdir/
|
||||
cp resources/nheko.desktop appdir/
|
||||
cp resources/nheko*.png appdir/
|
||||
|
||||
wget -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage"
|
||||
chmod a+x linuxdeployqt*.AppImage
|
||||
|
||||
unset QTDIR
|
||||
unset QT_PLUGIN_PATH
|
||||
unset LD_LIBRARY_PATH
|
||||
|
||||
./linuxdeployqt*.AppImage ./appdir/*.desktop -bundle-non-qt-libs
|
||||
./linuxdeployqt*.AppImage ./appdir/*.desktop -appimage
|
||||
|
||||
chmod +x nheko-x86_64.AppImage
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
sudo add-apt-repository -y ppa:beineri/opt-qt58-trusty
|
||||
sudo add-apt-repository -y ppa:beineri/opt-qt592-trusty
|
||||
sudo add-apt-repository -y ppa:george-edison55/cmake-3.x
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -qq -y qt58base qt58tools cmake liblmdb-dev
|
||||
sudo apt-get install -qq -y qt59base qt59tools cmake liblmdb-dev
|
||||
|
11
.ci/macos/deploy.sh
Executable file
11
.ci/macos/deploy.sh
Executable file
@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
# Add Qt binaries to path
|
||||
PATH=/usr/local/opt/qt/bin/:${PATH}
|
||||
|
||||
sudo macdeployqt build/nheko.app -dmg
|
||||
user=$(id -nu)
|
||||
sudo chown ${user} build/nheko.dmg
|
||||
mv build/nheko.dmg .
|
@ -1,225 +0,0 @@
|
||||
############################################################################################
|
||||
# NSIS Installation Script created by NSIS Quick Setup Script Generator v1.09.18
|
||||
# Entirely Edited with NullSoft Scriptable Installation System
|
||||
# by Vlasis K. Barkas aka Red Wine red_wine@freemail.gr Sep 2006
|
||||
############################################################################################
|
||||
|
||||
!define APP_NAME "nheko"
|
||||
!define COMP_NAME "mujx"
|
||||
!define WEB_SITE "https://github.com/mujx/nheko"
|
||||
!define VERSION "0.1.0.0"
|
||||
!define COPYRIGHT "mujx <20> 2017"
|
||||
!define DESCRIPTION "Desktop client for the Matrix protocol"
|
||||
!define LICENSE_TXT "LICENSE.txt"
|
||||
!define INSTALLER_NAME "..\..\nheko_setup.exe"
|
||||
!define INPUT_DIR "..\..\NhekoRelease"
|
||||
!define MAIN_APP_EXE "nheko.exe"
|
||||
!define INSTALL_TYPE "SetShellVarContext all"
|
||||
!define REG_ROOT "HKLM"
|
||||
!define REG_APP_PATH "Software\Microsoft\Windows\CurrentVersion\App Paths\${MAIN_APP_EXE}"
|
||||
!define UNINSTALL_PATH "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}"
|
||||
|
||||
!define REG_START_MENU "Start Menu Folder"
|
||||
|
||||
var SM_Folder
|
||||
|
||||
######################################################################
|
||||
|
||||
VIProductVersion "${VERSION}"
|
||||
VIAddVersionKey "ProductName" "${APP_NAME}"
|
||||
VIAddVersionKey "CompanyName" "${COMP_NAME}"
|
||||
VIAddVersionKey "LegalCopyright" "${COPYRIGHT}"
|
||||
VIAddVersionKey "FileDescription" "${DESCRIPTION}"
|
||||
VIAddVersionKey "FileVersion" "${VERSION}"
|
||||
|
||||
######################################################################
|
||||
|
||||
SetCompressor ZLIB
|
||||
Name "${APP_NAME}"
|
||||
Caption "${APP_NAME}"
|
||||
OutFile "${INSTALLER_NAME}"
|
||||
BrandingText "${APP_NAME}"
|
||||
XPStyle on
|
||||
InstallDirRegKey "${REG_ROOT}" "${REG_APP_PATH}" ""
|
||||
InstallDir "$PROGRAMFILES\nheko"
|
||||
|
||||
######################################################################
|
||||
|
||||
!include "MUI.nsh"
|
||||
|
||||
!define MUI_ICON "..\..\resources\nheko.ico"
|
||||
!define MUI_HEADERIMAGE
|
||||
!define MUI_HEADERIMAGE_BITMAP "..\..\resources\nheko.bmp"
|
||||
!define MUI_HEADERIMAGE_RIGHT
|
||||
|
||||
!define MUI_ABORTWARNING
|
||||
!define MUI_UNABORTWARNING
|
||||
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
|
||||
!ifdef LICENSE_TXT
|
||||
!insertmacro MUI_PAGE_LICENSE "${LICENSE_TXT}"
|
||||
!endif
|
||||
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
|
||||
!ifdef REG_START_MENU
|
||||
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "nheko"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "${REG_ROOT}"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_KEY "${UNINSTALL_PATH}"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "${REG_START_MENU}"
|
||||
!insertmacro MUI_PAGE_STARTMENU Application $SM_Folder
|
||||
!endif
|
||||
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
|
||||
!define MUI_FINISHPAGE_RUN "$INSTDIR\${MAIN_APP_EXE}"
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
|
||||
!insertmacro MUI_UNPAGE_FINISH
|
||||
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
|
||||
######################################################################
|
||||
|
||||
Section -MainProgram
|
||||
${INSTALL_TYPE}
|
||||
SetOverwrite ifnewer
|
||||
SetOutPath "$INSTDIR"
|
||||
File /r "${INPUT_DIR}\*"
|
||||
SectionEnd
|
||||
|
||||
######################################################################
|
||||
|
||||
Section -Icons_Reg
|
||||
SetOutPath "$INSTDIR"
|
||||
WriteUninstaller "$INSTDIR\uninstall.exe"
|
||||
|
||||
!ifdef REG_START_MENU
|
||||
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
|
||||
CreateDirectory "$SMPROGRAMS\$SM_Folder"
|
||||
CreateShortCut "$SMPROGRAMS\$SM_Folder\${APP_NAME}.lnk" "$INSTDIR\${MAIN_APP_EXE}"
|
||||
CreateShortCut "$DESKTOP\${APP_NAME}.lnk" "$INSTDIR\${MAIN_APP_EXE}"
|
||||
CreateShortCut "$SMPROGRAMS\$SM_Folder\Uninstall ${APP_NAME}.lnk" "$INSTDIR\uninstall.exe"
|
||||
|
||||
!ifdef WEB_SITE
|
||||
WriteIniStr "$INSTDIR\${APP_NAME} website.url" "InternetShortcut" "URL" "${WEB_SITE}"
|
||||
CreateShortCut "$SMPROGRAMS\$SM_Folder\${APP_NAME} Website.lnk" "$INSTDIR\${APP_NAME} website.url"
|
||||
!endif
|
||||
!insertmacro MUI_STARTMENU_WRITE_END
|
||||
!endif
|
||||
|
||||
!ifndef REG_START_MENU
|
||||
CreateDirectory "$SMPROGRAMS\nheko"
|
||||
CreateShortCut "$SMPROGRAMS\nheko\${APP_NAME}.lnk" "$INSTDIR\${MAIN_APP_EXE}"
|
||||
CreateShortCut "$DESKTOP\${APP_NAME}.lnk" "$INSTDIR\${MAIN_APP_EXE}"
|
||||
CreateShortCut "$SMPROGRAMS\nheko\Uninstall ${APP_NAME}.lnk" "$INSTDIR\uninstall.exe"
|
||||
|
||||
!ifdef WEB_SITE
|
||||
WriteIniStr "$INSTDIR\${APP_NAME} website.url" "InternetShortcut" "URL" "${WEB_SITE}"
|
||||
CreateShortCut "$SMPROGRAMS\nheko\${APP_NAME} Website.lnk" "$INSTDIR\${APP_NAME} website.url"
|
||||
!endif
|
||||
!endif
|
||||
|
||||
WriteRegStr ${REG_ROOT} "${REG_APP_PATH}" "" "$INSTDIR\${MAIN_APP_EXE}"
|
||||
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "DisplayName" "${APP_NAME}"
|
||||
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "UninstallString" "$INSTDIR\uninstall.exe"
|
||||
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "DisplayIcon" "$INSTDIR\${MAIN_APP_EXE}"
|
||||
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "DisplayVersion" "${VERSION}"
|
||||
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "Publisher" "${COMP_NAME}"
|
||||
|
||||
!ifdef WEB_SITE
|
||||
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "URLInfoAbout" "${WEB_SITE}"
|
||||
!endif
|
||||
SectionEnd
|
||||
|
||||
######################################################################
|
||||
|
||||
Section Uninstall
|
||||
${INSTALL_TYPE}
|
||||
|
||||
########
|
||||
|
||||
!macro BadPathsCheck
|
||||
StrCpy $R0 $INSTDIR "" -2
|
||||
StrCmp $R0 ":\" bad
|
||||
StrCpy $R0 $INSTDIR "" -14
|
||||
StrCmp $R0 "\Program Files" bad
|
||||
StrCpy $R0 $INSTDIR "" -8
|
||||
StrCmp $R0 "\Windows" bad
|
||||
StrCpy $R0 $INSTDIR "" -6
|
||||
StrCmp $R0 "\WinNT" bad
|
||||
StrCpy $R0 $INSTDIR "" -9
|
||||
StrCmp $R0 "\system32" bad
|
||||
StrCpy $R0 $INSTDIR "" -8
|
||||
StrCmp $R0 "\Desktop" bad
|
||||
StrCpy $R0 $INSTDIR "" -23
|
||||
StrCmp $R0 "\Documents and Settings" bad
|
||||
StrCpy $R0 $INSTDIR "" -13
|
||||
StrCmp $R0 "\My Documents" bad done
|
||||
bad:
|
||||
MessageBox MB_OK|MB_ICONSTOP "Install path invalid!"
|
||||
Abort
|
||||
done:
|
||||
!macroend
|
||||
|
||||
StrCmp $INSTDIR "" 0 +2
|
||||
StrCpy $INSTDIR $EXEDIR
|
||||
|
||||
# Check that the uninstall isn't dangerous.
|
||||
!insertmacro BadPathsCheck
|
||||
|
||||
# Does path end with "\nheko"?
|
||||
!define CHECK_PATH "\nheko"
|
||||
StrLen $R1 "${CHECK_PATH}"
|
||||
StrCpy $R0 $INSTDIR "" -$R1
|
||||
StrCmp $R0 "${CHECK_PATH}" +3
|
||||
MessageBox MB_YESNO|MB_ICONQUESTION "Unrecognised uninstall path. Continue anyway?" IDYES +2
|
||||
Abort
|
||||
|
||||
IfFileExists "$INSTDIR\*.*" 0 +2
|
||||
IfFileExists "$INSTDIR\nheko.exe" +3
|
||||
MessageBox MB_OK|MB_ICONSTOP "Install path invalid!"
|
||||
Abort
|
||||
|
||||
########
|
||||
|
||||
RMDir /r /REBOOTOK $INSTDIR
|
||||
|
||||
Delete "$INSTDIR\uninstall.exe"
|
||||
!ifdef WEB_SITE
|
||||
Delete "$INSTDIR\${APP_NAME} website.url"
|
||||
!endif
|
||||
|
||||
!ifdef REG_START_MENU
|
||||
!insertmacro MUI_STARTMENU_GETFOLDER "Application" $SM_Folder
|
||||
Delete "$SMPROGRAMS\$SM_Folder\${APP_NAME}.lnk"
|
||||
Delete "$SMPROGRAMS\$SM_Folder\Uninstall ${APP_NAME}.lnk"
|
||||
!ifdef WEB_SITE
|
||||
Delete "$SMPROGRAMS\$SM_Folder\${APP_NAME} Website.lnk"
|
||||
!endif
|
||||
Delete "$DESKTOP\${APP_NAME}.lnk"
|
||||
|
||||
RmDir "$SMPROGRAMS\$SM_Folder"
|
||||
!endif
|
||||
|
||||
!ifndef REG_START_MENU
|
||||
Delete "$SMPROGRAMS\nheko\${APP_NAME}.lnk"
|
||||
Delete "$SMPROGRAMS\nheko\Uninstall ${APP_NAME}.lnk"
|
||||
!ifdef WEB_SITE
|
||||
Delete "$SMPROGRAMS\nheko\${APP_NAME} Website.lnk"
|
||||
!endif
|
||||
Delete "$DESKTOP\${APP_NAME}.lnk"
|
||||
|
||||
RmDir "$SMPROGRAMS\nheko"
|
||||
!endif
|
||||
|
||||
DeleteRegKey ${REG_ROOT} "${REG_APP_PATH}"
|
||||
DeleteRegKey ${REG_ROOT} "${UNINSTALL_PATH}"
|
||||
SectionEnd
|
||||
|
||||
######################################################################
|
@ -1,5 +1,6 @@
|
||||
---
|
||||
Language: Cpp
|
||||
Standard: Cpp11
|
||||
AccessModifierOffset: -8
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: true
|
||||
@ -10,3 +11,4 @@ IndentCaseLabels: false
|
||||
IndentWidth: 8
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
PointerAlignment: Right
|
||||
Cpp11BracedListStyle: true
|
||||
|
20
.github/ISSUE_TEMPLATE.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
<!--
|
||||
If you want to request a feature or ask a question, feel free to remove all the irrelevant text.
|
||||
-->
|
||||
|
||||
### System:
|
||||
|
||||
- Nheko commit/version:
|
||||
- Operating System:
|
||||
- Qt version:
|
||||
- C++ compiler:
|
||||
- Desktop Environment: <!-- for Linux -->
|
||||
|
||||
### Actual behavior
|
||||
|
||||
### Expected behavior
|
||||
|
||||
### Steps to reproduce
|
||||
|
||||
<!-- If the program crashed. -->
|
||||
### Debugger traceback
|
28
.travis.yml
28
.travis.yml
@ -21,9 +21,33 @@ install:
|
||||
- if [ $TRAVIS_OS_NAME == osx ]; then export CMAKE_PREFIX_PATH=/usr/local/opt/qt5; fi
|
||||
- if [ $TRAVIS_OS_NAME == linux ]; then ./.ci/linux/install-deps.sh; fi
|
||||
before_script:
|
||||
- if [ $TRAVIS_OS_NAME == linux ]; then source /opt/qt58/bin/qt58-env.sh; fi
|
||||
- if [ $TRAVIS_OS_NAME == linux ]; then source /opt/qt59/bin/qt59-env.sh; fi
|
||||
- cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release
|
||||
script:
|
||||
- make -C build -j2
|
||||
- if [ $TRAVIS_OS_NAME == linux ]; then ./.ci/linux/run-tests.sh; fi
|
||||
- if [ $TRAVIS_OS_NAME == osx ]; then make lint; fi
|
||||
- if [ $TRAVIS_OS_NAME == osx ]; then ./.ci/macos/deploy.sh; fi
|
||||
- if [ $TRAVIS_OS_NAME == linux ]; then ./.ci/linux/run-tests.sh; fi
|
||||
- if [ $TRAVIS_OS_NAME == linux ]; then ./.ci/linux/deploy.sh; fi
|
||||
|
||||
deploy:
|
||||
- skip_cleanup: true
|
||||
overwrite: true
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: oprXzESukFiXBeF2BXkXUlegsAQc95Ub4kc/OkoNFaYBvqpA+IGpWHmHCx5JPny/OT3Kc2Urpe2JUeGSWDHZ7UCKDjH+NzGP3uN82fHh/HiszG/Srw7+hWEHm1ve+gMK9GS8pr+yUsUrPP0UfVXlPoI4pBWa4zGi2Ndb/SqvjCgIHFLtGyoBo6CydKQ/AyWiXSMKDfJL+Dx4JLIPP4RTCBJy8ZrZ8m/a5Tgy4Ij6+djjrgYCZCEhGxSYw7xDIT/9SV8g9NkrbisqBDrILzAH8Yhe4XMRMXo88OAxV5+Vb9Rw1hrqczez6lpFDbJetv8MjofND+pSoAFwtjaL1wTFK9Ud6w4O9AuHlEQH9cGVdvsxFcosRwJVh58x51JM9ptoktqhx/HHJBTuCHCYYlHwtRwbwqnMYdLzKZG5FnujT8DG+9mcva1fL6tzW/XD505VPMWwXFC/2/pvolgAkTFFXYSALAwZlK3IgoXU8Gok/3B4iHofzQsFf6Yq3BI/88x7tVASUqiYhoKrO50+gb6pNIRCyWgGUiBEVXBp6Ziq3ORQPyQJg7i9HHUGTUu74yvGLHWLwjNQzZP/hxJZK3VlJxzyXntdOxiJc8iOzNrU+rPKBAlAaE6bQDOoniIysEgdD5BXHTLFzPvts4P1n2Ckor5/rNJ+qXR8GU+/y7e1GKU=
|
||||
file: nheko-x86_64.AppImage
|
||||
on:
|
||||
condition: $TRAVIS_OS_NAME == linux
|
||||
repo: mujx/nheko
|
||||
tags: true
|
||||
- skip_cleanup: true
|
||||
overwrite: true
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: oprXzESukFiXBeF2BXkXUlegsAQc95Ub4kc/OkoNFaYBvqpA+IGpWHmHCx5JPny/OT3Kc2Urpe2JUeGSWDHZ7UCKDjH+NzGP3uN82fHh/HiszG/Srw7+hWEHm1ve+gMK9GS8pr+yUsUrPP0UfVXlPoI4pBWa4zGi2Ndb/SqvjCgIHFLtGyoBo6CydKQ/AyWiXSMKDfJL+Dx4JLIPP4RTCBJy8ZrZ8m/a5Tgy4Ij6+djjrgYCZCEhGxSYw7xDIT/9SV8g9NkrbisqBDrILzAH8Yhe4XMRMXo88OAxV5+Vb9Rw1hrqczez6lpFDbJetv8MjofND+pSoAFwtjaL1wTFK9Ud6w4O9AuHlEQH9cGVdvsxFcosRwJVh58x51JM9ptoktqhx/HHJBTuCHCYYlHwtRwbwqnMYdLzKZG5FnujT8DG+9mcva1fL6tzW/XD505VPMWwXFC/2/pvolgAkTFFXYSALAwZlK3IgoXU8Gok/3B4iHofzQsFf6Yq3BI/88x7tVASUqiYhoKrO50+gb6pNIRCyWgGUiBEVXBp6Ziq3ORQPyQJg7i9HHUGTUu74yvGLHWLwjNQzZP/hxJZK3VlJxzyXntdOxiJc8iOzNrU+rPKBAlAaE6bQDOoniIysEgdD5BXHTLFzPvts4P1n2Ckor5/rNJ+qXR8GU+/y7e1GKU=
|
||||
file: nheko.dmg
|
||||
on:
|
||||
condition: $TRAVIS_OS_NAME == osx
|
||||
repo: mujx/nheko
|
||||
tags: true
|
||||
|
810
.vscode/.cmaketools.json
vendored
Normal file
810
.vscode/.cmaketools.json
vendored
Normal file
@ -0,0 +1,810 @@
|
||||
{
|
||||
"variant": {
|
||||
"label": "Debug",
|
||||
"keywordSettings": {
|
||||
"buildType": "debug"
|
||||
},
|
||||
"description": "Emit debug information without performing optimizations"
|
||||
},
|
||||
"activeEnvironments": [],
|
||||
"codeModel": {
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Debug",
|
||||
"projects": [
|
||||
{
|
||||
"buildDirectory": "/home/max/Program/nheko/build",
|
||||
"name": "nheko",
|
||||
"sourceDirectory": "/home/max/Program/nheko",
|
||||
"targets": [
|
||||
{
|
||||
"artifacts": [
|
||||
"/home/max/Program/nheko/build/nheko"
|
||||
],
|
||||
"buildDirectory": "/home/max/Program/nheko/build",
|
||||
"crossReferences": {
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 355,
|
||||
"name": "add_executable",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"relatedStatements": [
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 233,
|
||||
"name": "include_directories",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_include_directories"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 234,
|
||||
"name": "include_directories",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_include_directories"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 235,
|
||||
"name": "include_directories",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_include_directories"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 236,
|
||||
"name": "include_directories",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_include_directories"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 238,
|
||||
"name": "include_directories",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_include_directories"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 239,
|
||||
"name": "include_directories",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_include_directories"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 356,
|
||||
"name": "target_link_libraries",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_link_libraries"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 356,
|
||||
"name": "target_link_libraries",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_link_libraries"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 356,
|
||||
"name": "target_link_libraries",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_link_libraries"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 356,
|
||||
"name": "target_link_libraries",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_link_libraries"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 356,
|
||||
"name": "target_link_libraries",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_link_libraries"
|
||||
}
|
||||
]
|
||||
},
|
||||
"fileGroups": [
|
||||
{
|
||||
"isGenerated": false,
|
||||
"sources": [
|
||||
"resources/res.qrc",
|
||||
"build/translations.qrc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"compileFlags": " -Wall -Wextra -march=native -Werror -pipe -pedantic -Wunreachable-code -fdiagnostics-color=always -g -fPIC -std=gnu++11",
|
||||
"defines": [
|
||||
"QT_CONCURRENT_LIB",
|
||||
"QT_CORE_LIB",
|
||||
"QT_GUI_LIB",
|
||||
"QT_NETWORK_LIB",
|
||||
"QT_WIDGETS_LIB"
|
||||
],
|
||||
"includePath": [
|
||||
{
|
||||
"path": "/home/max/Program/nheko/build"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/include"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/include/ui"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/include/events"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/include/events/messages"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/libs/lmdbxx"
|
||||
},
|
||||
{
|
||||
"isSystem": true,
|
||||
"path": "/usr/include/qt5"
|
||||
},
|
||||
{
|
||||
"isSystem": true,
|
||||
"path": "/usr/include/qt5/QtCore"
|
||||
},
|
||||
{
|
||||
"isSystem": true,
|
||||
"path": "/usr/lib64/qt5/./mkspecs/linux-g++"
|
||||
},
|
||||
{
|
||||
"isSystem": true,
|
||||
"path": "/usr/include/qt5/QtWidgets"
|
||||
},
|
||||
{
|
||||
"isSystem": true,
|
||||
"path": "/usr/include/qt5/QtGui"
|
||||
},
|
||||
{
|
||||
"isSystem": true,
|
||||
"path": "/usr/include/qt5/QtNetwork"
|
||||
},
|
||||
{
|
||||
"isSystem": true,
|
||||
"path": "/usr/include/qt5/QtConcurrent"
|
||||
}
|
||||
],
|
||||
"isGenerated": false,
|
||||
"language": "CXX",
|
||||
"sources": [
|
||||
"src/AvatarProvider.cc",
|
||||
"src/Cache.cc",
|
||||
"src/ChatPage.cc",
|
||||
"src/CommunitiesListItem.cc",
|
||||
"src/CommunitiesList.cc",
|
||||
"src/Community.cc",
|
||||
"src/Deserializable.cc",
|
||||
"src/EmojiCategory.cc",
|
||||
"src/EmojiItemDelegate.cc",
|
||||
"src/EmojiPanel.cc",
|
||||
"src/EmojiPickButton.cc",
|
||||
"src/EmojiProvider.cc",
|
||||
"src/ImageItem.cc",
|
||||
"src/ImageOverlayDialog.cc",
|
||||
"src/InputValidator.cc",
|
||||
"src/JoinRoomDialog.cc",
|
||||
"src/LeaveRoomDialog.cc",
|
||||
"src/Login.cc",
|
||||
"src/LoginPage.cc",
|
||||
"src/LogoutDialog.cc",
|
||||
"src/MainWindow.cc",
|
||||
"src/MatrixClient.cc",
|
||||
"src/Profile.cc",
|
||||
"src/QuickSwitcher.cc",
|
||||
"src/Register.cc",
|
||||
"src/RegisterPage.cc",
|
||||
"src/RoomInfoListItem.cc",
|
||||
"src/RoomList.cc",
|
||||
"src/RoomMessages.cc",
|
||||
"src/RoomState.cc",
|
||||
"src/SideBarActions.cc",
|
||||
"src/UserSettingsPage.cc",
|
||||
"src/Splitter.cc",
|
||||
"src/Sync.cc",
|
||||
"src/TextInputWidget.cc",
|
||||
"src/TimelineItem.cc",
|
||||
"src/TimelineView.cc",
|
||||
"src/TimelineViewManager.cc",
|
||||
"src/TopRoomBar.cc",
|
||||
"src/TrayIcon.cc",
|
||||
"src/TypingDisplay.cc",
|
||||
"src/UserInfoWidget.cc",
|
||||
"src/Versions.cc",
|
||||
"src/WelcomePage.cc",
|
||||
"src/main.cc",
|
||||
"src/ui/Avatar.cc",
|
||||
"src/ui/Badge.cc",
|
||||
"src/ui/LoadingIndicator.cc",
|
||||
"src/ui/FlatButton.cc",
|
||||
"src/ui/FloatingButton.cc",
|
||||
"src/ui/Label.cc",
|
||||
"src/ui/OverlayModal.cc",
|
||||
"src/ui/ScrollBar.cc",
|
||||
"src/ui/SnackBar.cc",
|
||||
"src/ui/RaisedButton.cc",
|
||||
"src/ui/Ripple.cc",
|
||||
"src/ui/RippleOverlay.cc",
|
||||
"src/ui/OverlayWidget.cc",
|
||||
"src/ui/TextField.cc",
|
||||
"src/ui/ToggleButton.cc",
|
||||
"src/ui/Theme.cc",
|
||||
"src/ui/ThemeManager.cc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"isGenerated": true,
|
||||
"sources": [
|
||||
"build/nheko_de.qm",
|
||||
"build/nheko_el.qm",
|
||||
"build/nheko_en.qm",
|
||||
"build/nheko_nl.qm",
|
||||
"build/include/moc_AvatarProvider.cpp.rule",
|
||||
"build/include/moc_ChatPage.cpp.rule",
|
||||
"build/include/moc_CommunitiesListItem.cpp.rule",
|
||||
"build/include/moc_CommunitiesList.cpp.rule",
|
||||
"build/include/moc_Community.cpp.rule",
|
||||
"build/include/moc_EmojiCategory.cpp.rule",
|
||||
"build/include/moc_EmojiItemDelegate.cpp.rule",
|
||||
"build/include/moc_EmojiPanel.cpp.rule",
|
||||
"build/include/moc_EmojiPickButton.cpp.rule",
|
||||
"build/include/ui/moc_FloatingButton.cpp.rule",
|
||||
"build/include/moc_ImageItem.cpp.rule",
|
||||
"build/include/moc_ImageOverlayDialog.cpp.rule",
|
||||
"build/include/moc_JoinRoomDialog.cpp.rule",
|
||||
"build/include/moc_LeaveRoomDialog.cpp.rule",
|
||||
"build/include/moc_LoginPage.cpp.rule",
|
||||
"build/include/moc_LogoutDialog.cpp.rule",
|
||||
"build/include/moc_MainWindow.cpp.rule",
|
||||
"build/include/moc_MatrixClient.cpp.rule",
|
||||
"build/include/moc_QuickSwitcher.cpp.rule",
|
||||
"build/include/moc_RegisterPage.cpp.rule",
|
||||
"build/include/moc_RoomInfoListItem.cpp.rule",
|
||||
"build/include/moc_RoomList.cpp.rule",
|
||||
"build/include/moc_SideBarActions.cpp.rule",
|
||||
"build/include/moc_UserSettingsPage.cpp.rule",
|
||||
"build/include/moc_Splitter.cpp.rule",
|
||||
"build/include/moc_TextInputWidget.cpp.rule",
|
||||
"build/include/moc_TimelineItem.cpp.rule",
|
||||
"build/include/moc_TimelineView.cpp.rule",
|
||||
"build/include/moc_TimelineViewManager.cpp.rule",
|
||||
"build/include/moc_TopRoomBar.cpp.rule",
|
||||
"build/include/moc_TrayIcon.cpp.rule",
|
||||
"build/include/moc_TypingDisplay.cpp.rule",
|
||||
"build/include/moc_UserInfoWidget.cpp.rule",
|
||||
"build/include/moc_WelcomePage.cpp.rule",
|
||||
"build/include/ui/moc_Avatar.cpp.rule",
|
||||
"build/include/ui/moc_Badge.cpp.rule",
|
||||
"build/include/ui/moc_LoadingIndicator.cpp.rule",
|
||||
"build/include/ui/moc_FlatButton.cpp.rule",
|
||||
"build/include/ui/moc_Label.cpp.rule",
|
||||
"build/include/ui/moc_OverlayWidget.cpp.rule",
|
||||
"build/include/ui/moc_ScrollBar.cpp.rule",
|
||||
"build/include/ui/moc_SnackBar.cpp.rule",
|
||||
"build/include/ui/moc_RaisedButton.cpp.rule",
|
||||
"build/include/ui/moc_Ripple.cpp.rule",
|
||||
"build/include/ui/moc_RippleOverlay.cpp.rule",
|
||||
"build/include/ui/moc_TextField.cpp.rule",
|
||||
"build/include/ui/moc_ToggleButton.cpp.rule",
|
||||
"build/include/ui/moc_Theme.cpp.rule",
|
||||
"build/include/ui/moc_ThemeManager.cpp.rule",
|
||||
"build/nheko_de.qm.rule",
|
||||
"build/nheko_el.qm.rule",
|
||||
"build/nheko_en.qm.rule",
|
||||
"build/nheko_nl.qm.rule"
|
||||
]
|
||||
},
|
||||
{
|
||||
"compileFlags": " -Wall -Wextra -march=native -Werror -pipe -pedantic -Wunreachable-code -fdiagnostics-color=always -g -fPIC -std=gnu++11",
|
||||
"defines": [
|
||||
"QT_CONCURRENT_LIB",
|
||||
"QT_CORE_LIB",
|
||||
"QT_GUI_LIB",
|
||||
"QT_NETWORK_LIB",
|
||||
"QT_WIDGETS_LIB"
|
||||
],
|
||||
"includePath": [
|
||||
{
|
||||
"path": "/home/max/Program/nheko/build"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/include"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/include/ui"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/include/events"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/include/events/messages"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/libs/lmdbxx"
|
||||
},
|
||||
{
|
||||
"isSystem": true,
|
||||
"path": "/usr/include/qt5"
|
||||
},
|
||||
{
|
||||
"isSystem": true,
|
||||
"path": "/usr/include/qt5/QtCore"
|
||||
},
|
||||
{
|
||||
"isSystem": true,
|
||||
"path": "/usr/lib64/qt5/./mkspecs/linux-g++"
|
||||
},
|
||||
{
|
||||
"isSystem": true,
|
||||
"path": "/usr/include/qt5/QtWidgets"
|
||||
},
|
||||
{
|
||||
"isSystem": true,
|
||||
"path": "/usr/include/qt5/QtGui"
|
||||
},
|
||||
{
|
||||
"isSystem": true,
|
||||
"path": "/usr/include/qt5/QtNetwork"
|
||||
},
|
||||
{
|
||||
"isSystem": true,
|
||||
"path": "/usr/include/qt5/QtConcurrent"
|
||||
}
|
||||
],
|
||||
"isGenerated": true,
|
||||
"language": "CXX",
|
||||
"sources": [
|
||||
"build/include/moc_AvatarProvider.cpp",
|
||||
"build/include/moc_ChatPage.cpp",
|
||||
"build/include/moc_CommunitiesListItem.cpp",
|
||||
"build/include/moc_CommunitiesList.cpp",
|
||||
"build/include/moc_Community.cpp",
|
||||
"build/include/moc_EmojiCategory.cpp",
|
||||
"build/include/moc_EmojiItemDelegate.cpp",
|
||||
"build/include/moc_EmojiPanel.cpp",
|
||||
"build/include/moc_EmojiPickButton.cpp",
|
||||
"build/include/ui/moc_FloatingButton.cpp",
|
||||
"build/include/moc_ImageItem.cpp",
|
||||
"build/include/moc_ImageOverlayDialog.cpp",
|
||||
"build/include/moc_JoinRoomDialog.cpp",
|
||||
"build/include/moc_LeaveRoomDialog.cpp",
|
||||
"build/include/moc_LoginPage.cpp",
|
||||
"build/include/moc_LogoutDialog.cpp",
|
||||
"build/include/moc_MainWindow.cpp",
|
||||
"build/include/moc_MatrixClient.cpp",
|
||||
"build/include/moc_QuickSwitcher.cpp",
|
||||
"build/include/moc_RegisterPage.cpp",
|
||||
"build/include/moc_RoomInfoListItem.cpp",
|
||||
"build/include/moc_RoomList.cpp",
|
||||
"build/include/moc_SideBarActions.cpp",
|
||||
"build/include/moc_UserSettingsPage.cpp",
|
||||
"build/include/moc_Splitter.cpp",
|
||||
"build/include/moc_TextInputWidget.cpp",
|
||||
"build/include/moc_TimelineItem.cpp",
|
||||
"build/include/moc_TimelineView.cpp",
|
||||
"build/include/moc_TimelineViewManager.cpp",
|
||||
"build/include/moc_TopRoomBar.cpp",
|
||||
"build/include/moc_TrayIcon.cpp",
|
||||
"build/include/moc_TypingDisplay.cpp",
|
||||
"build/include/moc_UserInfoWidget.cpp",
|
||||
"build/include/moc_WelcomePage.cpp",
|
||||
"build/include/ui/moc_Avatar.cpp",
|
||||
"build/include/ui/moc_Badge.cpp",
|
||||
"build/include/ui/moc_LoadingIndicator.cpp",
|
||||
"build/include/ui/moc_FlatButton.cpp",
|
||||
"build/include/ui/moc_Label.cpp",
|
||||
"build/include/ui/moc_OverlayWidget.cpp",
|
||||
"build/include/ui/moc_ScrollBar.cpp",
|
||||
"build/include/ui/moc_SnackBar.cpp",
|
||||
"build/include/ui/moc_RaisedButton.cpp",
|
||||
"build/include/ui/moc_Ripple.cpp",
|
||||
"build/include/ui/moc_RippleOverlay.cpp",
|
||||
"build/include/ui/moc_TextField.cpp",
|
||||
"build/include/ui/moc_ToggleButton.cpp",
|
||||
"build/include/ui/moc_Theme.cpp",
|
||||
"build/include/ui/moc_ThemeManager.cpp",
|
||||
"build/qrc_res.cpp",
|
||||
"build/qrc_translations.cpp"
|
||||
]
|
||||
}
|
||||
],
|
||||
"fullName": "nheko",
|
||||
"linkFlags": "-rdynamic",
|
||||
"linkLanguageFlags": "-Wall -Wextra -march=native -Werror -pipe -pedantic -Wunreachable-code -fdiagnostics-color=always -g",
|
||||
"linkLibraries": "libmatrix_events.a /usr/lib64/libQt5Widgets.so.5.9.2 /usr/lib64/libQt5Network.so.5.9.2 /usr/lib64/libQt5Concurrent.so.5.9.2 -llmdb /usr/lib64/libQt5Gui.so.5.9.2 /usr/lib64/libQt5Core.so.5.9.2",
|
||||
"linkerLanguage": "CXX",
|
||||
"name": "nheko",
|
||||
"sourceDirectory": "/home/max/Program/nheko",
|
||||
"type": "EXECUTABLE"
|
||||
},
|
||||
{
|
||||
"buildDirectory": "/home/max/Program/nheko/build",
|
||||
"crossReferences": {
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 300,
|
||||
"name": "add_custom_target",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"relatedStatements": [
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 233,
|
||||
"name": "include_directories",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_include_directories"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 234,
|
||||
"name": "include_directories",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_include_directories"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 235,
|
||||
"name": "include_directories",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_include_directories"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 236,
|
||||
"name": "include_directories",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_include_directories"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 238,
|
||||
"name": "include_directories",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_include_directories"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 239,
|
||||
"name": "include_directories",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_include_directories"
|
||||
}
|
||||
]
|
||||
},
|
||||
"fileGroups": [
|
||||
{
|
||||
"isGenerated": true,
|
||||
"sources": [
|
||||
"build/CMakeFiles/LANG_QRC",
|
||||
"build/CMakeFiles/LANG_QRC.rule",
|
||||
"build/nheko_de.qm.rule",
|
||||
"build/nheko_el.qm.rule",
|
||||
"build/nheko_en.qm.rule",
|
||||
"build/nheko_nl.qm.rule"
|
||||
]
|
||||
}
|
||||
],
|
||||
"fullName": "LANG_QRC",
|
||||
"name": "LANG_QRC",
|
||||
"sourceDirectory": "/home/max/Program/nheko",
|
||||
"type": "UTILITY"
|
||||
},
|
||||
{
|
||||
"artifacts": [
|
||||
"/home/max/Program/nheko/build/libmatrix_events.a"
|
||||
],
|
||||
"buildDirectory": "/home/max/Program/nheko/build",
|
||||
"crossReferences": {
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 317,
|
||||
"name": "add_library",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"relatedStatements": [
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 233,
|
||||
"name": "include_directories",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_include_directories"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 234,
|
||||
"name": "include_directories",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_include_directories"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 235,
|
||||
"name": "include_directories",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_include_directories"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 236,
|
||||
"name": "include_directories",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_include_directories"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 238,
|
||||
"name": "include_directories",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_include_directories"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 239,
|
||||
"name": "include_directories",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_include_directories"
|
||||
},
|
||||
{
|
||||
"backtrace": [
|
||||
{
|
||||
"line": 318,
|
||||
"name": "target_link_libraries",
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/CMakeLists.txt"
|
||||
}
|
||||
],
|
||||
"type": "target_link_libraries"
|
||||
}
|
||||
]
|
||||
},
|
||||
"fileGroups": [
|
||||
{
|
||||
"compileFlags": " -Wall -Wextra -march=native -Werror -pipe -pedantic -Wunreachable-code -fdiagnostics-color=always -g -fPIC -std=gnu++11",
|
||||
"defines": [
|
||||
"QT_CORE_LIB"
|
||||
],
|
||||
"includePath": [
|
||||
{
|
||||
"path": "/home/max/Program/nheko/build"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/include"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/include/ui"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/include/events"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/include/events/messages"
|
||||
},
|
||||
{
|
||||
"path": "/home/max/Program/nheko/libs/lmdbxx"
|
||||
},
|
||||
{
|
||||
"isSystem": true,
|
||||
"path": "/usr/include/qt5"
|
||||
},
|
||||
{
|
||||
"isSystem": true,
|
||||
"path": "/usr/include/qt5/QtCore"
|
||||
},
|
||||
{
|
||||
"isSystem": true,
|
||||
"path": "/usr/lib64/qt5/./mkspecs/linux-g++"
|
||||
}
|
||||
],
|
||||
"isGenerated": false,
|
||||
"language": "CXX",
|
||||
"sources": [
|
||||
"src/events/Event.cc",
|
||||
"src/events/AliasesEventContent.cc",
|
||||
"src/events/AvatarEventContent.cc",
|
||||
"src/events/CanonicalAliasEventContent.cc",
|
||||
"src/events/CreateEventContent.cc",
|
||||
"src/events/HistoryVisibilityEventContent.cc",
|
||||
"src/events/JoinRulesEventContent.cc",
|
||||
"src/events/MemberEventContent.cc",
|
||||
"src/events/MessageEventContent.cc",
|
||||
"src/events/NameEventContent.cc",
|
||||
"src/events/PowerLevelsEventContent.cc",
|
||||
"src/events/TopicEventContent.cc",
|
||||
"src/events/messages/Audio.cc",
|
||||
"src/events/messages/Emote.cc",
|
||||
"src/events/messages/File.cc",
|
||||
"src/events/messages/Image.cc",
|
||||
"src/events/messages/Location.cc",
|
||||
"src/events/messages/Notice.cc",
|
||||
"src/events/messages/Text.cc",
|
||||
"src/events/messages/Video.cc",
|
||||
"src/Deserializable.cc"
|
||||
]
|
||||
}
|
||||
],
|
||||
"fullName": "libmatrix_events.a",
|
||||
"linkerLanguage": "CXX",
|
||||
"name": "matrix_events",
|
||||
"sourceDirectory": "/home/max/Program/nheko",
|
||||
"type": "STATIC_LIBRARY"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"cookie": "0.46582309898312313",
|
||||
"inReplyTo": "codemodel",
|
||||
"type": "reply"
|
||||
}
|
||||
}
|
16
.vscode/c_cpp_properties.json
vendored
Normal file
16
.vscode/c_cpp_properties.json
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "null",
|
||||
"includePath": [],
|
||||
"defines": [],
|
||||
"browse": {
|
||||
"path": [],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
},
|
||||
"intelliSenseMode": "clang-x64"
|
||||
}
|
||||
],
|
||||
"version": 3
|
||||
}
|
12
.vscode/tasks.json
vendored
Normal file
12
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "echo",
|
||||
"type": "shell",
|
||||
"command": "echo Hello"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,10 +1,25 @@
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
|
||||
project(nheko C CXX)
|
||||
|
||||
option(BUILD_TESTS "Build all tests" OFF)
|
||||
option(APPVEYOR_BUILD "Build on appveyor" OFF)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
|
||||
# Include Qt basic functions
|
||||
include(QtCommon)
|
||||
|
||||
project(nheko LANGUAGES C CXX VERSION 0.1.0)
|
||||
|
||||
# Set PROJECT_VERSION_PATCH and PROJECT_VERSION_TWEAK to 0 if not present, needed by add_project_meta
|
||||
fix_project_version()
|
||||
|
||||
# Set additional project information
|
||||
set(COMPANY "Nheko")
|
||||
set(COPYRIGHT "Copyright (c) 2017 Mujx")
|
||||
set(IDENTIFIER "com.mujx.nheko")
|
||||
|
||||
add_project_meta(META_FILES_TO_INCLUDE)
|
||||
|
||||
#
|
||||
# LMDB
|
||||
#
|
||||
@ -156,6 +171,7 @@ set(SRC_FILES
|
||||
src/RoomMessages.cc
|
||||
src/RoomState.cc
|
||||
src/SideBarActions.cc
|
||||
src/UserSettingsPage.cc
|
||||
src/Splitter.cc
|
||||
src/Sync.cc
|
||||
src/TextInputWidget.cc
|
||||
@ -184,6 +200,7 @@ set(SRC_FILES
|
||||
src/ui/RippleOverlay.cc
|
||||
src/ui/OverlayWidget.cc
|
||||
src/ui/TextField.cc
|
||||
src/ui/ToggleButton.cc
|
||||
src/ui/Theme.cc
|
||||
src/ui/ThemeManager.cc
|
||||
)
|
||||
@ -245,6 +262,7 @@ qt5_wrap_cpp(MOC_HEADERS
|
||||
include/RoomInfoListItem.h
|
||||
include/RoomList.h
|
||||
include/SideBarActions.h
|
||||
include/UserSettingsPage.h
|
||||
include/Splitter.h
|
||||
include/TextInputWidget.h
|
||||
include/TimelineItem.h
|
||||
@ -268,6 +286,7 @@ qt5_wrap_cpp(MOC_HEADERS
|
||||
include/ui/Ripple.h
|
||||
include/ui/RippleOverlay.h
|
||||
include/ui/TextField.h
|
||||
include/ui/ToggleButton.h
|
||||
include/ui/Theme.h
|
||||
include/ui/ThemeManager.h
|
||||
)
|
||||
@ -298,14 +317,6 @@ qt5_add_resources(QRC resources/res.qrc)
|
||||
add_library(matrix_events ${MATRIX_EVENTS} src/Deserializable.cc)
|
||||
target_link_libraries(matrix_events Qt5::Core)
|
||||
|
||||
#
|
||||
# Bundle icons.
|
||||
#
|
||||
if (APPLE)
|
||||
set(ICON_FILE resources/nheko.icns)
|
||||
set_source_files_properties(${ICON_FILE} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
endif()
|
||||
|
||||
if (BUILD_TESTS)
|
||||
enable_testing()
|
||||
|
||||
@ -332,15 +343,15 @@ else()
|
||||
set (NHEKO_LIBS matrix_events Qt5::Widgets Qt5::Network Qt5::Concurrent ${LMDB_LIBRARY})
|
||||
endif()
|
||||
|
||||
set (NHEKO_DEPS ${OS_BUNDLE} ${SRC_FILES} ${UI_HEADERS} ${MOC_HEADERS} ${QRC} ${LANG_QRC} ${QM_SRC})
|
||||
set (NHEKO_DEPS ${SRC_FILES} ${UI_HEADERS} ${MOC_HEADERS} ${QRC} ${LANG_QRC} ${QM_SRC} ${META_FILES_TO_INCLUDE})
|
||||
|
||||
if(APPLE)
|
||||
add_executable (nheko ${NHEKO_DEPS})
|
||||
add_executable (nheko ${OS_BUNDLE} ${NHEKO_DEPS})
|
||||
target_link_libraries (nheko ${NHEKO_LIBS} Qt5::MacExtras)
|
||||
elseif(WIN32)
|
||||
add_executable (nheko ${ICON_FILE} ${NHEKO_DEPS})
|
||||
add_executable (nheko ${OS_BUNDLE} ${ICON_FILE} ${NHEKO_DEPS})
|
||||
target_link_libraries (nheko ${NTDLIB} ${NHEKO_LIBS} Qt5::WinMain)
|
||||
else()
|
||||
add_executable (nheko ${NHEKO_DEPS})
|
||||
add_executable (nheko ${OS_BUNDLE} ${NHEKO_DEPS})
|
||||
target_link_libraries (nheko ${NHEKO_LIBS})
|
||||
endif()
|
||||
|
22
Makefile
22
Makefile
@ -1,9 +1,4 @@
|
||||
APP_NAME = nheko
|
||||
|
||||
MAC_DIST_DIR = dist/MacOS
|
||||
APP_TEMPLATE = $(MAC_DIST_DIR)/Nheko.app
|
||||
|
||||
# Linux specific helpers
|
||||
debug:
|
||||
@cmake -DBUILD_TESTS=OFF -H. -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Debug
|
||||
@cmake --build build
|
||||
@ -17,19 +12,14 @@ test:
|
||||
@cmake --build build
|
||||
@cd build && GTEST_COLOR=1 ctest --verbose
|
||||
|
||||
app: release-debug $(APP_TEMPLATE)
|
||||
@cp -fp ./build/$(APP_NAME) $(APP_TEMPLATE)/Contents/MacOS
|
||||
@echo "Created '$(APP_NAME).app' in '$(APP_TEMPLATE)'"
|
||||
linux-appimage:
|
||||
@./.ci/linux/deploy.sh
|
||||
|
||||
app-install: app
|
||||
cp -Rf $(APP_TEMPLATE) /Applications/
|
||||
macos-app: release-debug
|
||||
@./.ci/macos/deploy.sh
|
||||
|
||||
dmg: app
|
||||
hdiutil create $(MAC_DIST_DIR)/Nheko.dmg \
|
||||
-volname "$(APP_NAME)" \
|
||||
-fs HFS+ \
|
||||
-srcfolder $(MAC_DIST_DIR) \
|
||||
-ov -format UDZO
|
||||
macos-app-install:
|
||||
cp -Rf build/nheko.app /Applications
|
||||
|
||||
run:
|
||||
@./build/nheko
|
||||
|
18
README.md
18
README.md
@ -16,10 +16,12 @@ but we are getting close to a more feature complete client.
|
||||
Specifically there is support for:
|
||||
- Joining & leaving rooms
|
||||
- Sending & receiving images and emoji.
|
||||
- Receiving typing notifications.
|
||||
- Typing notifications.
|
||||
|
||||
### Installation
|
||||
|
||||
There are pre-built nigtly releases [here](https://github.com/mujx/nheko/releases/tag/nightly) for Linux ([AppImage](https://appimage.org/)), Mac and Windows.
|
||||
|
||||
#### Arch Linux
|
||||
```bash
|
||||
pacaur -S nheko-git
|
||||
@ -37,10 +39,6 @@ sudo layman -a matrix
|
||||
sudo emerge -a nheko
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
You can find an installer [here](https://ci.appveyor.com/project/mujx/nheko/branch/master/artifacts).
|
||||
|
||||
### Build Requirements
|
||||
|
||||
- Qt5 (5.7 or greater). Qt 5.7 adds support for color font rendering with
|
||||
@ -105,15 +103,7 @@ make -C build
|
||||
|
||||
The `nheko` binary will be located in the `build` directory.
|
||||
|
||||
##### MacOS
|
||||
|
||||
You can create an app bundle with `make app`. The output will be located at
|
||||
`dist/MacOS/Nheko.app` which can be copied to `/Applications/Nheko.app`.
|
||||
|
||||
You can also create a disk image with `make dmg`. The output will be located at
|
||||
`dist/MacOS/Nheko.dmg`
|
||||
|
||||
##### Nix
|
||||
#### Nix
|
||||
|
||||
Download the repo as mentioned above and run
|
||||
|
||||
|
79
appveyor.yml
79
appveyor.yml
@ -15,14 +15,32 @@ build:
|
||||
install:
|
||||
- set QT_DIR=C:\Qt\5.8\msvc2015_64
|
||||
- set PATH=%PATH%;%QT_DIR%\bin;C:\MinGW\bin
|
||||
- copy LICENSE .ci\windows\LICENSE.txt
|
||||
- cinst nsis --version 3.0 -y -installArgs /D=C:\nsis
|
||||
|
||||
build_script:
|
||||
- cmake -G "Visual Studio 14 2015 Win64" -H. -Bbuild -DAPPVEYOR_BUILD=ON
|
||||
# VERSION format: branch-master/branch-1.2
|
||||
# INSTVERSION format: x.y.z
|
||||
# WINVERSION format: 9999.0.0.123/1.2.0.234
|
||||
- if "%APPVEYOR_REPO_TAG%"=="false" set INSTVERSION=0.1.0
|
||||
- if "%APPVEYOR_REPO_TAG%"=="false" set VERSION=0.1.0
|
||||
- if "%APPVEYOR_REPO_TAG%"=="false" if "%APPVEYOR_REPO_BRANCH%"=="master" set INSTVERSION=9999.0
|
||||
- if "%APPVEYOR_REPO_TAG%"=="false" set WINVERSION=%INSTVERSION%.0.%APPVEYOR_BUILD_NUMBER%
|
||||
# VERSION format: v1.2.3/v1.3.4
|
||||
# INSTVERSION format: 1.2.3/1.3.4
|
||||
# WINVERSION format: 1.2.3.123/1.3.4.234
|
||||
- if "%APPVEYOR_REPO_TAG%"=="true" set VERSION=%APPVEYOR_REPO_TAG_NAME%
|
||||
- if "%APPVEYOR_REPO_TAG%"=="true" set INSTVERSION=%VERSION:~1%
|
||||
- if "%APPVEYOR_REPO_TAG%"=="true" set WINVERSION=%VERSION:~1%.%APPVEYOR_BUILD_NUMBER%
|
||||
- set DATE=%date:~10,4%-%date:~4,2%-%date:~7,2%
|
||||
- echo %VERSION%
|
||||
- echo %INSTVERSION%
|
||||
- echo %DATE%
|
||||
- cmake -G "Visual Studio 14 2015 Win64" -H. -Bbuild -DAPPVEYOR_BUILD=ON -DCMAKE_BUILD_TYPE=Release
|
||||
- cmake --build build --config Release
|
||||
|
||||
after_build:
|
||||
# Variables
|
||||
- set BUILD=%APPVEYOR_BUILD_FOLDER%
|
||||
- echo %BUILD%
|
||||
- mkdir NhekoRelease
|
||||
- copy build\Release\nheko.exe NhekoRelease\nheko.exe
|
||||
- windeployqt --qmldir C:\Qt\5.8\msvc2015_64\qml\ --release NhekoRelease\nheko.exe
|
||||
@ -31,9 +49,58 @@ after_build:
|
||||
- copy C:\OpenSSL-Win64\lib\libeay32.lib .\NhekoRelease\libeay32.lib
|
||||
- copy C:\OpenSSL-Win64\bin\ssleay32.dll .\NhekoRelease\ssleay32.dll
|
||||
- 7z a nheko_win_64.zip .\NhekoRelease\*
|
||||
- C:\nsis\makensis .ci\windows\nheko.nsi
|
||||
- ls -lh build\Release\
|
||||
- ls -lh NhekoRelease\
|
||||
- mkdir NhekoData
|
||||
- xcopy .\NhekoRelease\*.* NhekoData\*.* /s /e /c /y
|
||||
#
|
||||
# Create the Qt Installer Framework version
|
||||
#
|
||||
- mkdir installer
|
||||
- mkdir installer\config
|
||||
- mkdir installer\packages
|
||||
- mkdir installer\packages\com.mujx.nheko
|
||||
- mkdir installer\packages\com.mujx.nheko\data
|
||||
- mkdir installer\packages\com.mujx.nheko\meta
|
||||
- mkdir installer\packages\com.mujx.nheko.cleanup\meta
|
||||
# Copy installer data
|
||||
- copy %BUILD%\resources\nheko.ico installer\config
|
||||
- copy %BUILD%\resources\nheko.png installer\config
|
||||
- copy %BUILD%\LICENSE installer\packages\com.mujx.nheko\meta\license.txt
|
||||
- copy %BUILD%\LICENSE installer\packages\com.mujx.nheko.cleanup\meta\license.txt
|
||||
- copy %BUILD%\deploy\installer\config.xml installer\config
|
||||
- copy %BUILD%\deploy\installer\controlscript.qs installer\config
|
||||
- copy %BUILD%\deploy\installer\uninstall.qs installer\packages\com.mujx.nheko\data
|
||||
- copy %BUILD%\deploy\installer\gui\package.xml installer\packages\com.mujx.nheko\meta
|
||||
- copy %BUILD%\deploy\installer\gui\installscript.qs installer\packages\com.mujx.nheko\meta
|
||||
- copy %BUILD%\deploy\installer\cleanup\package.xml installer\packages\com.mujx.nheko.cleanup\meta
|
||||
- copy %BUILD%\deploy\installer\cleanup\installscript.qs installer\packages\com.mujx.nheko.cleanup\meta
|
||||
# Amend version and date
|
||||
- sed -i "s/__VERSION__/0.1.0/" installer\config\config.xml
|
||||
- sed -i "s/__VERSION__/0.1.0/" installer\packages\com.mujx.nheko\meta\package.xml
|
||||
- sed -i "s/__VERSION__/0.1.0/" installer\packages\com.mujx.nheko.cleanup\meta\package.xml
|
||||
- sed -i "s/__DATE__/%DATE%/" installer\packages\com.mujx.nheko\meta\package.xml
|
||||
- sed -i "s/__DATE__/%DATE%/" installer\packages\com.mujx.nheko.cleanup\meta\package.xml
|
||||
# Copy nheko data
|
||||
- xcopy NhekoData\*.* installer\packages\com.mujx.nheko\data\*.* /s /e /c /y
|
||||
- move NhekoRelease\nheko.exe installer\packages\com.mujx.nheko\data
|
||||
- mkdir tools
|
||||
- curl -L -O https://download.qt.io/official_releases/qt-installer-framework/3.0.1/QtInstallerFramework-win-x86.exe
|
||||
- 7z x QtInstallerFramework-win-x86.exe -otools -aoa
|
||||
- set PATH=%BUILD%\tools\bin;%PATH%
|
||||
- binarycreator.exe -f -c installer\config\config.xml -p installer\packages nheko-installer.exe
|
||||
|
||||
deploy:
|
||||
description: "Development builds"
|
||||
provider: GitHub
|
||||
auth_token:
|
||||
secure: YqB7hcM+4482eSHhtVR7ZA7N7lE78y8BC897/7UDTBQd+NWdWFW/6S+oKDie9TT7
|
||||
artifact: nheko-installer.exe
|
||||
force_update: true
|
||||
prerelease: true
|
||||
on:
|
||||
appveyor_repo_tag: true
|
||||
|
||||
artifacts:
|
||||
- path: nheko_win_64.zip
|
||||
- path: NhekoRelease\nheko.exe
|
||||
- path: nheko_setup.exe
|
||||
- path: nheko-installer.exe
|
||||
|
36
cmake/MacOSXBundleInfo.plist.in
Normal file
36
cmake/MacOSXBundleInfo.plist.in
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleLongVersionString</key>
|
||||
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
|
||||
<key>CSResourcesFileMapped</key>
|
||||
<true/>
|
||||
<key>LSRequiresCarbon</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
76
cmake/QtCommon.cmake
Normal file
76
cmake/QtCommon.cmake
Normal file
@ -0,0 +1,76 @@
|
||||
macro(fix_project_version)
|
||||
if (NOT PROJECT_VERSION_PATCH)
|
||||
set(PROJECT_VERSION_PATCH 0)
|
||||
endif()
|
||||
|
||||
if (NOT PROJECT_VERSION_TWEAK)
|
||||
set(PROJECT_VERSION_TWEAK 0)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(add_project_meta FILES_TO_INCLUDE)
|
||||
if (NOT RESOURCE_FOLDER)
|
||||
set(RESOURCE_FOLDER resources)
|
||||
endif()
|
||||
|
||||
if (NOT ICON_NAME)
|
||||
set(ICON_NAME nheko)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
set(ICON_FILE ${RESOURCE_FOLDER}/${ICON_NAME}.icns)
|
||||
elseif (WIN32)
|
||||
set(ICON_FILE ${RESOURCE_FOLDER}/${ICON_NAME}.ico)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
configure_file("${PROJECT_SOURCE_DIR}/cmake/windows_metafile.rc.in"
|
||||
"windows_metafile.rc"
|
||||
)
|
||||
set(RES_FILES "windows_metafile.rc")
|
||||
set(CMAKE_RC_COMPILER_INIT windres)
|
||||
ENABLE_LANGUAGE(RC)
|
||||
SET(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> <FLAGS> -O coff <DEFINES> -i <SOURCE> -o <OBJECT>")
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
set_source_files_properties(${ICON_FILE} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
|
||||
# Identify MacOS bundle
|
||||
set(MACOSX_BUNDLE_BUNDLE_NAME ${PROJECT_NAME})
|
||||
set(MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION})
|
||||
set(MACOSX_BUNDLE_LONG_VERSION_STRING ${PROJECT_VERSION})
|
||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
|
||||
set(MACOSX_BUNDLE_COPYRIGHT ${COPYRIGHT})
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER ${IDENTIFIER})
|
||||
set(MACOSX_BUNDLE_ICON_FILE ${ICON_NAME})
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
set(${FILES_TO_INCLUDE} ${ICON_FILE})
|
||||
elseif (WIN32)
|
||||
set(${FILES_TO_INCLUDE} ${RES_FILES})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(init_os_bundle)
|
||||
if (APPLE)
|
||||
set(OS_BUNDLE MACOSX_BUNDLE)
|
||||
elseif (WIN32)
|
||||
IF(CMAKE_BUILD_TYPE MATCHES Release)
|
||||
set(OS_BUNDLE WIN32)
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(fix_win_compiler)
|
||||
if (MSVC)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
WIN32_EXECUTABLE YES
|
||||
LINK_FLAGS "/ENTRY:mainCRTStartup"
|
||||
)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
init_os_bundle()
|
||||
fix_win_compiler()
|
28
cmake/windows_metafile.rc.in
Normal file
28
cmake/windows_metafile.rc.in
Normal file
@ -0,0 +1,28 @@
|
||||
#include "winver.h"
|
||||
|
||||
IDI_ICON1 ICON DISCARDABLE "@ICON_FILE@"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,@PROJECT_VERSION_TWEAK@
|
||||
PRODUCTVERSION @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,@PROJECT_VERSION_TWEAK@
|
||||
FILEFLAGS 0x0L
|
||||
FILEFLAGSMASK 0x3fL
|
||||
FILEOS 0x00040004L
|
||||
FILETYPE 0x1L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "000004b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "@COMPANY@"
|
||||
VALUE "FileDescription", "@PROJECT_NAME@"
|
||||
VALUE "FileVersion", "@PROJECT_VERSION@"
|
||||
VALUE "LegalCopyright", "@COPYRIGHT@"
|
||||
VALUE "InternalName", "@PROJECT_NAME@"
|
||||
VALUE "OriginalFilename", "@PROJECT_NAME@.exe"
|
||||
VALUE "ProductName", "@PROJECT_NAME@"
|
||||
VALUE "ProductVersion", "@PROJECT_VERSION@"
|
||||
END
|
||||
END
|
||||
END
|
28
deploy/installer/cleanup/installscript.qs
Normal file
28
deploy/installer/cleanup/installscript.qs
Normal file
@ -0,0 +1,28 @@
|
||||
function Component()
|
||||
{
|
||||
}
|
||||
|
||||
Component.prototype.createOperations = function()
|
||||
{
|
||||
component.createOperations();
|
||||
|
||||
try
|
||||
{
|
||||
if( installer.value("os") === "win" )
|
||||
{
|
||||
/**
|
||||
* Cleanup AppData and registry
|
||||
*/
|
||||
component.addElevatedOperation("Execute","UNDOEXECUTE","cmd /C reg delete HKEY_CURRENT_USER\Software\nheko\nheko /f");
|
||||
var localappdata = installer.environmentVariable("LOCALAPPDATA");
|
||||
if( localappdata != "" )
|
||||
{
|
||||
component.addElevatedOperation("Execute","UNDOEXECUTE","cmd /C rmdir "+localappdata+"\nheko /f");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( e )
|
||||
{
|
||||
print( e );
|
||||
}
|
||||
}
|
10
deploy/installer/cleanup/package.xml
Normal file
10
deploy/installer/cleanup/package.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Package>
|
||||
<DisplayName>Cleanup AppData and Registry</DisplayName>
|
||||
<Description>Cleans up AppData and Registry when selected (logs you out) - Broken</Description>
|
||||
<Version>__VERSION__</Version>
|
||||
<ReleaseDate>__DATE__</ReleaseDate>
|
||||
<SortingPriority>80</SortingPriority>
|
||||
<Script>installscript.qs</Script>
|
||||
<Checkable>false</Checkable>
|
||||
</Package>
|
15
deploy/installer/config.xml
Normal file
15
deploy/installer/config.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Installer>
|
||||
<Name>Nheko</Name>
|
||||
<Version>__VERSION__</Version>
|
||||
<Title>Nheko Installer</Title>
|
||||
<Publisher>Mujx</Publisher>
|
||||
<ProductUrl>https://github.com/mujx/nheko</ProductUrl>
|
||||
<InstallerWindowIcon>nheko</InstallerWindowIcon>
|
||||
<InstallerApplicationIcon>nheko</InstallerApplicationIcon>
|
||||
<Logo>nheko.png</Logo>
|
||||
<StartMenuDir>Nheko</StartMenuDir>
|
||||
<TargetDir>@ApplicationsDir@/nheko</TargetDir>
|
||||
<RunProgram>@TargetDir@/nheko.exe</RunProgram>
|
||||
<ControlScript>controlscript.qs</ControlScript>
|
||||
</Installer>
|
25
deploy/installer/controlscript.qs
Normal file
25
deploy/installer/controlscript.qs
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Source: http://stackoverflow.com/questions/21389105/qt-installer-framework-offline-update-how
|
||||
*/
|
||||
|
||||
function Controller()
|
||||
{
|
||||
}
|
||||
|
||||
Controller.prototype.TargetDirectoryPageCallback = function()
|
||||
{
|
||||
var widget = gui.currentPageWidget();
|
||||
widget.TargetDirectoryLineEdit.textChanged.connect( this, Controller.prototype.targetChanged );
|
||||
Controller.prototype.targetChanged( widget.TargetDirectoryLineEdit.text );
|
||||
}
|
||||
|
||||
Controller.prototype.targetChanged = function( text )
|
||||
{
|
||||
if( text != "" && installer.fileExists(text + "/components.xml") )
|
||||
{
|
||||
if( QMessageBox.question("PreviousInstallation", "Previous installation detected", "Do you want to uninstall the previous installation?", QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes )
|
||||
{
|
||||
installer.execute( text+"/maintenancetool.exe", new Array("--script", text+"/uninstall.qs") )
|
||||
}
|
||||
}
|
||||
}
|
32
deploy/installer/gui/installscript.qs
Normal file
32
deploy/installer/gui/installscript.qs
Normal file
@ -0,0 +1,32 @@
|
||||
function Component()
|
||||
{
|
||||
}
|
||||
|
||||
Component.prototype.createOperations = function()
|
||||
{
|
||||
component.createOperations();
|
||||
|
||||
try
|
||||
{
|
||||
if( installer.value("os") === "win" )
|
||||
{
|
||||
/**
|
||||
* Start Menu Shortcut
|
||||
*/
|
||||
component.addOperation( "CreateShortcut", "@TargetDir@\\nheko.exe", "@StartMenuDir@\\nheko.lnk",
|
||||
"workingDirectory=@TargetDir@", "iconPath=@TargetDir@\\nheko.exe",
|
||||
"iconId=0", "description=Desktop client for the Matrix protocol");
|
||||
|
||||
/**
|
||||
* Desktop Shortcut
|
||||
*/
|
||||
component.addOperation( "CreateShortcut", "@TargetDir@\\nheko.exe", "@DesktopDir@\\nheko.lnk",
|
||||
"workingDirectory=@TargetDir@", "iconPath=@TargetDir@\\nheko.exe",
|
||||
"iconId=0", "description=Desktop client for the Matrix protocol");
|
||||
}
|
||||
}
|
||||
catch( e )
|
||||
{
|
||||
print( e );
|
||||
}
|
||||
}
|
14
deploy/installer/gui/package.xml
Normal file
14
deploy/installer/gui/package.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Package>
|
||||
<DisplayName>Nheko</DisplayName>
|
||||
<Description>Desktop client for the Matrix protocol</Description>
|
||||
<Version>__VERSION__</Version>
|
||||
<ReleaseDate>__DATE__</ReleaseDate>
|
||||
<Licenses>
|
||||
<License name="Nheko License - GPLv3" file="license.txt" />
|
||||
</Licenses>
|
||||
<Default>true</Default>
|
||||
<ForcedInstallation>true</ForcedInstallation>
|
||||
<SortingPriority>100</SortingPriority>
|
||||
<Script>installscript.qs</Script>
|
||||
</Package>
|
18
deploy/installer/uninstall.qs
Normal file
18
deploy/installer/uninstall.qs
Normal file
@ -0,0 +1,18 @@
|
||||
function Controller()
|
||||
{
|
||||
}
|
||||
|
||||
Controller.prototype.IntroductionPageCallback = function()
|
||||
{
|
||||
gui.clickButton( buttons.NextButton );
|
||||
}
|
||||
|
||||
Controller.prototype.ReadyForInstallationPageCallback = function()
|
||||
{
|
||||
gui.clickButton( buttons.CommitButton );
|
||||
}
|
||||
|
||||
Controller.prototype.FinishedPageCallback = function()
|
||||
{
|
||||
gui.clickButton( buttons.FinishButton );
|
||||
}
|
33
dist/MacOS/nheko.app/Contents/Info.plist
vendored
33
dist/MacOS/nheko.app/Contents/Info.plist
vendored
@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
|
||||
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Nheko</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>nheko</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>nheko</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Nheko</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>nheko.icns</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.1.0</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true />
|
||||
<key>NSMainNibFile</key>
|
||||
<string></string>
|
||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||
<true />
|
||||
</dict>
|
||||
</plist>
|
BIN
dist/MacOS/nheko.app/Contents/Resources/nheko.icns
vendored
BIN
dist/MacOS/nheko.app/Contents/Resources/nheko.icns
vendored
Binary file not shown.
@ -17,6 +17,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMap>
|
||||
#include <QPixmap>
|
||||
@ -47,8 +48,9 @@ class UserInfoWidget;
|
||||
class JoinedRoom;
|
||||
class LeftRoom;
|
||||
|
||||
constexpr int CONSENSUS_TIMEOUT = 1000;
|
||||
constexpr int SHOW_CONTENT_TIMEOUT = 3000;
|
||||
constexpr int CONSENSUS_TIMEOUT = 1000;
|
||||
constexpr int SHOW_CONTENT_TIMEOUT = 3000;
|
||||
constexpr int TYPING_REFRESH_TIMEOUT = 10000;
|
||||
|
||||
class ChatPage : public QWidget
|
||||
{
|
||||
@ -69,6 +71,7 @@ signals:
|
||||
void unreadMessages(int count);
|
||||
void showNotification(const QString &msg);
|
||||
void showLoginPage(const QString &msg);
|
||||
void showUserSettingsPage();
|
||||
|
||||
private slots:
|
||||
void showUnreadMessageNotification(int count);
|
||||
@ -119,10 +122,8 @@ private:
|
||||
QWidget *sideBarTopWidget_;
|
||||
QVBoxLayout *sideBarTopWidgetLayout_;
|
||||
|
||||
QWidget *content_;
|
||||
QFrame *content_;
|
||||
QVBoxLayout *contentLayout_;
|
||||
QHBoxLayout *topBarLayout_;
|
||||
QVBoxLayout *mainContentLayout_;
|
||||
|
||||
CommunitiesList *communitiesList_;
|
||||
RoomList *room_list_;
|
||||
@ -153,6 +154,7 @@ private:
|
||||
|
||||
// Keeps track of the users currently typing on each room.
|
||||
QMap<QString, QList<QString>> typingUsers_;
|
||||
QTimer *typingRefresher_;
|
||||
|
||||
QSharedPointer<QuickSwitcher> quickSwitcher_;
|
||||
QSharedPointer<OverlayModal> quickSwitcherModal_;
|
||||
|
@ -30,6 +30,8 @@ class OverlayModal;
|
||||
class RegisterPage;
|
||||
class SnackBar;
|
||||
class TrayIcon;
|
||||
class UserSettingsPage;
|
||||
class UserSettings;
|
||||
class WelcomePage;
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
@ -59,6 +61,7 @@ private slots:
|
||||
|
||||
// Show the register page in the main window.
|
||||
void showRegisterPage();
|
||||
void showUserSettingsPage();
|
||||
|
||||
// Show the chat page and start communicating with the given access token.
|
||||
void showChatPage(QString user_id, QString home_server, QString token);
|
||||
@ -85,6 +88,8 @@ private:
|
||||
|
||||
// The main chat area.
|
||||
ChatPage *chat_page_;
|
||||
UserSettingsPage *userSettingsPage_;
|
||||
QSharedPointer<UserSettings> userSettings_;
|
||||
|
||||
// Used to hide undefined states between page transitions.
|
||||
QSharedPointer<OverlayModal> progressModal_;
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QUrl>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include "MessageEvent.h"
|
||||
|
||||
@ -40,8 +41,10 @@ public:
|
||||
void initialSync() noexcept;
|
||||
void sync() noexcept;
|
||||
void sendRoomMessage(matrix::events::MessageEventType ty,
|
||||
int txnId,
|
||||
const QString &roomid,
|
||||
const QString &msg,
|
||||
const QFileInfo &fileinfo,
|
||||
const QString &url = "") noexcept;
|
||||
void login(const QString &username, const QString &password) noexcept;
|
||||
void registerUser(const QString &username,
|
||||
@ -59,10 +62,12 @@ public:
|
||||
void uploadImage(const QString &roomid, const QString &filename);
|
||||
void joinRoom(const QString &roomIdOrAlias);
|
||||
void leaveRoom(const QString &roomId);
|
||||
void sendTypingNotification(const QString &roomid, int timeoutInMillis = 20000);
|
||||
void removeTypingNotification(const QString &roomid);
|
||||
|
||||
QUrl getHomeServer() { return server_; };
|
||||
int transactionId() { return txn_id_; };
|
||||
void incrementTransactionId() { txn_id_ += 1; };
|
||||
int incrementTransactionId() { return ++txn_id_; };
|
||||
|
||||
void reset() noexcept;
|
||||
|
||||
@ -109,6 +114,7 @@ signals:
|
||||
void syncFailed(const QString &msg);
|
||||
void joinFailed(const QString &msg);
|
||||
void messageSent(const QString &event_id, const QString &roomid, const int txn_id);
|
||||
void messageSendFailed(const QString &roomid, const int txn_id);
|
||||
void emoteSent(const QString &event_id, const QString &roomid, const int txn_id);
|
||||
void messagesRetrieved(const QString &room_id, const RoomMessages &msgs);
|
||||
void joinedRoom(const QString &room_id);
|
||||
|
@ -14,6 +14,9 @@ public:
|
||||
SideBarActions(QWidget *parent = nullptr);
|
||||
~SideBarActions();
|
||||
|
||||
signals:
|
||||
void showSettings();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QPaintEvent>
|
||||
#include <QTextEdit>
|
||||
@ -29,18 +31,36 @@
|
||||
|
||||
namespace msgs = matrix::events::messages;
|
||||
|
||||
static const QString EMOTE_COMMAND("/me ");
|
||||
static const QString JOIN_COMMAND("/join ");
|
||||
|
||||
class FilteredTextEdit : public QTextEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FilteredTextEdit(QWidget *parent = nullptr);
|
||||
void keyPressEvent(QKeyEvent *event);
|
||||
|
||||
void stopTyping();
|
||||
|
||||
QSize sizeHint() const override;
|
||||
QSize minimumSizeHint() const override;
|
||||
|
||||
void submit();
|
||||
|
||||
signals:
|
||||
void enterPressed();
|
||||
void startedTyping();
|
||||
void stoppedTyping();
|
||||
void message(QString);
|
||||
void command(QString name, QString args);
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
|
||||
private:
|
||||
std::deque<QString> true_history_, working_history_;
|
||||
size_t history_index_;
|
||||
QTimer *typingTimer_;
|
||||
|
||||
void textChanged();
|
||||
void afterCompletion(int);
|
||||
};
|
||||
|
||||
class TextInputWidget : public QFrame
|
||||
@ -51,8 +71,9 @@ public:
|
||||
TextInputWidget(QWidget *parent = 0);
|
||||
~TextInputWidget();
|
||||
|
||||
void stopTyping();
|
||||
|
||||
public slots:
|
||||
void onSendButtonClicked();
|
||||
void openFileSelection();
|
||||
void hideUploadSpinner();
|
||||
void focusLineEdit() { input_->setFocus(); };
|
||||
@ -66,10 +87,15 @@ signals:
|
||||
void uploadImage(QString filename);
|
||||
void sendJoinRoomRequest(const QString &room);
|
||||
|
||||
void startedTyping();
|
||||
void stoppedTyping();
|
||||
|
||||
protected:
|
||||
void focusInEvent(QFocusEvent *event);
|
||||
|
||||
private:
|
||||
void showUploadSpinner();
|
||||
QString parseEmoteCommand(const QString &cmd);
|
||||
QString parseJoinCommand(const QString &cmd);
|
||||
void command(QString name, QString args);
|
||||
|
||||
QHBoxLayout *topLayout_;
|
||||
FilteredTextEdit *input_;
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include <QLayout>
|
||||
#include <QList>
|
||||
#include <QQueue>
|
||||
#include <QScrollArea>
|
||||
|
||||
#include "Emote.h"
|
||||
@ -42,18 +43,26 @@ namespace events = matrix::events;
|
||||
// but not yet confirmed by the homeserver through sync.
|
||||
struct PendingMessage
|
||||
{
|
||||
matrix::events::MessageEventType ty;
|
||||
int txn_id;
|
||||
QString body;
|
||||
QString filename;
|
||||
QString event_id;
|
||||
TimelineItem *widget;
|
||||
|
||||
PendingMessage(int txn_id, QString body, QString event_id, TimelineItem *widget)
|
||||
: txn_id(txn_id)
|
||||
PendingMessage(matrix::events::MessageEventType ty,
|
||||
int txn_id,
|
||||
QString body,
|
||||
QString filename,
|
||||
QString event_id,
|
||||
TimelineItem *widget)
|
||||
: ty(ty)
|
||||
, txn_id(txn_id)
|
||||
, body(body)
|
||||
, filename(filename)
|
||||
, event_id(event_id)
|
||||
, widget(widget)
|
||||
{
|
||||
}
|
||||
{}
|
||||
};
|
||||
|
||||
// In which place new TimelineItems should be inserted.
|
||||
@ -87,8 +96,8 @@ public:
|
||||
|
||||
// Add new events at the end of the timeline.
|
||||
int addEvents(const Timeline &timeline);
|
||||
void addUserMessage(matrix::events::MessageEventType ty, const QString &msg, int txn_id);
|
||||
void addUserMessage(const QString &url, const QString &filename, int txn_id);
|
||||
void addUserMessage(matrix::events::MessageEventType ty, const QString &msg);
|
||||
void addUserMessage(const QString &url, const QString &filename);
|
||||
void updatePendingMessage(int txn_id, QString event_id);
|
||||
void scrollDown();
|
||||
|
||||
@ -103,6 +112,11 @@ public slots:
|
||||
// Whether or not the initial batch has been loaded.
|
||||
bool hasLoaded() { return scroll_layout_->count() > 1 || isTimelineFinished; };
|
||||
|
||||
void handleFailedMessage(int txnid);
|
||||
|
||||
private slots:
|
||||
void sendNextPendingMessage();
|
||||
|
||||
signals:
|
||||
void updateLastTimelineMessage(const QString &user, const DescInfo &info);
|
||||
|
||||
@ -116,13 +130,11 @@ private:
|
||||
// sender's name.
|
||||
bool isSenderRendered(const QString &user_id, TimelineDirection direction);
|
||||
|
||||
bool isPendingMessage(const QString &eventid,
|
||||
const QString &body,
|
||||
const QString &sender,
|
||||
const QString &userid);
|
||||
void removePendingMessage(const QString &eventid, const QString &body);
|
||||
bool isPendingMessage(const QString &txnid, const QString &sender, const QString &userid);
|
||||
void removePendingMessage(const QString &txnid);
|
||||
|
||||
bool isDuplicate(const QString &event_id) { return eventIds_.contains(event_id); };
|
||||
void handleNewUserMessage(PendingMessage msg);
|
||||
|
||||
// Return nullptr if the event couldn't be parsed.
|
||||
TimelineItem *parseMessageEvent(const QJsonObject &event, TimelineDirection direction);
|
||||
@ -163,6 +175,7 @@ private:
|
||||
|
||||
// The events currently rendered. Used for duplicate detection.
|
||||
QMap<QString, bool> eventIds_;
|
||||
QList<PendingMessage> pending_msgs_;
|
||||
QQueue<PendingMessage> pending_msgs_;
|
||||
QList<PendingMessage> pending_sent_msgs_;
|
||||
QSharedPointer<MatrixClient> client_;
|
||||
};
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include <QSharedPointer>
|
||||
#include <QStackedWidget>
|
||||
|
||||
#include "MessageEvent.h"
|
||||
|
||||
class JoinedRoom;
|
||||
class MatrixClient;
|
||||
class RoomInfoListItem;
|
||||
@ -61,12 +63,13 @@ signals:
|
||||
|
||||
public slots:
|
||||
void setHistoryView(const QString &room_id);
|
||||
void sendTextMessage(const QString &msg);
|
||||
void sendEmoteMessage(const QString &msg);
|
||||
void sendImageMessage(const QString &roomid, const QString &filename, const QString &url);
|
||||
void queueTextMessage(const QString &msg);
|
||||
void queueEmoteMessage(const QString &msg);
|
||||
void queueImageMessage(const QString &roomid, const QString &filename, const QString &url);
|
||||
|
||||
private slots:
|
||||
void messageSent(const QString &eventid, const QString &roomid, int txnid);
|
||||
void messageSendFailed(const QString &roomid, int txnid);
|
||||
|
||||
private:
|
||||
QString active_room_;
|
||||
|
86
include/UserSettingsPage.h
Normal file
86
include/UserSettingsPage.h
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QFrame>
|
||||
#include <QLayout>
|
||||
#include <QSharedPointer>
|
||||
#include <QWidget>
|
||||
|
||||
class Toggle;
|
||||
|
||||
constexpr int OptionMargin = 6;
|
||||
constexpr int LayoutTopMargin = 50;
|
||||
constexpr int LayoutBottomMargin = LayoutTopMargin;
|
||||
|
||||
class UserSettings
|
||||
{
|
||||
public:
|
||||
UserSettings();
|
||||
|
||||
void save();
|
||||
void load();
|
||||
void setTheme(QString theme) { theme_ = theme; }
|
||||
void setTray(bool state) { isTrayEnabled_ = state; }
|
||||
|
||||
QString theme() const { return !theme_.isEmpty() ? theme_ : "default"; }
|
||||
bool isTrayEnabled() const { return isTrayEnabled_; }
|
||||
|
||||
private:
|
||||
QString theme_;
|
||||
bool isTrayEnabled_;
|
||||
};
|
||||
|
||||
class HorizontalLine : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
HorizontalLine(QWidget *parent = nullptr);
|
||||
};
|
||||
|
||||
class UserSettingsPage : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
UserSettingsPage(QSharedPointer<UserSettings> settings, QWidget *parent = 0);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
signals:
|
||||
void moveBack();
|
||||
void trayOptionChanged(bool value);
|
||||
|
||||
private:
|
||||
// Layouts
|
||||
QVBoxLayout *topLayout_;
|
||||
QVBoxLayout *mainLayout_;
|
||||
QHBoxLayout *topBarLayout_;
|
||||
|
||||
// Shared settings object.
|
||||
QSharedPointer<UserSettings> settings_;
|
||||
|
||||
Toggle *trayToggle_;
|
||||
QComboBox *themeCombo_;
|
||||
|
||||
int sideMargin_ = 0;
|
||||
};
|
@ -60,12 +60,31 @@ isMessageEvent(EventType type);
|
||||
bool
|
||||
isStateEvent(EventType type);
|
||||
|
||||
class UnsignedData
|
||||
: public Deserializable
|
||||
, public Serializable
|
||||
{
|
||||
public:
|
||||
double age() const { return age_; }
|
||||
QString transactionId() const { return transaction_id_; }
|
||||
|
||||
bool isEmpty() const { return age_ <= 0 && transaction_id_.isEmpty(); }
|
||||
|
||||
void deserialize(const QJsonValue &data) override;
|
||||
QJsonObject serialize() const override;
|
||||
|
||||
private:
|
||||
double age_ = 0;
|
||||
QString transaction_id_;
|
||||
};
|
||||
|
||||
template<class Content>
|
||||
class Event : public Deserializable, public Serializable
|
||||
{
|
||||
public:
|
||||
Content content() const;
|
||||
EventType eventType() const;
|
||||
UnsignedData unsignedData() const { return unsignedData_; }
|
||||
|
||||
void deserialize(const QJsonValue &data) override;
|
||||
QJsonObject serialize() const override;
|
||||
@ -73,6 +92,7 @@ public:
|
||||
private:
|
||||
Content content_;
|
||||
EventType type_;
|
||||
UnsignedData unsignedData_;
|
||||
};
|
||||
|
||||
template<class Content>
|
||||
@ -100,6 +120,9 @@ Event<Content>::deserialize(const QJsonValue &data)
|
||||
|
||||
content_.deserialize(object.value("content"));
|
||||
type_ = extractEventType(object);
|
||||
|
||||
if (object.contains("unsigned"))
|
||||
unsignedData_.deserialize(object.value("unsigned"));
|
||||
}
|
||||
|
||||
template<class Content>
|
||||
@ -149,6 +172,9 @@ Event<Content>::serialize() const
|
||||
|
||||
object["content"] = content_.serialize();
|
||||
|
||||
if (!unsignedData_.isEmpty())
|
||||
object["unsigned"] = unsignedData_.serialize();
|
||||
|
||||
return object;
|
||||
}
|
||||
} // namespace events
|
||||
|
@ -12,8 +12,7 @@ enum class AvatarType
|
||||
Letter
|
||||
};
|
||||
|
||||
namespace sidebar
|
||||
{
|
||||
namespace sidebar {
|
||||
static const int SmallSize = 60;
|
||||
static const int NormalSize = 300;
|
||||
static const int CommunitiesSidebarSize = 64;
|
||||
|
110
include/ui/ToggleButton.h
Normal file
110
include/ui/ToggleButton.h
Normal file
@ -0,0 +1,110 @@
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractButton>
|
||||
#include <QColor>
|
||||
|
||||
class ToggleTrack;
|
||||
class ToggleThumb;
|
||||
|
||||
enum class Position
|
||||
{
|
||||
Left,
|
||||
Right
|
||||
};
|
||||
|
||||
class Toggle : public QAbstractButton
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QColor activeColor WRITE setActiveColor READ activeColor)
|
||||
Q_PROPERTY(QColor disabledColor WRITE setDisabledColor READ disabledColor)
|
||||
Q_PROPERTY(QColor inactiveColor WRITE setInactiveColor READ inactiveColor)
|
||||
Q_PROPERTY(QColor trackColor WRITE setTrackColor READ trackColor)
|
||||
|
||||
public:
|
||||
Toggle(QWidget *parent = nullptr);
|
||||
|
||||
void setState(bool isEnabled);
|
||||
|
||||
void setActiveColor(const QColor &color);
|
||||
void setDisabledColor(const QColor &color);
|
||||
void setInactiveColor(const QColor &color);
|
||||
void setTrackColor(const QColor &color);
|
||||
|
||||
QColor activeColor() const { return activeColor_; };
|
||||
QColor disabledColor() const { return disabledColor_; };
|
||||
QColor inactiveColor() const { return inactiveColor_; };
|
||||
QColor trackColor() const { return trackColor_.isValid() ? trackColor_ : QColor("#eee"); };
|
||||
|
||||
QSize sizeHint() const override { return QSize(64, 48); };
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
void init();
|
||||
void setupProperties();
|
||||
|
||||
ToggleTrack *track_;
|
||||
ToggleThumb *thumb_;
|
||||
|
||||
QColor disabledColor_;
|
||||
QColor activeColor_;
|
||||
QColor inactiveColor_;
|
||||
QColor trackColor_;
|
||||
};
|
||||
|
||||
class ToggleThumb : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QColor thumbColor WRITE setThumbColor READ thumbColor)
|
||||
|
||||
public:
|
||||
ToggleThumb(Toggle *parent);
|
||||
|
||||
Position shift() const { return position_; };
|
||||
qreal offset() const { return offset_; };
|
||||
QColor thumbColor() const { return thumbColor_; };
|
||||
|
||||
void setShift(Position position);
|
||||
void setThumbColor(const QColor &color)
|
||||
{
|
||||
thumbColor_ = color;
|
||||
update();
|
||||
};
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
void updateOffset();
|
||||
|
||||
Toggle *const toggle_;
|
||||
QColor thumbColor_;
|
||||
|
||||
Position position_;
|
||||
qreal offset_;
|
||||
};
|
||||
|
||||
class ToggleTrack : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QColor trackColor WRITE setTrackColor READ trackColor)
|
||||
|
||||
public:
|
||||
ToggleTrack(Toggle *parent);
|
||||
|
||||
void setTrackColor(const QColor &color);
|
||||
QColor trackColor() const { return trackColor_; };
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
Toggle *const toggle_;
|
||||
QColor trackColor_;
|
||||
};
|
10
src/Cache.cc
10
src/Cache.cc
@ -31,11 +31,11 @@ static const lmdb::val NEXT_BATCH_KEY("next_batch");
|
||||
static const lmdb::val transactionID("transaction_id");
|
||||
|
||||
Cache::Cache(const QString &userId)
|
||||
: env_{ nullptr }
|
||||
, stateDb_{ 0 }
|
||||
, roomDb_{ 0 }
|
||||
, isMounted_{ false }
|
||||
, userId_{ userId }
|
||||
: env_{nullptr}
|
||||
, stateDb_{0}
|
||||
, roomDb_{0}
|
||||
, isMounted_{false}
|
||||
, userId_{userId}
|
||||
{}
|
||||
|
||||
void
|
||||
|
@ -72,8 +72,8 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||
topLayout_->addWidget(splitter);
|
||||
|
||||
// SideBar
|
||||
sideBar_ = new QWidget(this);
|
||||
sideBar_->setMinimumSize(QSize(ui::sidebar::NormalSize, 0));
|
||||
sideBar_ = new QFrame(this);
|
||||
sideBar_->setMinimumSize(QSize(ui::sidebar::NormalSize, parent->height()));
|
||||
sideBarLayout_ = new QVBoxLayout(sideBar_);
|
||||
sideBarLayout_->setSpacing(0);
|
||||
sideBarLayout_->setMargin(0);
|
||||
@ -93,40 +93,33 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||
|
||||
sideBarTopWidget_ = new QWidget(sideBar_);
|
||||
sideBarTopWidget_->setStyleSheet("background-color: #d6dde3; color: #ebebeb;");
|
||||
sidebarActions_ = new SideBarActions(this);
|
||||
connect(
|
||||
sidebarActions_, &SideBarActions::showSettings, this, &ChatPage::showUserSettingsPage);
|
||||
|
||||
sideBarTopLayout_->addWidget(sideBarTopWidget_);
|
||||
user_info_widget_ = new UserInfoWidget(sideBar_);
|
||||
room_list_ = new RoomList(client, sideBar_);
|
||||
|
||||
sideBarTopWidgetLayout_ = new QVBoxLayout(sideBarTopWidget_);
|
||||
sideBarTopWidgetLayout_->setSpacing(0);
|
||||
sideBarTopWidgetLayout_->setMargin(0);
|
||||
sideBarLayout_->addWidget(user_info_widget_);
|
||||
sideBarLayout_->addWidget(room_list_);
|
||||
sideBarLayout_->addWidget(sidebarActions_);
|
||||
|
||||
// Content
|
||||
content_ = new QWidget(this);
|
||||
content_ = new QFrame(this);
|
||||
contentLayout_ = new QVBoxLayout(content_);
|
||||
contentLayout_->setSpacing(0);
|
||||
contentLayout_->setMargin(0);
|
||||
|
||||
topBarLayout_ = new QHBoxLayout();
|
||||
topBarLayout_->setSpacing(0);
|
||||
mainContentLayout_ = new QVBoxLayout();
|
||||
mainContentLayout_->setSpacing(0);
|
||||
mainContentLayout_->setMargin(0);
|
||||
top_bar_ = new TopRoomBar(this);
|
||||
view_manager_ = new TimelineViewManager(client, this);
|
||||
|
||||
contentLayout_->addLayout(topBarLayout_);
|
||||
contentLayout_->addLayout(mainContentLayout_);
|
||||
contentLayout_->addWidget(top_bar_);
|
||||
contentLayout_->addWidget(view_manager_);
|
||||
|
||||
// Splitter
|
||||
splitter->addWidget(sideBar_);
|
||||
splitter->addWidget(content_);
|
||||
|
||||
room_list_ = new RoomList(client, sideBar_);
|
||||
sideBarMainLayout_->addWidget(room_list_);
|
||||
|
||||
top_bar_ = new TopRoomBar(this);
|
||||
topBarLayout_->addWidget(top_bar_);
|
||||
|
||||
view_manager_ = new TimelineViewManager(client, this);
|
||||
mainContentLayout_->addWidget(view_manager_);
|
||||
splitter->setSizes({ui::sidebar::NormalSize, parent->width() - ui::sidebar::NormalSize});
|
||||
|
||||
text_input_ = new TextInputWidget(this);
|
||||
typingDisplay_ = new TypingDisplay(this);
|
||||
@ -135,6 +128,8 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||
|
||||
user_info_widget_ = new UserInfoWidget(sideBarTopWidget_);
|
||||
sideBarTopWidgetLayout_->addWidget(user_info_widget_);
|
||||
typingRefresher_ = new QTimer(this);
|
||||
typingRefresher_->setInterval(TYPING_REFRESH_TIMEOUT);
|
||||
|
||||
connect(user_info_widget_, SIGNAL(logout()), client_.data(), SLOT(logout()));
|
||||
connect(client_.data(), SIGNAL(loggedOut()), this, SLOT(logout()));
|
||||
@ -150,6 +145,7 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||
|
||||
typingDisplay_->setUsers(users);
|
||||
});
|
||||
connect(room_list_, &RoomList::roomChanged, text_input_, &TextInputWidget::stopTyping);
|
||||
|
||||
connect(room_list_, &RoomList::roomChanged, this, &ChatPage::changeTopRoomInfo);
|
||||
connect(room_list_, &RoomList::roomChanged, text_input_, &TextInputWidget::focusLineEdit);
|
||||
@ -170,6 +166,20 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||
room_list_->updateUnreadMessageCount(roomid, count);
|
||||
});
|
||||
|
||||
connect(text_input_, &TextInputWidget::startedTyping, this, [=]() {
|
||||
typingRefresher_->start();
|
||||
client_->sendTypingNotification(current_room_);
|
||||
});
|
||||
|
||||
connect(text_input_, &TextInputWidget::stoppedTyping, this, [=]() {
|
||||
typingRefresher_->stop();
|
||||
client_->removeTypingNotification(current_room_);
|
||||
});
|
||||
|
||||
connect(typingRefresher_, &QTimer::timeout, this, [=]() {
|
||||
client_->sendTypingNotification(current_room_);
|
||||
});
|
||||
|
||||
connect(view_manager_,
|
||||
&TimelineViewManager::updateRoomsLastMessage,
|
||||
room_list_,
|
||||
@ -183,12 +193,12 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||
connect(text_input_,
|
||||
SIGNAL(sendTextMessage(const QString &)),
|
||||
view_manager_,
|
||||
SLOT(sendTextMessage(const QString &)));
|
||||
SLOT(queueTextMessage(const QString &)));
|
||||
|
||||
connect(text_input_,
|
||||
SIGNAL(sendEmoteMessage(const QString &)),
|
||||
view_manager_,
|
||||
SLOT(sendEmoteMessage(const QString &)));
|
||||
SLOT(queueEmoteMessage(const QString &)));
|
||||
|
||||
connect(text_input_,
|
||||
&TextInputWidget::sendJoinRoomRequest,
|
||||
@ -205,7 +215,7 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||
this,
|
||||
[=](QString roomid, QString filename, QString url) {
|
||||
text_input_->hideUploadSpinner();
|
||||
view_manager_->sendImageMessage(roomid, filename, url);
|
||||
view_manager_->queueImageMessage(roomid, filename, url);
|
||||
});
|
||||
|
||||
connect(client_.data(),
|
||||
@ -604,6 +614,7 @@ ChatPage::showQuickSwitcher()
|
||||
connect(quickSwitcher_.data(), &QuickSwitcher::closing, this, [=]() {
|
||||
if (!this->quickSwitcherModal_.isNull())
|
||||
this->quickSwitcherModal_->fadeOut();
|
||||
this->text_input_->setFocus(Qt::FocusReason::PopupFocusReason);
|
||||
});
|
||||
}
|
||||
|
||||
@ -617,8 +628,12 @@ ChatPage::showQuickSwitcher()
|
||||
|
||||
QMap<QString, QString> rooms;
|
||||
|
||||
for (auto it = state_manager_.constBegin(); it != state_manager_.constEnd(); ++it)
|
||||
rooms.insert(it.value().getName(), it.key());
|
||||
for (auto it = state_manager_.constBegin(); it != state_manager_.constEnd(); ++it) {
|
||||
QString deambiguator = it.value().canonical_alias.content().alias();
|
||||
if (deambiguator == "")
|
||||
deambiguator = it.key();
|
||||
rooms.insert(it.value().getName() + " (" + deambiguator + ")", it.key());
|
||||
}
|
||||
|
||||
quickSwitcher_->setRoomList(rooms);
|
||||
quickSwitcherModal_->fadeIn();
|
||||
@ -662,13 +677,20 @@ ChatPage::updateTypingUsers(const QString &roomid, const QList<QString> &user_id
|
||||
{
|
||||
QStringList users;
|
||||
|
||||
for (const auto uid : user_ids)
|
||||
QSettings settings;
|
||||
QString user_id = settings.value("auth/user_id").toString();
|
||||
|
||||
for (const auto uid : user_ids) {
|
||||
if (uid == user_id)
|
||||
continue;
|
||||
users.append(TimelineViewManager::displayName(uid));
|
||||
}
|
||||
|
||||
users.sort();
|
||||
|
||||
if (current_room_ == roomid)
|
||||
if (current_room_ == roomid) {
|
||||
typingDisplay_->setUsers(users);
|
||||
}
|
||||
|
||||
typingUsers_.insert(roomid, users);
|
||||
}
|
||||
|
@ -26,11 +26,11 @@
|
||||
|
||||
EmojiPanel::EmojiPanel(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, shadowMargin_{ 2 }
|
||||
, width_{ 370 }
|
||||
, height_{ 350 }
|
||||
, animationDuration_{ 100 }
|
||||
, categoryIconSize_{ 20 }
|
||||
, shadowMargin_{2}
|
||||
, width_{370}
|
||||
, height_{350}
|
||||
, animationDuration_{100}
|
||||
, categoryIconSize_{20}
|
||||
{
|
||||
setStyleSheet("QWidget {background: #fff; color: #e8e8e8; border: none;}"
|
||||
"QScrollBar:vertical { background-color: #fff; width: 8px; margin: 0px "
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
EmojiPickButton::EmojiPickButton(QWidget *parent)
|
||||
: FlatButton(parent)
|
||||
, panel_{ nullptr }
|
||||
, panel_{nullptr}
|
||||
{}
|
||||
|
||||
void
|
||||
|
2847
src/EmojiProvider.cc
2847
src/EmojiProvider.cc
File diff suppressed because it is too large
Load Diff
@ -32,8 +32,8 @@ ImageItem::ImageItem(QSharedPointer<MatrixClient> client,
|
||||
const events::MessageEvent<msgs::Image> &event,
|
||||
QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, event_{ event }
|
||||
, client_{ client }
|
||||
, event_{event}
|
||||
, client_{client}
|
||||
{
|
||||
setMouseTracking(true);
|
||||
setCursor(Qt::PointingHandCursor);
|
||||
@ -66,9 +66,9 @@ ImageItem::ImageItem(QSharedPointer<MatrixClient> client,
|
||||
const QString &filename,
|
||||
QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, url_{ url }
|
||||
, text_{ QFileInfo(filename).fileName() }
|
||||
, client_{ client }
|
||||
, url_{url}
|
||||
, text_{QFileInfo(filename).fileName()}
|
||||
, client_{client}
|
||||
{
|
||||
setMouseTracking(true);
|
||||
setCursor(Qt::PointingHandCursor);
|
||||
|
@ -22,8 +22,8 @@
|
||||
#include "ImageOverlayDialog.h"
|
||||
|
||||
ImageOverlayDialog::ImageOverlayDialog(QPixmap image, QWidget *parent)
|
||||
: QWidget{ parent }
|
||||
, originalImage_{ image }
|
||||
: QWidget{parent}
|
||||
, originalImage_{image}
|
||||
{
|
||||
setMouseTracking(true);
|
||||
setParent(0);
|
||||
|
@ -41,10 +41,10 @@ LoginRequest::serialize() noexcept
|
||||
#endif
|
||||
|
||||
QJsonObject body{
|
||||
{ "type", "m.login.password" },
|
||||
{ "user", user_ },
|
||||
{ "password", password_ },
|
||||
{ "initial_device_display_name", initialDeviceName },
|
||||
{"type", "m.login.password"},
|
||||
{"user", user_},
|
||||
{"password", password_},
|
||||
{"initial_device_display_name", initialDeviceName},
|
||||
};
|
||||
|
||||
return QJsonDocument(body).toJson(QJsonDocument::Compact);
|
||||
|
@ -28,7 +28,7 @@
|
||||
LoginPage::LoginPage(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, inferredServerAddress_()
|
||||
, client_{ client }
|
||||
, client_{client}
|
||||
{
|
||||
setStyleSheet("background-color: #fff");
|
||||
|
||||
|
@ -31,36 +31,36 @@
|
||||
#include "RegisterPage.h"
|
||||
#include "SnackBar.h"
|
||||
#include "TrayIcon.h"
|
||||
#include "UserSettingsPage.h"
|
||||
#include "WelcomePage.h"
|
||||
|
||||
MainWindow *MainWindow::instance_ = nullptr;
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, progressModal_{ nullptr }
|
||||
, spinner_{ nullptr }
|
||||
, progressModal_{nullptr}
|
||||
, spinner_{nullptr}
|
||||
{
|
||||
QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
setSizePolicy(sizePolicy);
|
||||
setWindowTitle("nheko");
|
||||
setObjectName("MainWindow");
|
||||
setStyleSheet("QWidget#MainWindow {background-color: #fff}");
|
||||
|
||||
restoreWindowSize();
|
||||
setMinimumSize(QSize(conf::window::minWidth, conf::window::minHeight));
|
||||
|
||||
QFont font("Open Sans");
|
||||
font.setPixelSize(conf::fontSize);
|
||||
font.setStyleStrategy(QFont::PreferAntialias);
|
||||
setFont(font);
|
||||
|
||||
client_ = QSharedPointer<MatrixClient>(new MatrixClient("matrix.org"));
|
||||
trayIcon_ = new TrayIcon(":/logos/nheko-32.png", this);
|
||||
client_ = QSharedPointer<MatrixClient>(new MatrixClient("matrix.org"));
|
||||
userSettings_ = QSharedPointer<UserSettings>(new UserSettings);
|
||||
trayIcon_ = new TrayIcon(":/logos/nheko-32.png", this);
|
||||
|
||||
welcome_page_ = new WelcomePage(this);
|
||||
login_page_ = new LoginPage(client_, this);
|
||||
register_page_ = new RegisterPage(client_, this);
|
||||
chat_page_ = new ChatPage(client_, this);
|
||||
welcome_page_ = new WelcomePage(this);
|
||||
login_page_ = new LoginPage(client_, this);
|
||||
register_page_ = new RegisterPage(client_, this);
|
||||
chat_page_ = new ChatPage(client_, this);
|
||||
userSettingsPage_ = new UserSettingsPage(userSettings_, this);
|
||||
|
||||
// Initialize sliding widget manager.
|
||||
pageStack_ = new QStackedWidget(this);
|
||||
@ -68,6 +68,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
pageStack_->addWidget(login_page_);
|
||||
pageStack_->addWidget(register_page_);
|
||||
pageStack_->addWidget(chat_page_);
|
||||
pageStack_->addWidget(userSettingsPage_);
|
||||
|
||||
setCentralWidget(pageStack_);
|
||||
|
||||
@ -86,12 +87,21 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
showLoginPage();
|
||||
});
|
||||
|
||||
connect(userSettingsPage_, &UserSettingsPage::moveBack, this, [=]() {
|
||||
pageStack_->setCurrentWidget(chat_page_);
|
||||
});
|
||||
|
||||
connect(
|
||||
userSettingsPage_, SIGNAL(trayOptionChanged(bool)), trayIcon_, SLOT(setVisible(bool)));
|
||||
|
||||
connect(trayIcon_,
|
||||
SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
|
||||
this,
|
||||
SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
|
||||
|
||||
connect(chat_page_, SIGNAL(contentLoaded()), this, SLOT(removeOverlayProgressBar()));
|
||||
connect(
|
||||
chat_page_, &ChatPage::showUserSettingsPage, this, &MainWindow::showUserSettingsPage);
|
||||
|
||||
connect(client_.data(),
|
||||
SIGNAL(loginSuccess(QString, QString, QString)),
|
||||
@ -101,8 +111,15 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
QShortcut *quitShortcut = new QShortcut(QKeySequence::Quit, this);
|
||||
connect(quitShortcut, &QShortcut::activated, this, QApplication::quit);
|
||||
|
||||
QShortcut *quickSwitchShortcut = new QShortcut(QKeySequence("Ctrl+K"), this);
|
||||
connect(quickSwitchShortcut, &QShortcut::activated, this, [=]() {
|
||||
chat_page_->showQuickSwitcher();
|
||||
});
|
||||
|
||||
QSettings settings;
|
||||
|
||||
trayIcon_->setVisible(userSettings_->isTrayEnabled());
|
||||
|
||||
if (hasActiveUser()) {
|
||||
QString token = settings.value("auth/access_token").toString();
|
||||
QString home_server = settings.value("auth/home_server").toString();
|
||||
@ -234,10 +251,16 @@ MainWindow::showRegisterPage()
|
||||
pageStack_->setCurrentWidget(register_page_);
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::showUserSettingsPage()
|
||||
{
|
||||
pageStack_->setCurrentWidget(userSettingsPage_);
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
if (isVisible()) {
|
||||
if (isVisible() && userSettings_->isTrayEnabled()) {
|
||||
event->ignore();
|
||||
hide();
|
||||
}
|
||||
|
@ -38,9 +38,9 @@
|
||||
|
||||
MatrixClient::MatrixClient(QString server, QObject *parent)
|
||||
: QNetworkAccessManager(parent)
|
||||
, clientApiUrl_{ "/_matrix/client/r0" }
|
||||
, mediaApiUrl_{ "/_matrix/media/r0" }
|
||||
, server_{ "https://" + server }
|
||||
, clientApiUrl_{"/_matrix/client/r0"}
|
||||
, mediaApiUrl_{"/_matrix/media/r0"}
|
||||
, server_{"https://" + server}
|
||||
{
|
||||
QSettings settings;
|
||||
txn_id_ = settings.value("client/transaction_id", 1).toInt();
|
||||
@ -119,7 +119,6 @@ MatrixClient::login(const QString &username, const QString &password) noexcept
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
MatrixClient::logout() noexcept
|
||||
{
|
||||
@ -260,9 +259,11 @@ MatrixClient::sync() noexcept
|
||||
}
|
||||
|
||||
void
|
||||
MatrixClient::sendRoomMessage(matrix::events::MessageEventType ty,
|
||||
MatrixClient::sendRoomMessage(mtx::events::MessageType ty,
|
||||
int txnId,
|
||||
const QString &roomid,
|
||||
const QString &msg,
|
||||
const QFileInfo &fileinfo,
|
||||
const QString &url) noexcept
|
||||
{
|
||||
QUrlQuery query;
|
||||
@ -940,3 +941,53 @@ MatrixClient::leaveRoom(const QString &roomId)
|
||||
emit leftRoom(roomId);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
MatrixClient::sendTypingNotification(const QString &roomid, int timeoutInMillis)
|
||||
{
|
||||
QSettings settings;
|
||||
QString user_id = settings.value("auth/user_id").toString();
|
||||
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("access_token", token_);
|
||||
|
||||
QUrl endpoint(server_);
|
||||
endpoint.setPath(clientApiUrl_ + QString("/rooms/%1/typing/%2").arg(roomid).arg(user_id));
|
||||
|
||||
endpoint.setQuery(query);
|
||||
|
||||
QString msgType("");
|
||||
QJsonObject body;
|
||||
|
||||
body = {{"typing", true}, {"timeout", timeoutInMillis}};
|
||||
|
||||
QNetworkRequest request(QString(endpoint.toEncoded()));
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
put(request, QJsonDocument(body).toJson(QJsonDocument::Compact));
|
||||
}
|
||||
|
||||
void
|
||||
MatrixClient::removeTypingNotification(const QString &roomid)
|
||||
{
|
||||
QSettings settings;
|
||||
QString user_id = settings.value("auth/user_id").toString();
|
||||
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("access_token", token_);
|
||||
|
||||
QUrl endpoint(server_);
|
||||
endpoint.setPath(clientApiUrl_ + QString("/rooms/%1/typing/%2").arg(roomid).arg(user_id));
|
||||
|
||||
endpoint.setQuery(query);
|
||||
|
||||
QString msgType("");
|
||||
QJsonObject body;
|
||||
|
||||
body = {{"typing", false}};
|
||||
|
||||
QNetworkRequest request(QString(endpoint.toEncoded()));
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
put(request, QJsonDocument(body).toJson(QJsonDocument::Compact));
|
||||
}
|
||||
|
@ -122,7 +122,16 @@ QuickSwitcher::QuickSwitcher(QWidget *parent)
|
||||
roomSearch_, &RoomSearchInput::hiding, this, [=]() { completer_->popup()->hide(); });
|
||||
connect(roomSearch_, &QLineEdit::returnPressed, this, [=]() {
|
||||
emit closing();
|
||||
emit roomSelected(rooms_[this->roomSearch_->text().trimmed()]);
|
||||
|
||||
QString text("");
|
||||
|
||||
if (selection_ == -1) {
|
||||
completer_->setCurrentRow(0);
|
||||
text = completer_->currentCompletion();
|
||||
} else {
|
||||
text = this->roomSearch_->text().trimmed();
|
||||
}
|
||||
emit roomSelected(rooms_[text]);
|
||||
|
||||
roomSearch_->clear();
|
||||
});
|
||||
|
@ -27,7 +27,7 @@ RegisterRequest::RegisterRequest(const QString &username, const QString &passwor
|
||||
QByteArray
|
||||
RegisterRequest::serialize() noexcept
|
||||
{
|
||||
QJsonObject body{ { "username", user_ }, { "password", password_ } };
|
||||
QJsonObject body{{"username", user_}, {"password", password_}};
|
||||
|
||||
return QJsonDocument(body).toJson(QJsonDocument::Compact);
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ RoomInfoListItem::RoomInfoListItem(QSharedPointer<RoomSettings> settings,
|
||||
: QWidget(parent)
|
||||
, state_(state)
|
||||
, roomId_(room_id)
|
||||
, roomSettings_{ settings }
|
||||
, roomSettings_{settings}
|
||||
, isPressed_(false)
|
||||
, maxHeight_(IconSize + 2 * Padding)
|
||||
, unreadMsgCount_(0)
|
||||
|
@ -33,12 +33,8 @@ RoomList::RoomList(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, client_(client)
|
||||
{
|
||||
setStyleSheet("QWidget { border: none; }");
|
||||
|
||||
QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
sizePolicy.setHorizontalStretch(0);
|
||||
sizePolicy.setVerticalStretch(0);
|
||||
setSizePolicy(sizePolicy);
|
||||
setStyleSheet(
|
||||
"border: 1px solid #ccc; border-right: 0px solid #000; border-left: 0px solid #000;");
|
||||
|
||||
topLayout_ = new QVBoxLayout(this);
|
||||
topLayout_->setSpacing(0);
|
||||
@ -51,7 +47,7 @@ RoomList::RoomList(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||
scrollArea_->setWidgetResizable(true);
|
||||
scrollArea_->setAlignment(Qt::AlignLeading | Qt::AlignTop | Qt::AlignVCenter);
|
||||
|
||||
scrollAreaContents_ = new QWidget();
|
||||
scrollAreaContents_ = new QWidget(this);
|
||||
|
||||
contentsLayout_ = new QVBoxLayout(scrollAreaContents_);
|
||||
contentsLayout_->setSpacing(0);
|
||||
|
@ -5,13 +5,10 @@
|
||||
#include "Theme.h"
|
||||
|
||||
SideBarActions::SideBarActions(QWidget *parent)
|
||||
: QWidget{ parent }
|
||||
: QWidget{parent}
|
||||
{
|
||||
setFixedHeight(conf::sidebarActions::height);
|
||||
|
||||
QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
setSizePolicy(sizePolicy);
|
||||
|
||||
layout_ = new QHBoxLayout(this);
|
||||
layout_->setMargin(0);
|
||||
|
||||
@ -45,6 +42,8 @@ SideBarActions::SideBarActions(QWidget *parent)
|
||||
layout_->addWidget(createRoomBtn_);
|
||||
layout_->addWidget(joinRoomBtn_);
|
||||
layout_->addWidget(settingsBtn_);
|
||||
|
||||
connect(settingsBtn_, &QPushButton::clicked, this, &SideBarActions::showSettings);
|
||||
}
|
||||
|
||||
SideBarActions::~SideBarActions() {}
|
||||
|
@ -15,6 +15,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QAbstractTextDocumentLayout>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QFileDialog>
|
||||
@ -25,19 +26,143 @@
|
||||
#include "Config.h"
|
||||
#include "TextInputWidget.h"
|
||||
|
||||
static constexpr size_t INPUT_HISTORY_SIZE = 127;
|
||||
|
||||
FilteredTextEdit::FilteredTextEdit(QWidget *parent)
|
||||
: QTextEdit(parent)
|
||||
: QTextEdit{parent}
|
||||
, history_index_{0}
|
||||
{
|
||||
connect(document()->documentLayout(),
|
||||
&QAbstractTextDocumentLayout::documentSizeChanged,
|
||||
this,
|
||||
&FilteredTextEdit::updateGeometry);
|
||||
QSizePolicy policy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
policy.setHeightForWidth(true);
|
||||
setSizePolicy(policy);
|
||||
working_history_.push_back("");
|
||||
connect(this, &QTextEdit::textChanged, this, &FilteredTextEdit::textChanged);
|
||||
setAcceptRichText(false);
|
||||
|
||||
typingTimer_ = new QTimer(this);
|
||||
typingTimer_->setInterval(1000);
|
||||
typingTimer_->setSingleShot(true);
|
||||
|
||||
connect(typingTimer_, &QTimer::timeout, this, &FilteredTextEdit::stopTyping);
|
||||
}
|
||||
|
||||
void
|
||||
FilteredTextEdit::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
|
||||
emit enterPressed();
|
||||
else
|
||||
const bool isModifier = (event->modifiers() != Qt::NoModifier);
|
||||
|
||||
if (!isModifier) {
|
||||
if (!typingTimer_->isActive())
|
||||
emit startedTyping();
|
||||
|
||||
typingTimer_->start();
|
||||
}
|
||||
|
||||
switch (event->key()) {
|
||||
case Qt::Key_Return:
|
||||
case Qt::Key_Enter:
|
||||
if (!(event->modifiers() & Qt::ShiftModifier)) {
|
||||
stopTyping();
|
||||
submit();
|
||||
} else {
|
||||
QTextEdit::keyPressEvent(event);
|
||||
}
|
||||
break;
|
||||
case Qt::Key_Up: {
|
||||
auto initial_cursor = textCursor();
|
||||
QTextEdit::keyPressEvent(event);
|
||||
if (textCursor() == initial_cursor &&
|
||||
history_index_ + 1 < working_history_.size()) {
|
||||
++history_index_;
|
||||
setPlainText(working_history_[history_index_]);
|
||||
moveCursor(QTextCursor::End);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Qt::Key_Down: {
|
||||
auto initial_cursor = textCursor();
|
||||
QTextEdit::keyPressEvent(event);
|
||||
if (textCursor() == initial_cursor && history_index_ > 0) {
|
||||
--history_index_;
|
||||
setPlainText(working_history_[history_index_]);
|
||||
moveCursor(QTextCursor::End);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
QTextEdit::keyPressEvent(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FilteredTextEdit::stopTyping()
|
||||
{
|
||||
typingTimer_->stop();
|
||||
emit stoppedTyping();
|
||||
}
|
||||
|
||||
QSize
|
||||
FilteredTextEdit::sizeHint() const
|
||||
{
|
||||
ensurePolished();
|
||||
auto margins = viewportMargins();
|
||||
margins += document()->documentMargin();
|
||||
QSize size = document()->size().toSize();
|
||||
size.rwidth() += margins.left() + margins.right();
|
||||
size.rheight() += margins.top() + margins.bottom();
|
||||
return size;
|
||||
}
|
||||
|
||||
QSize
|
||||
FilteredTextEdit::minimumSizeHint() const
|
||||
{
|
||||
ensurePolished();
|
||||
auto margins = viewportMargins();
|
||||
margins += document()->documentMargin();
|
||||
margins += contentsMargins();
|
||||
QSize size(fontMetrics().averageCharWidth() * 10,
|
||||
fontMetrics().lineSpacing() + margins.top() + margins.bottom());
|
||||
return size;
|
||||
}
|
||||
|
||||
void
|
||||
FilteredTextEdit::submit()
|
||||
{
|
||||
if (true_history_.size() == INPUT_HISTORY_SIZE)
|
||||
true_history_.pop_back();
|
||||
true_history_.push_front(toPlainText());
|
||||
working_history_ = true_history_;
|
||||
working_history_.push_front("");
|
||||
history_index_ = 0;
|
||||
|
||||
QString text = toPlainText();
|
||||
if (text.startsWith('/')) {
|
||||
int command_end = text.indexOf(' ');
|
||||
if (command_end == -1)
|
||||
command_end = text.size();
|
||||
auto name = text.mid(1, command_end - 1);
|
||||
auto args = text.mid(command_end + 1);
|
||||
if (name.isEmpty() || name == "/") {
|
||||
message(args);
|
||||
} else {
|
||||
command(name, args);
|
||||
}
|
||||
} else {
|
||||
message(std::move(text));
|
||||
}
|
||||
|
||||
clear();
|
||||
}
|
||||
|
||||
void
|
||||
FilteredTextEdit::textChanged()
|
||||
{
|
||||
working_history_[history_index_] = toPlainText();
|
||||
}
|
||||
|
||||
TextInputWidget::TextInputWidget(QWidget *parent)
|
||||
@ -97,13 +222,18 @@ TextInputWidget::TextInputWidget(QWidget *parent)
|
||||
|
||||
setLayout(topLayout_);
|
||||
|
||||
connect(sendMessageBtn_, SIGNAL(clicked()), this, SLOT(onSendButtonClicked()));
|
||||
connect(sendMessageBtn_, &FlatButton::clicked, input_, &FilteredTextEdit::submit);
|
||||
connect(sendFileBtn_, SIGNAL(clicked()), this, SLOT(openFileSelection()));
|
||||
connect(input_, SIGNAL(enterPressed()), sendMessageBtn_, SIGNAL(clicked()));
|
||||
connect(input_, &FilteredTextEdit::message, this, &TextInputWidget::sendTextMessage);
|
||||
connect(input_, &FilteredTextEdit::command, this, &TextInputWidget::command);
|
||||
connect(emojiBtn_,
|
||||
SIGNAL(emojiSelected(const QString &)),
|
||||
this,
|
||||
SLOT(addSelectedEmoji(const QString &)));
|
||||
|
||||
connect(input_, &FilteredTextEdit::startedTyping, this, &TextInputWidget::startedTyping);
|
||||
|
||||
connect(input_, &FilteredTextEdit::stoppedTyping, this, &TextInputWidget::stoppedTyping);
|
||||
}
|
||||
|
||||
void
|
||||
@ -131,50 +261,13 @@ TextInputWidget::addSelectedEmoji(const QString &emoji)
|
||||
}
|
||||
|
||||
void
|
||||
TextInputWidget::onSendButtonClicked()
|
||||
TextInputWidget::command(QString command, QString args)
|
||||
{
|
||||
auto msgText = input_->document()->toPlainText().trimmed();
|
||||
|
||||
if (msgText.isEmpty())
|
||||
return;
|
||||
|
||||
if (msgText.startsWith(EMOTE_COMMAND)) {
|
||||
auto text = parseEmoteCommand(msgText);
|
||||
|
||||
if (!text.isEmpty())
|
||||
emit sendEmoteMessage(text);
|
||||
} else if (msgText.startsWith(JOIN_COMMAND)) {
|
||||
auto room = parseJoinCommand(msgText);
|
||||
|
||||
if (!room.isEmpty())
|
||||
emit sendJoinRoomRequest(room);
|
||||
} else {
|
||||
emit sendTextMessage(msgText);
|
||||
if (command == "me") {
|
||||
sendEmoteMessage(args);
|
||||
} else if (command == "join") {
|
||||
sendJoinRoomRequest(args);
|
||||
}
|
||||
|
||||
input_->clear();
|
||||
}
|
||||
|
||||
QString
|
||||
TextInputWidget::parseJoinCommand(const QString &cmd)
|
||||
{
|
||||
auto room = cmd.right(cmd.size() - JOIN_COMMAND.size()).trimmed();
|
||||
|
||||
if (!room.isEmpty())
|
||||
return room;
|
||||
|
||||
return QString("");
|
||||
}
|
||||
|
||||
QString
|
||||
TextInputWidget::parseEmoteCommand(const QString &cmd)
|
||||
{
|
||||
auto text = cmd.right(cmd.size() - EMOTE_COMMAND.size()).trimmed();
|
||||
|
||||
if (!text.isEmpty())
|
||||
return text;
|
||||
|
||||
return QString("");
|
||||
}
|
||||
|
||||
void
|
||||
@ -226,6 +319,16 @@ TextInputWidget::hideUploadSpinner()
|
||||
spinner_->stop();
|
||||
}
|
||||
|
||||
TextInputWidget::~TextInputWidget()
|
||||
TextInputWidget::~TextInputWidget() {}
|
||||
|
||||
void
|
||||
TextInputWidget::stopTyping()
|
||||
{
|
||||
input_->stopTyping();
|
||||
}
|
||||
|
||||
void
|
||||
TextInputWidget::focusInEvent(QFocusEvent *event)
|
||||
{
|
||||
input_->setFocus(event->reason());
|
||||
}
|
||||
|
@ -85,15 +85,15 @@ TimelineItem::TimelineItem(events::MessageEventType ty,
|
||||
|
||||
if (ty == events::MessageEventType::Emote) {
|
||||
body = QString("* %1 %2").arg(displayName).arg(body);
|
||||
descriptionMsg_ = { "", userid, body, descriptiveTime(timestamp) };
|
||||
descriptionMsg_ = {"", userid, body, descriptiveTime(timestamp)};
|
||||
} else {
|
||||
descriptionMsg_ = {
|
||||
"You: ", userid, body, descriptiveTime(QDateTime::currentDateTime())
|
||||
};
|
||||
"You: ", userid, body, descriptiveTime(QDateTime::currentDateTime())};
|
||||
}
|
||||
|
||||
body = body.toHtmlEscaped();
|
||||
body.replace(URL_REGEX, URL_HTML);
|
||||
body.replace("\n", "<br/>");
|
||||
generateTimestamp(timestamp);
|
||||
|
||||
if (withSender) {
|
||||
@ -114,14 +114,14 @@ TimelineItem::TimelineItem(ImageItem *image,
|
||||
const QString &userid,
|
||||
bool withSender,
|
||||
QWidget *parent)
|
||||
: QWidget{ parent }
|
||||
: QWidget{parent}
|
||||
{
|
||||
init();
|
||||
|
||||
auto displayName = TimelineViewManager::displayName(userid);
|
||||
auto timestamp = QDateTime::currentDateTime();
|
||||
|
||||
descriptionMsg_ = { "You", userid, " sent an image", descriptiveTime(timestamp) };
|
||||
descriptionMsg_ = {"You", userid, " sent an image", descriptiveTime(timestamp)};
|
||||
|
||||
generateTimestamp(timestamp);
|
||||
|
||||
@ -158,10 +158,10 @@ TimelineItem::TimelineItem(ImageItem *image,
|
||||
auto displayName = TimelineViewManager::displayName(event.sender());
|
||||
|
||||
QSettings settings;
|
||||
descriptionMsg_ = { event.sender() == settings.value("auth/user_id") ? "You" : displayName,
|
||||
event.sender(),
|
||||
" sent an image",
|
||||
descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp())) };
|
||||
descriptionMsg_ = {event.sender() == settings.value("auth/user_id") ? "You" : displayName,
|
||||
event.sender(),
|
||||
" sent an image",
|
||||
descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp()))};
|
||||
|
||||
generateTimestamp(timestamp);
|
||||
|
||||
@ -193,10 +193,10 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Notice> &event,
|
||||
: QWidget(parent)
|
||||
{
|
||||
init();
|
||||
descriptionMsg_ = { TimelineViewManager::displayName(event.sender()),
|
||||
event.sender(),
|
||||
" sent a notification",
|
||||
descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp())) };
|
||||
descriptionMsg_ = {TimelineViewManager::displayName(event.sender()),
|
||||
event.sender(),
|
||||
" sent a notification",
|
||||
descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp()))};
|
||||
|
||||
auto body = event.content().body().trimmed().toHtmlEscaped();
|
||||
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
|
||||
@ -204,6 +204,7 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Notice> &event,
|
||||
generateTimestamp(timestamp);
|
||||
|
||||
body.replace(URL_REGEX, URL_HTML);
|
||||
body.replace("\n", "<br/>");
|
||||
body = "<i style=\"color: #565E5E\">" + body + "</i>";
|
||||
|
||||
if (with_sender) {
|
||||
@ -238,14 +239,15 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Emote> &event,
|
||||
auto displayName = TimelineViewManager::displayName(event.sender());
|
||||
auto emoteMsg = QString("* %1 %2").arg(displayName).arg(body);
|
||||
|
||||
descriptionMsg_ = { "",
|
||||
event.sender(),
|
||||
emoteMsg,
|
||||
descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp())) };
|
||||
descriptionMsg_ = {"",
|
||||
event.sender(),
|
||||
emoteMsg,
|
||||
descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp()))};
|
||||
|
||||
generateTimestamp(timestamp);
|
||||
emoteMsg = emoteMsg.toHtmlEscaped();
|
||||
emoteMsg.replace(URL_REGEX, URL_HTML);
|
||||
emoteMsg.replace("\n", "<br/>");
|
||||
|
||||
if (with_sender) {
|
||||
generateBody(displayName, emoteMsg);
|
||||
@ -276,15 +278,16 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Text> &event,
|
||||
auto displayName = TimelineViewManager::displayName(event.sender());
|
||||
|
||||
QSettings settings;
|
||||
descriptionMsg_ = { event.sender() == settings.value("auth/user_id") ? "You" : displayName,
|
||||
event.sender(),
|
||||
QString(": %1").arg(body),
|
||||
descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp())) };
|
||||
descriptionMsg_ = {event.sender() == settings.value("auth/user_id") ? "You" : displayName,
|
||||
event.sender(),
|
||||
QString(": %1").arg(body),
|
||||
descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp()))};
|
||||
|
||||
generateTimestamp(timestamp);
|
||||
|
||||
body = body.toHtmlEscaped();
|
||||
body.replace(URL_REGEX, URL_HTML);
|
||||
body.replace("\n", "<br/>");
|
||||
|
||||
if (with_sender) {
|
||||
generateBody(displayName, body);
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QFileInfo>
|
||||
#include <QSettings>
|
||||
#include <QTimer>
|
||||
|
||||
@ -49,8 +50,8 @@ TimelineView::TimelineView(const Timeline &timeline,
|
||||
const QString &room_id,
|
||||
QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, room_id_{ room_id }
|
||||
, client_{ client }
|
||||
, room_id_{room_id}
|
||||
, client_{client}
|
||||
{
|
||||
init();
|
||||
addEvents(timeline);
|
||||
@ -60,8 +61,8 @@ TimelineView::TimelineView(QSharedPointer<MatrixClient> client,
|
||||
const QString &room_id,
|
||||
QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, room_id_{ room_id }
|
||||
, client_{ client }
|
||||
, room_id_{room_id}
|
||||
, client_{client}
|
||||
{
|
||||
init();
|
||||
client_->messages(room_id_, "");
|
||||
@ -179,6 +180,10 @@ TimelineView::addBackwardsEvents(const QString &room_id, const RoomMessages &msg
|
||||
isTimelineFinished = false;
|
||||
QList<TimelineItem *> items;
|
||||
|
||||
// Reset the sender of the first message in the timeline
|
||||
// cause we're about to insert a new one.
|
||||
firstSender_.clear();
|
||||
|
||||
// Parse in reverse order to determine where we should not show sender's
|
||||
// name.
|
||||
auto ii = msgs.chunk().size();
|
||||
@ -241,9 +246,10 @@ TimelineView::parseMessageEvent(const QJsonObject &event, TimelineDirection dire
|
||||
|
||||
eventIds_[text.eventId()] = true;
|
||||
|
||||
if (isPendingMessage(
|
||||
text.eventId(), text.content().body(), text.sender(), local_user_)) {
|
||||
removePendingMessage(text.eventId(), text.content().body());
|
||||
QString txnid = text.unsignedData().transactionId();
|
||||
if (!txnid.isEmpty() &&
|
||||
isPendingMessage(txnid, text.sender(), local_user_)) {
|
||||
removePendingMessage(txnid);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -287,9 +293,10 @@ TimelineView::parseMessageEvent(const QJsonObject &event, TimelineDirection dire
|
||||
|
||||
eventIds_[img.eventId()] = true;
|
||||
|
||||
if (isPendingMessage(
|
||||
img.eventId(), img.msgContent().url(), img.sender(), local_user_)) {
|
||||
removePendingMessage(img.eventId(), img.msgContent().url());
|
||||
QString txnid = img.unsignedData().transactionId();
|
||||
if (!txnid.isEmpty() &&
|
||||
isPendingMessage(txnid, img.sender(), local_user_)) {
|
||||
removePendingMessage(txnid);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -313,11 +320,10 @@ TimelineView::parseMessageEvent(const QJsonObject &event, TimelineDirection dire
|
||||
|
||||
eventIds_[emote.eventId()] = true;
|
||||
|
||||
if (isPendingMessage(emote.eventId(),
|
||||
emote.content().body(),
|
||||
emote.sender(),
|
||||
local_user_)) {
|
||||
removePendingMessage(emote.eventId(), emote.content().body());
|
||||
QString txnid = emote.unsignedData().transactionId();
|
||||
if (!txnid.isEmpty() &&
|
||||
isPendingMessage(txnid, emote.sender(), local_user_)) {
|
||||
removePendingMessage(txnid);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -495,16 +501,16 @@ TimelineView::addTimelineItem(TimelineItem *item, TimelineDirection direction)
|
||||
void
|
||||
TimelineView::updatePendingMessage(int txn_id, QString event_id)
|
||||
{
|
||||
for (auto &msg : pending_msgs_) {
|
||||
if (msg.txn_id == txn_id) {
|
||||
msg.event_id = event_id;
|
||||
break;
|
||||
}
|
||||
if (pending_msgs_.head().txn_id == txn_id) { // We haven't received it yet
|
||||
auto msg = pending_msgs_.dequeue();
|
||||
msg.event_id = event_id;
|
||||
pending_sent_msgs_.append(msg);
|
||||
}
|
||||
sendNextPendingMessage();
|
||||
}
|
||||
|
||||
void
|
||||
TimelineView::addUserMessage(matrix::events::MessageEventType ty, const QString &body, int txn_id)
|
||||
TimelineView::addUserMessage(matrix::events::MessageEventType ty, const QString &body)
|
||||
{
|
||||
QSettings settings;
|
||||
auto user_id = settings.value("auth/user_id").toString();
|
||||
@ -519,12 +525,13 @@ TimelineView::addUserMessage(matrix::events::MessageEventType ty, const QString
|
||||
|
||||
lastSender_ = user_id;
|
||||
|
||||
PendingMessage message(txn_id, body, "", view_item);
|
||||
pending_msgs_.push_back(message);
|
||||
int txn_id = client_->incrementTransactionId();
|
||||
PendingMessage message(ty, txn_id, body, "", "", view_item);
|
||||
handleNewUserMessage(message);
|
||||
}
|
||||
|
||||
void
|
||||
TimelineView::addUserMessage(const QString &url, const QString &filename, int txn_id)
|
||||
TimelineView::addUserMessage(const QString &url, const QString &filename)
|
||||
{
|
||||
QSettings settings;
|
||||
auto user_id = settings.value("auth/user_id").toString();
|
||||
@ -541,8 +548,36 @@ TimelineView::addUserMessage(const QString &url, const QString &filename, int tx
|
||||
|
||||
lastSender_ = user_id;
|
||||
|
||||
PendingMessage message(txn_id, url, "", view_item);
|
||||
pending_msgs_.push_back(message);
|
||||
int txn_id = client_->incrementTransactionId();
|
||||
PendingMessage message(
|
||||
matrix::events::MessageEventType::Image, txn_id, url, filename, "", view_item);
|
||||
handleNewUserMessage(message);
|
||||
}
|
||||
|
||||
void
|
||||
TimelineView::handleNewUserMessage(PendingMessage msg)
|
||||
{
|
||||
pending_msgs_.enqueue(msg);
|
||||
if (pending_msgs_.size() == 1 && pending_sent_msgs_.size() == 0)
|
||||
sendNextPendingMessage();
|
||||
}
|
||||
|
||||
void
|
||||
TimelineView::sendNextPendingMessage()
|
||||
{
|
||||
if (pending_msgs_.size() == 0)
|
||||
return;
|
||||
|
||||
PendingMessage &m = pending_msgs_.head();
|
||||
switch (m.ty) {
|
||||
case matrix::events::MessageEventType::Image:
|
||||
client_->sendRoomMessage(
|
||||
m.ty, m.txn_id, room_id_, QFileInfo(m.filename).fileName(), QFileInfo(m.filename), m.body);
|
||||
break;
|
||||
default:
|
||||
client_->sendRoomMessage(m.ty, m.txn_id, room_id_, m.body, QFileInfo());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -558,8 +593,7 @@ TimelineView::notifyForLastEvent()
|
||||
}
|
||||
|
||||
bool
|
||||
TimelineView::isPendingMessage(const QString &eventid,
|
||||
const QString &body,
|
||||
TimelineView::isPendingMessage(const QString &txnid,
|
||||
const QString &sender,
|
||||
const QString &local_userid)
|
||||
{
|
||||
@ -567,7 +601,12 @@ TimelineView::isPendingMessage(const QString &eventid,
|
||||
return false;
|
||||
|
||||
for (const auto &msg : pending_msgs_) {
|
||||
if (msg.event_id == eventid || msg.body == body)
|
||||
if (QString::number(msg.txn_id) == txnid)
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto &msg : pending_sent_msgs_) {
|
||||
if (QString::number(msg.txn_id) == txnid)
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -575,14 +614,28 @@ TimelineView::isPendingMessage(const QString &eventid,
|
||||
}
|
||||
|
||||
void
|
||||
TimelineView::removePendingMessage(const QString &eventid, const QString &body)
|
||||
TimelineView::removePendingMessage(const QString &txnid)
|
||||
{
|
||||
for (auto it = pending_sent_msgs_.begin(); it != pending_sent_msgs_.end(); ++it) {
|
||||
if (QString::number(it->txn_id) == txnid) {
|
||||
int index = std::distance(pending_sent_msgs_.begin(), it);
|
||||
pending_sent_msgs_.removeAt(index);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (auto it = pending_msgs_.begin(); it != pending_msgs_.end(); ++it) {
|
||||
int index = std::distance(pending_msgs_.begin(), it);
|
||||
|
||||
if (it->event_id == eventid || it->body == body) {
|
||||
if (QString::number(it->txn_id) == txnid) {
|
||||
int index = std::distance(pending_msgs_.begin(), it);
|
||||
pending_msgs_.removeAt(index);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TimelineView::handleFailedMessage(int txnid)
|
||||
{
|
||||
Q_UNUSED(txnid);
|
||||
// Note: We do this even if the message has already been echoed.
|
||||
QTimer::singleShot(500, this, SLOT(sendNextPendingMessage()));
|
||||
}
|
||||
|
@ -31,10 +31,15 @@ TimelineViewManager::TimelineViewManager(QSharedPointer<MatrixClient> client, QW
|
||||
: QStackedWidget(parent)
|
||||
, client_(client)
|
||||
{
|
||||
setStyleSheet("QWidget { background: #fff; color: #e8e8e8; border: none;}");
|
||||
setStyleSheet("border: none;");
|
||||
|
||||
connect(
|
||||
client_.data(), &MatrixClient::messageSent, this, &TimelineViewManager::messageSent);
|
||||
|
||||
connect(client_.data(),
|
||||
&MatrixClient::messageSendFailed,
|
||||
this,
|
||||
&TimelineViewManager::messageSendFailed);
|
||||
}
|
||||
|
||||
TimelineViewManager::~TimelineViewManager()
|
||||
@ -53,30 +58,34 @@ TimelineViewManager::messageSent(const QString &event_id, const QString &roomid,
|
||||
}
|
||||
|
||||
void
|
||||
TimelineViewManager::sendTextMessage(const QString &msg)
|
||||
TimelineViewManager::messageSendFailed(const QString &roomid, int txn_id)
|
||||
{
|
||||
auto view = views_[roomid];
|
||||
view->handleFailedMessage(txn_id);
|
||||
}
|
||||
|
||||
void
|
||||
TimelineViewManager::queueTextMessage(const QString &msg)
|
||||
{
|
||||
auto room_id = active_room_;
|
||||
auto view = views_[room_id];
|
||||
|
||||
view->addUserMessage(matrix::events::MessageEventType::Text, msg, client_->transactionId());
|
||||
client_->sendRoomMessage(matrix::events::MessageEventType::Text, room_id, msg);
|
||||
view->addUserMessage(matrix::events::MessageEventType::Text, msg);
|
||||
}
|
||||
|
||||
void
|
||||
TimelineViewManager::sendEmoteMessage(const QString &msg)
|
||||
TimelineViewManager::queueEmoteMessage(const QString &msg)
|
||||
{
|
||||
auto room_id = active_room_;
|
||||
auto view = views_[room_id];
|
||||
|
||||
view->addUserMessage(
|
||||
matrix::events::MessageEventType::Emote, msg, client_->transactionId());
|
||||
client_->sendRoomMessage(matrix::events::MessageEventType::Emote, room_id, msg);
|
||||
view->addUserMessage(matrix::events::MessageEventType::Emote, msg);
|
||||
}
|
||||
|
||||
void
|
||||
TimelineViewManager::sendImageMessage(const QString &roomid,
|
||||
const QString &filename,
|
||||
const QString &url)
|
||||
TimelineViewManager::queueImageMessage(const QString &roomid,
|
||||
const QString &filename,
|
||||
const QString &url)
|
||||
{
|
||||
if (!views_.contains(roomid)) {
|
||||
qDebug() << "Cannot send m.image message to a non-managed view";
|
||||
@ -85,9 +94,7 @@ TimelineViewManager::sendImageMessage(const QString &roomid,
|
||||
|
||||
auto view = views_[roomid];
|
||||
|
||||
view->addUserMessage(url, filename, client_->transactionId());
|
||||
client_->sendRoomMessage(
|
||||
matrix::events::MessageEventType::Image, roomid, QFileInfo(filename).fileName(), url);
|
||||
view->addUserMessage(url, filename);
|
||||
}
|
||||
|
||||
void
|
||||
@ -196,7 +203,7 @@ QString
|
||||
TimelineViewManager::chooseRandomColor()
|
||||
{
|
||||
std::random_device random_device;
|
||||
std::mt19937 engine{ random_device() };
|
||||
std::mt19937 engine{random_device()};
|
||||
std::uniform_real_distribution<float> dist(0, 1);
|
||||
|
||||
float hue = dist(engine);
|
||||
|
@ -30,11 +30,10 @@
|
||||
|
||||
TopRoomBar::TopRoomBar(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, buttonSize_{ 32 }
|
||||
, buttonSize_{32}
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
setMinimumSize(QSize(0, 65));
|
||||
setStyleSheet("background-color: #fff; color: #171919;");
|
||||
setFixedHeight(65);
|
||||
|
||||
topLayout_ = new QHBoxLayout();
|
||||
topLayout_->setSpacing(10);
|
||||
|
@ -123,9 +123,6 @@ TrayIcon::TrayIcon(const QString &filename, QWidget *parent)
|
||||
menu->addAction(quitAction_);
|
||||
|
||||
setContextMenu(menu);
|
||||
|
||||
// We wait a little for the icon to load.
|
||||
QTimer::singleShot(500, this, [=]() { show(); });
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
TypingDisplay::TypingDisplay(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, leftPadding_{ 24 }
|
||||
, leftPadding_{24}
|
||||
{
|
||||
QFont font;
|
||||
font.setPixelSize(conf::typingNotificationFontSize);
|
||||
|
@ -29,13 +29,11 @@ UserInfoWidget::UserInfoWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, display_name_("User")
|
||||
, user_id_("@user:homeserver.org")
|
||||
, logoutModal_{ nullptr }
|
||||
, logoutDialog_{ nullptr }
|
||||
, logoutButtonSize_{ 20 }
|
||||
, logoutModal_{nullptr}
|
||||
, logoutDialog_{nullptr}
|
||||
, logoutButtonSize_{20}
|
||||
{
|
||||
QSizePolicy sizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
|
||||
setSizePolicy(sizePolicy);
|
||||
setMinimumSize(QSize(0, 65));
|
||||
setFixedHeight(65);
|
||||
|
||||
topLayout_ = new QHBoxLayout(this);
|
||||
topLayout_->setSpacing(0);
|
||||
@ -142,6 +140,8 @@ UserInfoWidget::resizeEvent(QResizeEvent *event)
|
||||
displayNameLabel_->show();
|
||||
userIdLabel_->show();
|
||||
}
|
||||
|
||||
QWidget::resizeEvent(event);
|
||||
}
|
||||
|
||||
void
|
||||
|
155
src/UserSettingsPage.cc
Normal file
155
src/UserSettingsPage.cc
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QDebug>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QSettings>
|
||||
|
||||
#include "Config.h"
|
||||
#include "FlatButton.h"
|
||||
#include "UserSettingsPage.h"
|
||||
#include <ToggleButton.h>
|
||||
|
||||
UserSettings::UserSettings() { load(); }
|
||||
|
||||
void
|
||||
UserSettings::load()
|
||||
{
|
||||
QSettings settings;
|
||||
isTrayEnabled_ = settings.value("user/window/tray", true).toBool();
|
||||
theme_ = settings.value("user/theme", "default").toString();
|
||||
}
|
||||
|
||||
void
|
||||
UserSettings::save()
|
||||
{
|
||||
QSettings settings;
|
||||
settings.beginGroup("user");
|
||||
|
||||
settings.beginGroup("window");
|
||||
settings.setValue("tray", isTrayEnabled_);
|
||||
settings.endGroup();
|
||||
|
||||
settings.setValue("theme", theme());
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
HorizontalLine::HorizontalLine(QWidget *parent)
|
||||
: QFrame{parent}
|
||||
{
|
||||
setFrameShape(QFrame::HLine);
|
||||
setFrameShadow(QFrame::Sunken);
|
||||
}
|
||||
|
||||
UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidget *parent)
|
||||
: QWidget{parent}
|
||||
, settings_{settings}
|
||||
{
|
||||
topLayout_ = new QVBoxLayout(this);
|
||||
|
||||
QIcon icon;
|
||||
icon.addFile(":/icons/icons/ui/angle-pointing-to-left.png");
|
||||
|
||||
auto backBtn_ = new FlatButton(this);
|
||||
backBtn_->setMinimumSize(QSize(24, 24));
|
||||
backBtn_->setIcon(icon);
|
||||
backBtn_->setIconSize(QSize(24, 24));
|
||||
|
||||
auto heading_ = new QLabel(tr("User Settings"));
|
||||
heading_->setFont(QFont("Open Sans Bold", 22));
|
||||
|
||||
topBarLayout_ = new QHBoxLayout;
|
||||
topBarLayout_->setSpacing(0);
|
||||
topBarLayout_->setMargin(0);
|
||||
topBarLayout_->addWidget(backBtn_, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
||||
topBarLayout_->addWidget(heading_, 0, Qt::AlignBottom);
|
||||
topBarLayout_->addStretch(1);
|
||||
|
||||
auto trayOptionLayout_ = new QHBoxLayout;
|
||||
trayOptionLayout_->setContentsMargins(0, OptionMargin, 0, OptionMargin);
|
||||
auto trayLabel = new QLabel(tr("Minimize to tray"), this);
|
||||
trayToggle_ = new Toggle(this);
|
||||
trayToggle_->setActiveColor(QColor("#38A3D8"));
|
||||
trayToggle_->setInactiveColor(QColor("gray"));
|
||||
trayLabel->setFont(QFont("Open Sans", 15));
|
||||
|
||||
trayOptionLayout_->addWidget(trayLabel);
|
||||
trayOptionLayout_->addWidget(trayToggle_, 0, Qt::AlignBottom | Qt::AlignRight);
|
||||
|
||||
auto themeOptionLayout_ = new QHBoxLayout;
|
||||
themeOptionLayout_->setContentsMargins(0, OptionMargin, 0, OptionMargin);
|
||||
auto themeLabel_ = new QLabel(tr("App theme"), this);
|
||||
themeCombo_ = new QComboBox(this);
|
||||
themeCombo_->addItem("Default");
|
||||
themeCombo_->addItem("System");
|
||||
themeLabel_->setFont(QFont("Open Sans", 15));
|
||||
|
||||
themeOptionLayout_->addWidget(themeLabel_);
|
||||
themeOptionLayout_->addWidget(themeCombo_, 0, Qt::AlignBottom | Qt::AlignRight);
|
||||
|
||||
auto general_ = new QLabel(tr("GENERAL"), this);
|
||||
general_->setFont(QFont("Open Sans Bold", 17));
|
||||
general_->setStyleSheet("color: #5d6565");
|
||||
|
||||
mainLayout_ = new QVBoxLayout;
|
||||
mainLayout_->setSpacing(7);
|
||||
mainLayout_->setContentsMargins(
|
||||
sideMargin_, LayoutTopMargin, sideMargin_, LayoutBottomMargin);
|
||||
mainLayout_->addWidget(general_, 1, Qt::AlignLeft | Qt::AlignVCenter);
|
||||
mainLayout_->addWidget(new HorizontalLine(this));
|
||||
mainLayout_->addLayout(trayOptionLayout_);
|
||||
mainLayout_->addWidget(new HorizontalLine(this));
|
||||
mainLayout_->addLayout(themeOptionLayout_);
|
||||
mainLayout_->addWidget(new HorizontalLine(this));
|
||||
|
||||
topLayout_->addLayout(topBarLayout_);
|
||||
topLayout_->addLayout(mainLayout_);
|
||||
topLayout_->addStretch(1);
|
||||
|
||||
connect(themeCombo_,
|
||||
static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::activated),
|
||||
[=](const QString &text) { settings_->setTheme(text.toLower()); });
|
||||
|
||||
connect(trayToggle_, &Toggle::toggled, this, [=](bool isDisabled) {
|
||||
settings_->setTray(!isDisabled);
|
||||
emit trayOptionChanged(!isDisabled);
|
||||
});
|
||||
|
||||
connect(backBtn_, &QPushButton::clicked, this, [=]() {
|
||||
settings_->save();
|
||||
emit moveBack();
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
UserSettingsPage::showEvent(QShowEvent *)
|
||||
{
|
||||
themeCombo_->setCurrentIndex((settings_->theme() == "default" ? 0 : 1));
|
||||
trayToggle_->setState(!settings_->isTrayEnabled()); // Treats true as "off"
|
||||
}
|
||||
|
||||
void
|
||||
UserSettingsPage::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
sideMargin_ = width() * 0.2;
|
||||
mainLayout_->setContentsMargins(
|
||||
sideMargin_, LayoutTopMargin, sideMargin_, LayoutBottomMargin);
|
||||
|
||||
QWidget::resizeEvent(event);
|
||||
}
|
@ -78,3 +78,29 @@ matrix::events::isMessageEvent(EventType type)
|
||||
{
|
||||
return type == EventType::RoomMessage;
|
||||
}
|
||||
|
||||
void
|
||||
matrix::events::UnsignedData::deserialize(const QJsonValue &data)
|
||||
{
|
||||
if (!data.isObject())
|
||||
throw DeserializationException("UnsignedData is not a JSON object");
|
||||
|
||||
auto object = data.toObject();
|
||||
|
||||
transaction_id_ = object.value("transaction_id").toString();
|
||||
age_ = object.value("age").toDouble();
|
||||
}
|
||||
|
||||
QJsonObject
|
||||
matrix::events::UnsignedData::serialize() const
|
||||
{
|
||||
QJsonObject object;
|
||||
|
||||
if (!transaction_id_.isEmpty())
|
||||
object["transaction_id"] = transaction_id_;
|
||||
|
||||
if (age_ > 0)
|
||||
object["age"] = age_;
|
||||
|
||||
return object;
|
||||
}
|
||||
|
29
src/main.cc
29
src/main.cc
@ -19,11 +19,38 @@
|
||||
#include <QDesktopWidget>
|
||||
#include <QFontDatabase>
|
||||
#include <QLibraryInfo>
|
||||
#include <QNetworkProxy>
|
||||
#include <QSettings>
|
||||
#include <QTranslator>
|
||||
|
||||
#include "MainWindow.h"
|
||||
|
||||
void
|
||||
setupProxy()
|
||||
{
|
||||
QSettings settings;
|
||||
|
||||
/**
|
||||
To set up a SOCKS proxy:
|
||||
[user]
|
||||
proxy\socks\host=<>
|
||||
proxy\socks\port=<>
|
||||
proxy\socks\user=<>
|
||||
proxy\socks\password=<>
|
||||
**/
|
||||
if (settings.contains("user/proxy/socks/host")) {
|
||||
QNetworkProxy proxy;
|
||||
proxy.setType(QNetworkProxy::Socks5Proxy);
|
||||
proxy.setHostName(settings.value("user/proxy/socks/host").toString());
|
||||
proxy.setPort(settings.value("user/proxy/socks/port").toInt());
|
||||
if (settings.contains("user/proxy/socks/user"))
|
||||
proxy.setUser(settings.value("user/proxy/socks/user").toString());
|
||||
if (settings.contains("user/proxy/socks/password"))
|
||||
proxy.setPassword(settings.value("user/proxy/socks/password").toString());
|
||||
QNetworkProxy::setApplicationProxy(proxy);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
@ -62,6 +89,8 @@ main(int argc, char *argv[])
|
||||
appTranslator.load("nheko_" + lang, ":/translations");
|
||||
app.installTranslator(&appTranslator);
|
||||
|
||||
setupProxy();
|
||||
|
||||
MainWindow w;
|
||||
|
||||
// Move the MainWindow to the center
|
||||
|
@ -22,8 +22,8 @@
|
||||
|
||||
OverlayModal::OverlayModal(QWidget *parent, QWidget *content)
|
||||
: OverlayWidget(parent)
|
||||
, duration_{ 500 }
|
||||
, color_{ QColor(55, 55, 55) }
|
||||
, duration_{500}
|
||||
, color_{QColor(55, 55, 55)}
|
||||
{
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
ScrollBar::ScrollBar(QScrollArea *area, QWidget *parent)
|
||||
: QScrollBar(parent)
|
||||
, area_{ area }
|
||||
, area_{area}
|
||||
{
|
||||
hideTimer_.setSingleShot(true);
|
||||
|
||||
|
@ -56,15 +56,21 @@ void
|
||||
Theme::setColor(const QString &key, ui::Color color)
|
||||
{
|
||||
static const QColor palette[] = {
|
||||
QColor("#171919"),
|
||||
QColor("#171919"),
|
||||
|
||||
QColor("#EBEBEB"), QColor("#C9C9C9"), QColor("#929292"),
|
||||
QColor("#EBEBEB"),
|
||||
QColor("#C9C9C9"),
|
||||
QColor("#929292"),
|
||||
|
||||
QColor("#1C3133"), QColor("#577275"), QColor("#46A451"),
|
||||
QColor("#1C3133"),
|
||||
QColor("#577275"),
|
||||
QColor("#46A451"),
|
||||
|
||||
QColor("#5D6565"), QColor("#E22826"), QColor("#81B3A9"),
|
||||
QColor("#5D6565"),
|
||||
QColor("#E22826"),
|
||||
QColor("#81B3A9"),
|
||||
|
||||
rgba(0, 0, 0, 0),
|
||||
rgba(0, 0, 0, 0),
|
||||
};
|
||||
|
||||
colors_.insert(key, palette[static_cast<int>(color)]);
|
||||
|
212
src/ui/ToggleButton.cc
Normal file
212
src/ui/ToggleButton.cc
Normal file
@ -0,0 +1,212 @@
|
||||
#include <QApplication>
|
||||
#include <QColor>
|
||||
#include <QEvent>
|
||||
#include <QPainter>
|
||||
|
||||
#include "ToggleButton.h"
|
||||
|
||||
void
|
||||
Toggle::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
}
|
||||
|
||||
Toggle::Toggle(QWidget *parent)
|
||||
: QAbstractButton{parent}
|
||||
{
|
||||
init();
|
||||
|
||||
connect(this, &QAbstractButton::toggled, this, &Toggle::setState);
|
||||
}
|
||||
|
||||
void
|
||||
Toggle::setState(bool isEnabled)
|
||||
{
|
||||
thumb_->setShift(isEnabled ? Position::Right : Position::Left);
|
||||
setupProperties();
|
||||
}
|
||||
|
||||
void
|
||||
Toggle::init()
|
||||
{
|
||||
track_ = new ToggleTrack(this);
|
||||
thumb_ = new ToggleThumb(this);
|
||||
|
||||
setCursor(QCursor(Qt::PointingHandCursor));
|
||||
setCheckable(true);
|
||||
setChecked(false);
|
||||
setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
|
||||
|
||||
setState(false);
|
||||
setupProperties();
|
||||
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
|
||||
void
|
||||
Toggle::setupProperties()
|
||||
{
|
||||
if (isEnabled()) {
|
||||
Position position = thumb_->shift();
|
||||
|
||||
thumb_->setThumbColor(trackColor());
|
||||
|
||||
if (position == Position::Left)
|
||||
track_->setTrackColor(activeColor());
|
||||
else if (position == Position::Right)
|
||||
track_->setTrackColor(inactiveColor());
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void
|
||||
Toggle::setDisabledColor(const QColor &color)
|
||||
{
|
||||
disabledColor_ = color;
|
||||
setupProperties();
|
||||
}
|
||||
|
||||
void
|
||||
Toggle::setActiveColor(const QColor &color)
|
||||
{
|
||||
activeColor_ = color;
|
||||
setupProperties();
|
||||
}
|
||||
|
||||
void
|
||||
Toggle::setInactiveColor(const QColor &color)
|
||||
{
|
||||
inactiveColor_ = color;
|
||||
setupProperties();
|
||||
}
|
||||
|
||||
void
|
||||
Toggle::setTrackColor(const QColor &color)
|
||||
{
|
||||
trackColor_ = color;
|
||||
setupProperties();
|
||||
}
|
||||
|
||||
ToggleThumb::ToggleThumb(Toggle *parent)
|
||||
: QWidget{parent}
|
||||
, toggle_{parent}
|
||||
, position_{Position::Right}
|
||||
, offset_{0}
|
||||
{
|
||||
parent->installEventFilter(this);
|
||||
}
|
||||
|
||||
void
|
||||
ToggleThumb::setShift(Position position)
|
||||
{
|
||||
if (position_ != position) {
|
||||
position_ = position;
|
||||
updateOffset();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ToggleThumb::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
const QEvent::Type type = event->type();
|
||||
|
||||
if (QEvent::Resize == type || QEvent::Move == type) {
|
||||
setGeometry(toggle_->rect().adjusted(8, 8, -8, -8));
|
||||
updateOffset();
|
||||
}
|
||||
|
||||
return QWidget::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
void
|
||||
ToggleThumb::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
QBrush brush;
|
||||
brush.setStyle(Qt::SolidPattern);
|
||||
brush.setColor(toggle_->isEnabled() ? thumbColor_ : Qt::white);
|
||||
|
||||
painter.setBrush(brush);
|
||||
painter.setPen(Qt::NoPen);
|
||||
|
||||
int s;
|
||||
QRectF r;
|
||||
|
||||
s = height() - 10;
|
||||
r = QRectF(5 + offset_, 5, s, s);
|
||||
|
||||
painter.drawEllipse(r);
|
||||
|
||||
if (!toggle_->isEnabled()) {
|
||||
brush.setColor(toggle_->disabledColor());
|
||||
painter.setBrush(brush);
|
||||
painter.drawEllipse(r);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ToggleThumb::updateOffset()
|
||||
{
|
||||
const QSize s(size());
|
||||
offset_ = position_ == Position::Left ? static_cast<qreal>(s.width() - s.height()) : 0;
|
||||
update();
|
||||
}
|
||||
|
||||
ToggleTrack::ToggleTrack(Toggle *parent)
|
||||
: QWidget{parent}
|
||||
, toggle_{parent}
|
||||
{
|
||||
Q_ASSERT(parent);
|
||||
|
||||
parent->installEventFilter(this);
|
||||
}
|
||||
|
||||
void
|
||||
ToggleTrack::setTrackColor(const QColor &color)
|
||||
{
|
||||
trackColor_ = color;
|
||||
update();
|
||||
}
|
||||
|
||||
bool
|
||||
ToggleTrack::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
const QEvent::Type type = event->type();
|
||||
|
||||
if (QEvent::Resize == type || QEvent::Move == type) {
|
||||
setGeometry(toggle_->rect());
|
||||
}
|
||||
|
||||
return QWidget::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
void
|
||||
ToggleTrack::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
QBrush brush;
|
||||
if (toggle_->isEnabled()) {
|
||||
brush.setColor(trackColor_);
|
||||
painter.setOpacity(0.8);
|
||||
} else {
|
||||
brush.setColor(toggle_->disabledColor());
|
||||
painter.setOpacity(0.6);
|
||||
}
|
||||
|
||||
brush.setStyle(Qt::SolidPattern);
|
||||
painter.setBrush(brush);
|
||||
painter.setPen(Qt::NoPen);
|
||||
|
||||
const int h = height() / 2;
|
||||
const QRect r(0, h / 2, width(), h);
|
||||
painter.drawRoundedRect(r.adjusted(14, 4, -14, -4), h / 2 - 4, h / 2 - 4);
|
||||
}
|
246
tests/events.cc
246
tests/events.cc
@ -22,8 +22,8 @@ using namespace matrix::events;
|
||||
TEST(BaseEvent, Deserialization)
|
||||
{
|
||||
// NameEventContent
|
||||
auto data = QJsonObject{ { "content", QJsonObject{ { "name", "Room Name" } } },
|
||||
{ "type", "m.room.name" } };
|
||||
auto data =
|
||||
QJsonObject{{"content", QJsonObject{{"name", "Room Name"}}}, {"type", "m.room.name"}};
|
||||
|
||||
Event<NameEventContent> name_event;
|
||||
name_event.deserialize(data);
|
||||
@ -31,47 +31,57 @@ TEST(BaseEvent, Deserialization)
|
||||
EXPECT_EQ(name_event.serialize(), data);
|
||||
|
||||
// TopicEventContent
|
||||
data = QJsonObject{ { "content", QJsonObject{ { "topic", "Room Topic" } } },
|
||||
{ "type", "m.room.topic" } };
|
||||
data = QJsonObject{{"content", QJsonObject{{"topic", "Room Topic"}}},
|
||||
{"unsigned", QJsonObject{{"age", 22}, {"transaction_id", "randomid"}}},
|
||||
{"type", "m.room.topic"}};
|
||||
|
||||
Event<TopicEventContent> topic_event;
|
||||
topic_event.deserialize(data);
|
||||
EXPECT_EQ(topic_event.content().topic(), "Room Topic");
|
||||
EXPECT_EQ(topic_event.unsignedData().age(), 22);
|
||||
EXPECT_EQ(topic_event.unsignedData().transactionId(), "randomid");
|
||||
EXPECT_EQ(topic_event.serialize(), data);
|
||||
|
||||
// AvatarEventContent
|
||||
data = QJsonObject{ { "content", QJsonObject{ { "url", "https://matrix.org" } } },
|
||||
{ "type", "m.room.avatar" } };
|
||||
data = QJsonObject{
|
||||
{"content", QJsonObject{{"url", "https://matrix.org"}}},
|
||||
{"unsigned", QJsonObject{{"age", 1343434343}, {"transaction_id", "m33434.33"}}},
|
||||
{"type", "m.room.avatar"}};
|
||||
|
||||
Event<AvatarEventContent> avatar_event;
|
||||
avatar_event.deserialize(data);
|
||||
EXPECT_EQ(avatar_event.content().url().toString(), "https://matrix.org");
|
||||
EXPECT_EQ(avatar_event.unsignedData().age(), 1343434343);
|
||||
EXPECT_EQ(avatar_event.unsignedData().transactionId(), "m33434.33");
|
||||
EXPECT_EQ(avatar_event.serialize(), data);
|
||||
|
||||
// AliasesEventContent
|
||||
data =
|
||||
QJsonObject{ { "content",
|
||||
QJsonObject{
|
||||
{ "aliases", QJsonArray{ "#test:matrix.org", "#test2:matrix.org" } } } },
|
||||
{ "type", "m.room.aliases" } };
|
||||
data = QJsonObject{
|
||||
{"content",
|
||||
QJsonObject{{"aliases", QJsonArray{"#test:matrix.org", "#test2:matrix.org"}}}},
|
||||
{"unsigned", QJsonObject{{"transaction_id", "m33434.33"}}},
|
||||
{"type", "m.room.aliases"}};
|
||||
|
||||
Event<AliasesEventContent> aliases_event;
|
||||
aliases_event.deserialize(data);
|
||||
EXPECT_EQ(aliases_event.content().aliases().size(), 2);
|
||||
EXPECT_EQ(aliases_event.unsignedData().transactionId(), "m33434.33");
|
||||
EXPECT_EQ(aliases_event.serialize(), data);
|
||||
|
||||
// CreateEventContent
|
||||
data = QJsonObject{ { "content", QJsonObject{ { "creator", "@alice:matrix.org" } } },
|
||||
{ "type", "m.room.create" } };
|
||||
data = QJsonObject{{"content", QJsonObject{{"creator", "@alice:matrix.org"}}},
|
||||
{"unsigned", QJsonObject{{"age", 2233}}},
|
||||
{"type", "m.room.create"}};
|
||||
|
||||
Event<CreateEventContent> create_event;
|
||||
create_event.deserialize(data);
|
||||
EXPECT_EQ(create_event.content().creator(), "@alice:matrix.org");
|
||||
EXPECT_EQ(create_event.unsignedData().age(), 2233);
|
||||
EXPECT_EQ(create_event.serialize(), data);
|
||||
|
||||
// JoinRulesEventContent
|
||||
data = QJsonObject{ { "content", QJsonObject{ { "join_rule", "private" } } },
|
||||
{ "type", "m.room.join_rules" } };
|
||||
data = QJsonObject{{"content", QJsonObject{{"join_rule", "private"}}},
|
||||
{"type", "m.room.join_rules"}};
|
||||
|
||||
Event<JoinRulesEventContent> join_rules_event;
|
||||
join_rules_event.deserialize(data);
|
||||
@ -81,27 +91,34 @@ TEST(BaseEvent, Deserialization)
|
||||
|
||||
TEST(BaseEvent, DeserializationException)
|
||||
{
|
||||
auto data = QJsonObject{ { "content", QJsonObject{ { "rule", "private" } } },
|
||||
{ "type", "m.room.join_rules" } };
|
||||
auto data =
|
||||
QJsonObject{{"content", QJsonObject{{"rule", "private"}}}, {"type", "m.room.join_rules"}};
|
||||
|
||||
Event<JoinRulesEventContent> event1;
|
||||
ASSERT_THROW(event1.deserialize(data), DeserializationException);
|
||||
|
||||
data = QJsonObject{ { "contents", QJsonObject{ { "join_rule", "private" } } },
|
||||
{ "type", "m.room.join_rules" } };
|
||||
data = QJsonObject{{"contents", QJsonObject{{"join_rule", "private"}}},
|
||||
{"type", "m.room.join_rules"}};
|
||||
|
||||
Event<JoinRulesEventContent> event2;
|
||||
ASSERT_THROW(event2.deserialize(data), DeserializationException);
|
||||
|
||||
data = QJsonObject{{"contents", QJsonObject{{"join_rule", "private"}}},
|
||||
{"unsigned", QJsonObject{{"age", "222"}}},
|
||||
{"type", "m.room.join_rules"}};
|
||||
|
||||
Event<JoinRulesEventContent> event3;
|
||||
ASSERT_THROW(event3.deserialize(data), DeserializationException);
|
||||
}
|
||||
|
||||
TEST(RoomEvent, Deserialization)
|
||||
{
|
||||
auto data = QJsonObject{ { "content", QJsonObject{ { "name", "Name" } } },
|
||||
{ "event_id", "$asdfafdf8af:matrix.org" },
|
||||
{ "room_id", "!aasdfaeae23r9:matrix.org" },
|
||||
{ "sender", "@alice:matrix.org" },
|
||||
{ "origin_server_ts", 1323238293289323LL },
|
||||
{ "type", "m.room.name" } };
|
||||
auto data = QJsonObject{{"content", QJsonObject{{"name", "Name"}}},
|
||||
{"event_id", "$asdfafdf8af:matrix.org"},
|
||||
{"room_id", "!aasdfaeae23r9:matrix.org"},
|
||||
{"sender", "@alice:matrix.org"},
|
||||
{"origin_server_ts", 1323238293289323LL},
|
||||
{"type", "m.room.name"}};
|
||||
|
||||
RoomEvent<NameEventContent> event;
|
||||
event.deserialize(data);
|
||||
@ -116,11 +133,11 @@ TEST(RoomEvent, Deserialization)
|
||||
|
||||
TEST(RoomEvent, DeserializationException)
|
||||
{
|
||||
auto data = QJsonObject{ { "content", QJsonObject{ { "name", "Name" } } },
|
||||
{ "event_id", "$asdfafdf8af:matrix.org" },
|
||||
{ "room_id", "!aasdfaeae23r9:matrix.org" },
|
||||
{ "origin_server_ts", 1323238293289323LL },
|
||||
{ "type", "m.room.name" } };
|
||||
auto data = QJsonObject{{"content", QJsonObject{{"name", "Name"}}},
|
||||
{"event_id", "$asdfafdf8af:matrix.org"},
|
||||
{"room_id", "!aasdfaeae23r9:matrix.org"},
|
||||
{"origin_server_ts", 1323238293289323LL},
|
||||
{"type", "m.room.name"}};
|
||||
|
||||
RoomEvent<NameEventContent> event;
|
||||
|
||||
@ -133,14 +150,14 @@ TEST(RoomEvent, DeserializationException)
|
||||
|
||||
TEST(StateEvent, Deserialization)
|
||||
{
|
||||
auto data = QJsonObject{ { "content", QJsonObject{ { "name", "Name" } } },
|
||||
{ "event_id", "$asdfafdf8af:matrix.org" },
|
||||
{ "state_key", "some_state_key" },
|
||||
{ "prev_content", QJsonObject{ { "name", "Previous Name" } } },
|
||||
{ "room_id", "!aasdfaeae23r9:matrix.org" },
|
||||
{ "sender", "@alice:matrix.org" },
|
||||
{ "origin_server_ts", 1323238293289323LL },
|
||||
{ "type", "m.room.name" } };
|
||||
auto data = QJsonObject{{"content", QJsonObject{{"name", "Name"}}},
|
||||
{"event_id", "$asdfafdf8af:matrix.org"},
|
||||
{"state_key", "some_state_key"},
|
||||
{"prev_content", QJsonObject{{"name", "Previous Name"}}},
|
||||
{"room_id", "!aasdfaeae23r9:matrix.org"},
|
||||
{"sender", "@alice:matrix.org"},
|
||||
{"origin_server_ts", 1323238293289323LL},
|
||||
{"type", "m.room.name"}};
|
||||
|
||||
StateEvent<NameEventContent> event;
|
||||
event.deserialize(data);
|
||||
@ -157,13 +174,13 @@ TEST(StateEvent, Deserialization)
|
||||
|
||||
TEST(StateEvent, DeserializationException)
|
||||
{
|
||||
auto data = QJsonObject{ { "content", QJsonObject{ { "name", "Name" } } },
|
||||
{ "event_id", "$asdfafdf8af:matrix.org" },
|
||||
{ "prev_content", QJsonObject{ { "name", "Previous Name" } } },
|
||||
{ "room_id", "!aasdfaeae23r9:matrix.org" },
|
||||
{ "sender", "@alice:matrix.org" },
|
||||
{ "origin_server_ts", 1323238293289323LL },
|
||||
{ "type", "m.room.name" } };
|
||||
auto data = QJsonObject{{"content", QJsonObject{{"name", "Name"}}},
|
||||
{"event_id", "$asdfafdf8af:matrix.org"},
|
||||
{"prev_content", QJsonObject{{"name", "Previous Name"}}},
|
||||
{"room_id", "!aasdfaeae23r9:matrix.org"},
|
||||
{"sender", "@alice:matrix.org"},
|
||||
{"origin_server_ts", 1323238293289323LL},
|
||||
{"type", "m.room.name"}};
|
||||
|
||||
StateEvent<NameEventContent> event;
|
||||
|
||||
@ -176,35 +193,30 @@ TEST(StateEvent, DeserializationException)
|
||||
|
||||
TEST(EventType, Mapping)
|
||||
{
|
||||
EXPECT_EQ(extractEventType(QJsonObject{ { "type", "m.room.aliases" } }),
|
||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.aliases"}}),
|
||||
EventType::RoomAliases);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{ { "type", "m.room.avatar" } }),
|
||||
EventType::RoomAvatar);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{ { "type", "m.room.canonical_alias" } }),
|
||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.avatar"}}), EventType::RoomAvatar);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.canonical_alias"}}),
|
||||
EventType::RoomCanonicalAlias);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{ { "type", "m.room.create" } }),
|
||||
EventType::RoomCreate);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{ { "type", "m.room.history_visibility" } }),
|
||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.create"}}), EventType::RoomCreate);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.history_visibility"}}),
|
||||
EventType::RoomHistoryVisibility);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{ { "type", "m.room.join_rules" } }),
|
||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.join_rules"}}),
|
||||
EventType::RoomJoinRules);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{ { "type", "m.room.member" } }),
|
||||
EventType::RoomMember);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{ { "type", "m.room.message" } }),
|
||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.member"}}), EventType::RoomMember);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.message"}}),
|
||||
EventType::RoomMessage);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{ { "type", "m.room.name" } }), EventType::RoomName);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{ { "type", "m.room.power_levels" } }),
|
||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.name"}}), EventType::RoomName);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.power_levels"}}),
|
||||
EventType::RoomPowerLevels);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{ { "type", "m.room.topic" } }),
|
||||
EventType::RoomTopic);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{ { "type", "m.room.unknown" } }),
|
||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.topic"}}), EventType::RoomTopic);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.unknown"}}),
|
||||
EventType::Unsupported);
|
||||
}
|
||||
|
||||
TEST(AliasesEventContent, Deserialization)
|
||||
{
|
||||
auto data =
|
||||
QJsonObject{ { "aliases", QJsonArray{ "#test:matrix.org", "#test2:matrix.org" } } };
|
||||
auto data = QJsonObject{{"aliases", QJsonArray{"#test:matrix.org", "#test2:matrix.org"}}};
|
||||
|
||||
AliasesEventContent content;
|
||||
content.deserialize(data);
|
||||
@ -215,7 +227,7 @@ TEST(AliasesEventContent, Deserialization)
|
||||
|
||||
TEST(AliasesEventContent, NotAnObject)
|
||||
{
|
||||
auto data = QJsonArray{ "#test:matrix.org", "#test2:matrix.org" };
|
||||
auto data = QJsonArray{"#test:matrix.org", "#test2:matrix.org"};
|
||||
|
||||
AliasesEventContent content;
|
||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
||||
@ -223,7 +235,7 @@ TEST(AliasesEventContent, NotAnObject)
|
||||
|
||||
TEST(AliasesEventContent, MissingKey)
|
||||
{
|
||||
auto data = QJsonObject{ { "key", QJsonArray{ "#test:matrix.org", "#test2:matrix.org" } } };
|
||||
auto data = QJsonObject{{"key", QJsonArray{"#test:matrix.org", "#test2:matrix.org"}}};
|
||||
|
||||
AliasesEventContent content;
|
||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
||||
@ -237,7 +249,7 @@ TEST(AliasesEventContent, MissingKey)
|
||||
|
||||
TEST(AvatarEventContent, Deserialization)
|
||||
{
|
||||
auto data = QJsonObject{ { "url", "https://matrix.org/avatar.png" } };
|
||||
auto data = QJsonObject{{"url", "https://matrix.org/avatar.png"}};
|
||||
|
||||
AvatarEventContent content;
|
||||
content.deserialize(data);
|
||||
@ -248,7 +260,7 @@ TEST(AvatarEventContent, Deserialization)
|
||||
|
||||
TEST(AvatarEventContent, NotAnObject)
|
||||
{
|
||||
auto data = QJsonArray{ "key", "url" };
|
||||
auto data = QJsonArray{"key", "url"};
|
||||
|
||||
AvatarEventContent content;
|
||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
||||
@ -256,7 +268,7 @@ TEST(AvatarEventContent, NotAnObject)
|
||||
|
||||
TEST(AvatarEventContent, MissingKey)
|
||||
{
|
||||
auto data = QJsonObject{ { "key", "https://matrix.org" } };
|
||||
auto data = QJsonObject{{"key", "https://matrix.org"}};
|
||||
|
||||
AvatarEventContent content;
|
||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
||||
@ -270,7 +282,7 @@ TEST(AvatarEventContent, MissingKey)
|
||||
|
||||
TEST(CreateEventContent, Deserialization)
|
||||
{
|
||||
auto data = QJsonObject{ { "creator", "@alice:matrix.org" } };
|
||||
auto data = QJsonObject{{"creator", "@alice:matrix.org"}};
|
||||
|
||||
CreateEventContent content;
|
||||
content.deserialize(data);
|
||||
@ -281,7 +293,7 @@ TEST(CreateEventContent, Deserialization)
|
||||
|
||||
TEST(CreateEventContent, NotAnObject)
|
||||
{
|
||||
auto data = QJsonArray{ "creator", "alice" };
|
||||
auto data = QJsonArray{"creator", "alice"};
|
||||
|
||||
CreateEventContent content;
|
||||
|
||||
@ -290,7 +302,7 @@ TEST(CreateEventContent, NotAnObject)
|
||||
|
||||
TEST(CreateEventContent, MissingKey)
|
||||
{
|
||||
auto data = QJsonObject{ { "key", "@alice:matrix.org" } };
|
||||
auto data = QJsonObject{{"key", "@alice:matrix.org"}};
|
||||
|
||||
CreateEventContent content;
|
||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
||||
@ -304,23 +316,23 @@ TEST(CreateEventContent, MissingKey)
|
||||
|
||||
TEST(HistoryVisibilityEventContent, Deserialization)
|
||||
{
|
||||
auto data = QJsonObject{ { "history_visibility", "invited" } };
|
||||
auto data = QJsonObject{{"history_visibility", "invited"}};
|
||||
|
||||
HistoryVisibilityEventContent content;
|
||||
content.deserialize(data);
|
||||
EXPECT_EQ(content.historyVisibility(), HistoryVisibility::Invited);
|
||||
|
||||
data = QJsonObject{ { "history_visibility", "joined" } };
|
||||
data = QJsonObject{{"history_visibility", "joined"}};
|
||||
|
||||
content.deserialize(data);
|
||||
EXPECT_EQ(content.historyVisibility(), HistoryVisibility::Joined);
|
||||
|
||||
data = QJsonObject{ { "history_visibility", "shared" } };
|
||||
data = QJsonObject{{"history_visibility", "shared"}};
|
||||
|
||||
content.deserialize(data);
|
||||
EXPECT_EQ(content.historyVisibility(), HistoryVisibility::Shared);
|
||||
|
||||
data = QJsonObject{ { "history_visibility", "world_readable" } };
|
||||
data = QJsonObject{{"history_visibility", "world_readable"}};
|
||||
|
||||
content.deserialize(data);
|
||||
EXPECT_EQ(content.historyVisibility(), HistoryVisibility::WorldReadable);
|
||||
@ -328,7 +340,7 @@ TEST(HistoryVisibilityEventContent, Deserialization)
|
||||
|
||||
TEST(HistoryVisibilityEventContent, NotAnObject)
|
||||
{
|
||||
auto data = QJsonArray{ "history_visibility", "alice" };
|
||||
auto data = QJsonArray{"history_visibility", "alice"};
|
||||
|
||||
HistoryVisibilityEventContent content;
|
||||
|
||||
@ -337,7 +349,7 @@ TEST(HistoryVisibilityEventContent, NotAnObject)
|
||||
|
||||
TEST(HistoryVisibilityEventContent, InvalidHistoryVisibility)
|
||||
{
|
||||
auto data = QJsonObject{ { "history_visibility", "wrong" } };
|
||||
auto data = QJsonObject{{"history_visibility", "wrong"}};
|
||||
|
||||
HistoryVisibilityEventContent content;
|
||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
||||
@ -351,7 +363,7 @@ TEST(HistoryVisibilityEventContent, InvalidHistoryVisibility)
|
||||
|
||||
TEST(HistoryVisibilityEventContent, MissingKey)
|
||||
{
|
||||
auto data = QJsonObject{ { "key", "joined" } };
|
||||
auto data = QJsonObject{{"key", "joined"}};
|
||||
|
||||
HistoryVisibilityEventContent content;
|
||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
||||
@ -365,23 +377,23 @@ TEST(HistoryVisibilityEventContent, MissingKey)
|
||||
|
||||
TEST(JoinRulesEventContent, Deserialization)
|
||||
{
|
||||
auto data = QJsonObject{ { "join_rule", "invite" } };
|
||||
auto data = QJsonObject{{"join_rule", "invite"}};
|
||||
|
||||
JoinRulesEventContent content;
|
||||
content.deserialize(data);
|
||||
EXPECT_EQ(content.joinRule(), JoinRule::Invite);
|
||||
|
||||
data = QJsonObject{ { "join_rule", "knock" } };
|
||||
data = QJsonObject{{"join_rule", "knock"}};
|
||||
|
||||
content.deserialize(data);
|
||||
EXPECT_EQ(content.joinRule(), JoinRule::Knock);
|
||||
|
||||
data = QJsonObject{ { "join_rule", "private" } };
|
||||
data = QJsonObject{{"join_rule", "private"}};
|
||||
|
||||
content.deserialize(data);
|
||||
EXPECT_EQ(content.joinRule(), JoinRule::Private);
|
||||
|
||||
data = QJsonObject{ { "join_rule", "public" } };
|
||||
data = QJsonObject{{"join_rule", "public"}};
|
||||
|
||||
content.deserialize(data);
|
||||
EXPECT_EQ(content.joinRule(), JoinRule::Public);
|
||||
@ -389,7 +401,7 @@ TEST(JoinRulesEventContent, Deserialization)
|
||||
|
||||
TEST(JoinRulesEventContent, NotAnObject)
|
||||
{
|
||||
auto data = QJsonArray{ "rule", "alice" };
|
||||
auto data = QJsonArray{"rule", "alice"};
|
||||
|
||||
JoinRulesEventContent content;
|
||||
|
||||
@ -398,7 +410,7 @@ TEST(JoinRulesEventContent, NotAnObject)
|
||||
|
||||
TEST(JoinRulesEventContent, InvalidHistoryVisibility)
|
||||
{
|
||||
auto data = QJsonObject{ { "join_rule", "wrong" } };
|
||||
auto data = QJsonObject{{"join_rule", "wrong"}};
|
||||
|
||||
JoinRulesEventContent content;
|
||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
||||
@ -412,7 +424,7 @@ TEST(JoinRulesEventContent, InvalidHistoryVisibility)
|
||||
|
||||
TEST(JoinRulesEventContent, MissingKey)
|
||||
{
|
||||
auto data = QJsonObject{ { "key", "invite" } };
|
||||
auto data = QJsonObject{{"key", "invite"}};
|
||||
|
||||
JoinRulesEventContent content;
|
||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
||||
@ -426,7 +438,7 @@ TEST(JoinRulesEventContent, MissingKey)
|
||||
|
||||
TEST(CanonicalAliasEventContent, Deserialization)
|
||||
{
|
||||
auto data = QJsonObject{ { "alias", "Room Alias" } };
|
||||
auto data = QJsonObject{{"alias", "Room Alias"}};
|
||||
|
||||
CanonicalAliasEventContent content;
|
||||
content.deserialize(data);
|
||||
@ -437,7 +449,7 @@ TEST(CanonicalAliasEventContent, Deserialization)
|
||||
|
||||
TEST(CanonicalAliasEventContent, NotAnObject)
|
||||
{
|
||||
auto data = QJsonArray{ "alias", "Room Alias" };
|
||||
auto data = QJsonArray{"alias", "Room Alias"};
|
||||
|
||||
CanonicalAliasEventContent content;
|
||||
|
||||
@ -446,7 +458,7 @@ TEST(CanonicalAliasEventContent, NotAnObject)
|
||||
|
||||
TEST(CanonicalAliasEventContent, MissingKey)
|
||||
{
|
||||
auto data = QJsonObject{ { "key", "alias" } };
|
||||
auto data = QJsonObject{{"key", "alias"}};
|
||||
|
||||
CanonicalAliasEventContent content;
|
||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
||||
@ -462,29 +474,29 @@ TEST(MemberEventContent, Deserialization)
|
||||
{
|
||||
MemberEventContent content;
|
||||
|
||||
auto data = QJsonObject{ { "membership", "join" } };
|
||||
auto data = QJsonObject{{"membership", "join"}};
|
||||
|
||||
content.deserialize(data);
|
||||
EXPECT_EQ(content.membershipState(), Membership::Join);
|
||||
|
||||
data = QJsonObject{ { "membership", "invite" }, { "displayname", "Username" } };
|
||||
data = QJsonObject{{"membership", "invite"}, {"displayname", "Username"}};
|
||||
|
||||
content.deserialize(data);
|
||||
EXPECT_EQ(content.membershipState(), Membership::Invite);
|
||||
EXPECT_EQ(content.displayName(), "Username");
|
||||
|
||||
data = QJsonObject{ { "membership", "leave" }, { "avatar_url", "https://matrix.org" } };
|
||||
data = QJsonObject{{"membership", "leave"}, {"avatar_url", "https://matrix.org"}};
|
||||
|
||||
content.deserialize(data);
|
||||
EXPECT_EQ(content.membershipState(), Membership::Leave);
|
||||
EXPECT_EQ(content.avatarUrl().toString(), "https://matrix.org");
|
||||
|
||||
data = QJsonObject{ { "membership", "ban" } };
|
||||
data = QJsonObject{{"membership", "ban"}};
|
||||
|
||||
content.deserialize(data);
|
||||
EXPECT_EQ(content.membershipState(), Membership::Ban);
|
||||
|
||||
data = QJsonObject{ { "membership", "knock" } };
|
||||
data = QJsonObject{{"membership", "knock"}};
|
||||
|
||||
content.deserialize(data);
|
||||
EXPECT_EQ(content.membershipState(), Membership::Knock);
|
||||
@ -492,7 +504,7 @@ TEST(MemberEventContent, Deserialization)
|
||||
|
||||
TEST(MemberEventContent, InvalidMembership)
|
||||
{
|
||||
auto data = QJsonObject{ { "membership", "wrong" } };
|
||||
auto data = QJsonObject{{"membership", "wrong"}};
|
||||
|
||||
MemberEventContent content;
|
||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
||||
@ -506,7 +518,7 @@ TEST(MemberEventContent, InvalidMembership)
|
||||
|
||||
TEST(MemberEventContent, NotAnObject)
|
||||
{
|
||||
auto data = QJsonArray{ "name", "join" };
|
||||
auto data = QJsonArray{"name", "join"};
|
||||
|
||||
MemberEventContent content;
|
||||
|
||||
@ -515,7 +527,7 @@ TEST(MemberEventContent, NotAnObject)
|
||||
|
||||
TEST(MemberEventContent, MissingName)
|
||||
{
|
||||
auto data = QJsonObject{ { "key", "random" } };
|
||||
auto data = QJsonObject{{"key", "random"}};
|
||||
|
||||
MemberEventContent content;
|
||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
||||
@ -529,7 +541,7 @@ TEST(MemberEventContent, MissingName)
|
||||
|
||||
TEST(NameEventContent, Deserialization)
|
||||
{
|
||||
auto data = QJsonObject{ { "name", "Room Name" } };
|
||||
auto data = QJsonObject{{"name", "Room Name"}};
|
||||
|
||||
NameEventContent content;
|
||||
content.deserialize(data);
|
||||
@ -540,7 +552,7 @@ TEST(NameEventContent, Deserialization)
|
||||
|
||||
TEST(NameEventContent, NotAnObject)
|
||||
{
|
||||
auto data = QJsonArray{ "name", "Room Name" };
|
||||
auto data = QJsonArray{"name", "Room Name"};
|
||||
|
||||
NameEventContent content;
|
||||
|
||||
@ -549,7 +561,7 @@ TEST(NameEventContent, NotAnObject)
|
||||
|
||||
TEST(NameEventContent, MissingName)
|
||||
{
|
||||
auto data = QJsonObject{ { "key", "Room Name" } };
|
||||
auto data = QJsonObject{{"key", "Room Name"}};
|
||||
|
||||
NameEventContent content;
|
||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
||||
@ -582,17 +594,17 @@ TEST(PowerLevelsEventContent, DefaultValues)
|
||||
TEST(PowerLevelsEventContent, FullDeserialization)
|
||||
{
|
||||
auto data = QJsonObject{
|
||||
{ "ban", 1 },
|
||||
{ "invite", 2 },
|
||||
{ "kick", 3 },
|
||||
{ "redact", 4 },
|
||||
{"ban", 1},
|
||||
{"invite", 2},
|
||||
{"kick", 3},
|
||||
{"redact", 4},
|
||||
|
||||
{ "events_default", 5 },
|
||||
{ "state_default", 6 },
|
||||
{ "users_default", 7 },
|
||||
{"events_default", 5},
|
||||
{"state_default", 6},
|
||||
{"users_default", 7},
|
||||
|
||||
{ "events", QJsonObject{ { "m.message.text", 8 }, { "m.message.image", 9 } } },
|
||||
{ "users", QJsonObject{ { "@alice:matrix.org", 10 }, { "@bob:matrix.org", 11 } } },
|
||||
{"events", QJsonObject{{"m.message.text", 8}, {"m.message.image", 9}}},
|
||||
{"users", QJsonObject{{"@alice:matrix.org", 10}, {"@bob:matrix.org", 11}}},
|
||||
};
|
||||
|
||||
PowerLevelsEventContent power_levels;
|
||||
@ -621,13 +633,13 @@ TEST(PowerLevelsEventContent, FullDeserialization)
|
||||
TEST(PowerLevelsEventContent, PartialDeserialization)
|
||||
{
|
||||
auto data = QJsonObject{
|
||||
{ "ban", 1 },
|
||||
{ "invite", 2 },
|
||||
{"ban", 1},
|
||||
{"invite", 2},
|
||||
|
||||
{ "events_default", 5 },
|
||||
{ "users_default", 7 },
|
||||
{"events_default", 5},
|
||||
{"users_default", 7},
|
||||
|
||||
{ "users", QJsonObject{ { "@alice:matrix.org", 10 }, { "@bob:matrix.org", 11 } } },
|
||||
{"users", QJsonObject{{"@alice:matrix.org", 10}, {"@bob:matrix.org", 11}}},
|
||||
};
|
||||
|
||||
PowerLevelsEventContent power_levels;
|
||||
@ -653,7 +665,7 @@ TEST(PowerLevelsEventContent, PartialDeserialization)
|
||||
|
||||
TEST(PowerLevelsEventContent, NotAnObject)
|
||||
{
|
||||
auto data = QJsonArray{ "test", "test2" };
|
||||
auto data = QJsonArray{"test", "test2"};
|
||||
|
||||
PowerLevelsEventContent power_levels;
|
||||
|
||||
@ -662,7 +674,7 @@ TEST(PowerLevelsEventContent, NotAnObject)
|
||||
|
||||
TEST(TopicEventContent, Deserialization)
|
||||
{
|
||||
auto data = QJsonObject{ { "topic", "Room Topic" } };
|
||||
auto data = QJsonObject{{"topic", "Room Topic"}};
|
||||
|
||||
TopicEventContent content;
|
||||
content.deserialize(data);
|
||||
@ -673,7 +685,7 @@ TEST(TopicEventContent, Deserialization)
|
||||
|
||||
TEST(TopicEventContent, NotAnObject)
|
||||
{
|
||||
auto data = QJsonArray{ "topic", "Room Topic" };
|
||||
auto data = QJsonArray{"topic", "Room Topic"};
|
||||
|
||||
TopicEventContent content;
|
||||
|
||||
@ -682,7 +694,7 @@ TEST(TopicEventContent, NotAnObject)
|
||||
|
||||
TEST(TopicEventContent, MissingName)
|
||||
{
|
||||
auto data = QJsonObject{ { "key", "Room Name" } };
|
||||
auto data = QJsonObject{{"key", "Room Name"}};
|
||||
|
||||
TopicEventContent content;
|
||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
||||
|
Loading…
Reference in New Issue
Block a user