Move to automatic type registration

pull/1500/head
Nicolas Werner 1 year ago
parent 2cb04fd741
commit ce1a64bc19
No known key found for this signature in database
GPG Key ID: C8D75E610773F2D9
  1. 136
      CMakeLists.txt
  2. 2
      resources/qml/Avatar.qml
  3. 2
      resources/qml/ImageButton.qml
  4. 2
      resources/qml/MatrixText.qml
  5. 4
      resources/qml/MessageView.qml
  6. 8
      resources/qml/Root.qml
  7. 2
      resources/qml/TimelineRow.qml
  8. 19
      resources/qml/TimelineView.qml
  9. 2
      resources/qml/TopBar.qml
  10. 2
      resources/qml/components/AdaptiveLayout.qml
  11. 2
      resources/qml/components/TextButton.qml
  12. 2
      resources/qml/delegates/FileMessage.qml
  13. 2
      resources/qml/delegates/Reply.qml
  14. 2
      resources/qml/delegates/TextMessage.qml
  15. 2
      resources/qml/dialogs/InviteDialog.qml
  16. 2
      resources/qml/dialogs/ReadReceipts.qml
  17. 2
      resources/qml/dialogs/RoomMembers.qml
  18. 2
      resources/qml/dialogs/RoomSettings.qml
  19. 1
      resources/qml/emoji/StickerPicker.qml
  20. 2
      resources/qml/ui/animations/qmldir
  21. 3
      resources/qml/ui/media/qmldir
  22. 4
      resources/qml/ui/qmldir
  23. 24
      resources/qml/voip/ActiveCallBar.qml
  24. 2
      resources/qml/voip/CallDevices.qml
  25. 8
      resources/qml/voip/CallInvite.qml
  26. 8
      resources/qml/voip/CallInviteBar.qml
  27. 4
      resources/qml/voip/PlaceCall.qml
  28. 8
      resources/qml/voip/ScreenShare.qml
  29. 100
      resources/res.qrc
  30. 4
      src/AliasEditModel.h
  31. 3
      src/CacheCryptoStructs.h
  32. 4
      src/Clipboard.h
  33. 8
      src/LoginPage.h
  34. 215
      src/MainWindow.cpp
  35. 25
      src/MainWindow.h
  36. 4
      src/PowerlevelsEditModels.h
  37. 4
      src/ReadReceiptsModel.h
  38. 2
      src/RegisterPage.h
  39. 2
      src/RoomDirectoryModel.h
  40. 2
      src/UserDirectoryModel.h
  41. 24
      src/UserSettingsPage.h
  42. 3
      src/encryption/Olm.h
  43. 5
      src/encryption/SelfVerificationStatus.cpp
  44. 4
      src/encryption/SelfVerificationStatus.h
  45. 1
      src/encryption/VerificationManager.cpp
  46. 27
      src/encryption/VerificationManager.h
  47. 2
      src/main.cpp
  48. 1
      src/timeline/CommunitiesModel.cpp
  49. 28
      src/timeline/CommunitiesModel.h
  50. 2
      src/timeline/DelegateChooser.h
  51. 6
      src/timeline/InputBar.h
  52. 27
      src/timeline/PresenceEmitter.h
  53. 2
      src/timeline/RoomlistModel.cpp
  54. 26
      src/timeline/RoomlistModel.h
  55. 2
      src/timeline/TimelineFilter.h
  56. 5
      src/timeline/TimelineModel.h
  57. 30
      src/timeline/TimelineViewManager.cpp
  58. 25
      src/timeline/TimelineViewManager.h
  59. 2
      src/ui/HiddenEvents.h
  60. 1
      src/ui/MxcAnimatedImage.h
  61. 3
      src/ui/MxcMediaProxy.h
  62. 2
      src/ui/NhekoCursorShape.h
  63. 1
      src/ui/NhekoDropArea.h
  64. 60
      src/ui/NhekoEventObserver.cpp
  65. 27
      src/ui/NhekoEventObserver.h
  66. 4
      src/ui/NhekoGlobalObject.h
  67. 4
      src/ui/RoomSummary.h
  68. 22
      src/ui/UIA.h
  69. 2
      src/ui/UserProfile.h
  70. 21
      src/voip/CallManager.cpp
  71. 7
      src/voip/CallManager.h
  72. 40
      src/voip/WebRTCSession.cpp
  73. 2
      src/voip/WebRTCSession.h

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13..3.21)
option(APPVEYOR_BUILD "Build on appveyor" OFF) option(APPVEYOR_BUILD "Build on appveyor" OFF)
option(CI_BUILD "Set when building in CI. Enables -Werror where possible" OFF) option(CI_BUILD "Set when building in CI. Enables -Werror where possible" OFF)
@ -395,8 +395,6 @@ set(SRC_FILES
src/ui/NhekoCursorShape.h src/ui/NhekoCursorShape.h
src/ui/NhekoDropArea.cpp src/ui/NhekoDropArea.cpp
src/ui/NhekoDropArea.h src/ui/NhekoDropArea.h
src/ui/NhekoEventObserver.cpp
src/ui/NhekoEventObserver.h
src/ui/NhekoGlobalObject.cpp src/ui/NhekoGlobalObject.cpp
src/ui/NhekoGlobalObject.h src/ui/NhekoGlobalObject.h
src/ui/RoomSettings.cpp src/ui/RoomSettings.cpp
@ -499,8 +497,6 @@ set(SRC_FILES
src/SingleImagePackModel.h src/SingleImagePackModel.h
src/TrayIcon.cpp src/TrayIcon.cpp
src/TrayIcon.h src/TrayIcon.h
src/UserDirectoryModel.cpp
src/UserDirectoryModel.h
src/UserSettingsPage.cpp src/UserSettingsPage.cpp
src/UserSettingsPage.h src/UserSettingsPage.h
src/UsersModel.cpp src/UsersModel.cpp
@ -679,10 +675,10 @@ if(ASAN)
endif() endif()
if(WIN32) if(WIN32)
add_executable (nheko WIN32 ${OS_BUNDLE} ${NHEKO_DEPS}) qt_add_executable (nheko WIN32 ${OS_BUNDLE} ${NHEKO_DEPS})
target_compile_definitions(nheko PRIVATE _WIN32_WINNT=0x0601 NOMINMAX WIN32_LEAN_AND_MEAN STRICT) target_compile_definitions(nheko PRIVATE _WIN32_WINNT=0x0601 NOMINMAX WIN32_LEAN_AND_MEAN STRICT)
else() else()
add_executable (nheko ${OS_BUNDLE} ${NHEKO_DEPS}) qt_add_executable (nheko ${OS_BUNDLE} ${NHEKO_DEPS})
if (HAVE_BACKTRACE_SYMBOLS_FD AND NOT CMAKE_BUILD_TYPE STREQUAL "Release") if (HAVE_BACKTRACE_SYMBOLS_FD AND NOT CMAKE_BUILD_TYPE STREQUAL "Release")
set_target_properties(nheko PROPERTIES ENABLE_EXPORTS ON) set_target_properties(nheko PROPERTIES ENABLE_EXPORTS ON)
@ -700,6 +696,130 @@ set_target_properties(nheko
file(GLOB LANG_TS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/resources/langs/*.ts") file(GLOB LANG_TS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/resources/langs/*.ts")
qt_add_translations(nheko RESOURCE_PREFIX "/translations" TS_FILES ${LANG_TS_SRC}) qt_add_translations(nheko RESOURCE_PREFIX "/translations" TS_FILES ${LANG_TS_SRC})
#
# Add qml files
#
set(QML_SOURCES
resources/qml/Root.qml
resources/qml/ChatPage.qml
resources/qml/CommunitiesList.qml
resources/qml/RoomList.qml
resources/qml/TimelineView.qml
resources/qml/Avatar.qml
resources/qml/Completer.qml
resources/qml/EncryptionIndicator.qml
resources/qml/ImageButton.qml
resources/qml/ElidedLabel.qml
resources/qml/MatrixText.qml
resources/qml/MatrixTextField.qml
resources/qml/ToggleButton.qml
resources/qml/UploadBox.qml
resources/qml/MessageInput.qml
resources/qml/MessageView.qml
resources/qml/PrivacyScreen.qml
resources/qml/Reactions.qml
resources/qml/ReplyPopup.qml
resources/qml/StatusIndicator.qml
resources/qml/TimelineRow.qml
resources/qml/TopBar.qml
resources/qml/QuickSwitcher.qml
resources/qml/ForwardCompleter.qml
resources/qml/SelfVerificationCheck.qml
resources/qml/TypingIndicator.qml
resources/qml/MessageInputWarning.qml
resources/qml/components/AdaptiveLayout.qml
resources/qml/components/AdaptiveLayoutElement.qml
resources/qml/components/AvatarListTile.qml
resources/qml/components/FlatButton.qml
resources/qml/components/MainWindowDialog.qml
resources/qml/components/NhekoTabButton.qml
resources/qml/components/NotificationBubble.qml
resources/qml/components/ReorderableListview.qml
resources/qml/components/SpaceMenuLevel.qml
resources/qml/components/TextButton.qml
resources/qml/components/UserListRow.qml
resources/qml/delegates/Encrypted.qml
resources/qml/delegates/FileMessage.qml
resources/qml/delegates/ImageMessage.qml
resources/qml/delegates/MessageDelegate.qml
resources/qml/delegates/NoticeMessage.qml
resources/qml/delegates/Pill.qml
resources/qml/delegates/Placeholder.qml
resources/qml/delegates/PlayableMediaMessage.qml
resources/qml/delegates/Redacted.qml
resources/qml/delegates/Reply.qml
resources/qml/delegates/TextMessage.qml
resources/qml/device-verification/DeviceVerification.qml
resources/qml/device-verification/DigitVerification.qml
resources/qml/device-verification/EmojiVerification.qml
resources/qml/device-verification/Failed.qml
resources/qml/device-verification/NewVerificationRequest.qml
resources/qml/device-verification/Success.qml
resources/qml/device-verification/Waiting.qml
resources/qml/dialogs/AliasEditor.qml
resources/qml/dialogs/ConfirmJoinRoomDialog.qml
resources/qml/dialogs/CreateDirect.qml
resources/qml/dialogs/CreateRoom.qml
resources/qml/dialogs/HiddenEventsDialog.qml
resources/qml/dialogs/ImageOverlay.qml
resources/qml/dialogs/ImagePackEditorDialog.qml
resources/qml/dialogs/ImagePackSettingsDialog.qml
resources/qml/dialogs/InputDialog.qml
resources/qml/dialogs/InviteDialog.qml
resources/qml/dialogs/JoinRoomDialog.qml
resources/qml/dialogs/LeaveRoomDialog.qml
resources/qml/dialogs/LogoutDialog.qml
resources/qml/dialogs/PhoneNumberInputDialog.qml
resources/qml/dialogs/PowerLevelEditor.qml
resources/qml/dialogs/PowerLevelSpacesApplyDialog.qml
resources/qml/dialogs/RawMessageDialog.qml
resources/qml/dialogs/ReadReceipts.qml
resources/qml/dialogs/RoomDirectory.qml
resources/qml/dialogs/RoomMembers.qml
resources/qml/dialogs/AllowedRoomsSettingsDialog.qml
resources/qml/dialogs/RoomSettings.qml
resources/qml/dialogs/UserProfile.qml
resources/qml/emoji/StickerPicker.qml
resources/qml/pages/LoginPage.qml
resources/qml/pages/RegisterPage.qml
resources/qml/pages/UserSettingsPage.qml
resources/qml/pages/WelcomePage.qml
resources/qml/ui/NhekoSlider.qml
resources/qml/ui/Ripple.qml
resources/qml/ui/Snackbar.qml
resources/qml/ui/Spinner.qml
resources/qml/ui/animations/BlinkAnimation.qml
resources/qml/ui/media/MediaControls.qml
resources/qml/voip/ActiveCallBar.qml
resources/qml/voip/CallDevices.qml
resources/qml/voip/CallInvite.qml
resources/qml/voip/CallInviteBar.qml
resources/qml/voip/DeviceError.qml
resources/qml/voip/PlaceCall.qml
resources/qml/voip/ScreenShare.qml
resources/qml/voip/VideoCall.qml
resources/qml/delegates/EncryptionEnabled.qml
resources/qml/ui/TimelineEffects.qml
)
qt_add_qml_module(nheko
URI im.nheko
NO_RESOURCE_TARGET_PATH
RESOURCE_PREFIX "/"
VERSION 1.1
DEPENDENCIES QtQml QtQuick # https://bugreports.qt.io/browse/QTBUG-102554
QML_FILES
${QML_SOURCES}
SOURCES
src/UserDirectoryModel.cpp
src/UserDirectoryModel.h
)
#qt_target_qml_sources(nheko
# #PREFIX "/"
#)
if(WIN32) if(WIN32)
target_compile_definitions(nheko PRIVATE WIN32_LEAN_AND_MEAN) target_compile_definitions(nheko PRIVATE WIN32_LEAN_AND_MEAN)
if(MSVC) if(MSVC)
@ -712,7 +832,7 @@ else()
endif() endif()
endif() endif()
target_include_directories(nheko PRIVATE src includes) target_include_directories(nheko PRIVATE src includes src/timeline/ src/ui/ src/encryption/ src/voip/)
if (USE_BUNDLED_CPPHTTPLIB) if (USE_BUNDLED_CPPHTTPLIB)
target_include_directories(nheko PRIVATE third_party/cpp-httplib-0.5.12) target_include_directories(nheko PRIVATE third_party/cpp-httplib-0.5.12)

@ -102,7 +102,7 @@ AbstractButton {
target: Presence target: Presence
} }
} }
CursorShape { NhekoCursorShape {
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
} }

@ -31,7 +31,7 @@ AbstractButton {
sourceSize.height: button.height sourceSize.height: button.height
sourceSize.width: button.width sourceSize.width: button.width
} }
CursorShape { NhekoCursorShape {
id: mouseArea id: mouseArea
anchors.fill: parent anchors.fill: parent

@ -44,7 +44,7 @@ TextArea {
onPressAndHold: (event) => event.accepted = false onPressAndHold: (event) => event.accepted = false
onPressed: (event) => event.accepted = (event.button == Qt.LeftButton) onPressed: (event) => event.accepted = (event.button == Qt.LeftButton)
CursorShape { NhekoCursorShape {
id: cs id: cs
anchors.fill: parent anchors.fill: parent

@ -332,7 +332,7 @@ Item {
sourceSize.height: button.height sourceSize.height: button.height
sourceSize.width: button.width sourceSize.width: button.width
} }
CursorShape { NhekoCursorShape {
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
} }
@ -590,7 +590,7 @@ Item {
elideWidth: userInfo.remainingWidth - Math.min(statusMsg.implicitWidth, userInfo.remainingWidth / 3) elideWidth: userInfo.remainingWidth - Math.min(statusMsg.implicitWidth, userInfo.remainingWidth / 3)
text: userName text: userName
} }
CursorShape { NhekoCursorShape {
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
} }

@ -15,7 +15,6 @@ import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Window import QtQuick.Window
import im.nheko import im.nheko
import im.nheko.EmojiModel
Pane { Pane {
id: timelineRoot id: timelineRoot
@ -92,15 +91,14 @@ Pane {
FontMetrics { FontMetrics {
id: fontMetrics id: fontMetrics
}
RoomDirectoryModel {
id: publicRooms
} }
UserDirectoryModel { UserDirectoryModel {
id: userDirectory id: userDirectory
} }
RoomDirectoryModel {
id: publicRooms
}
Component { Component {
id: readReceiptsDialog id: readReceiptsDialog

@ -173,7 +173,7 @@ AbstractButton {
Layout.row: 0 Layout.row: 0
blurhash: r.relatedEventCacheBuster, fromModel(Room.Blurhash) ?? "" blurhash: r.relatedEventCacheBuster, fromModel(Room.Blurhash) ?? ""
body: r.relatedEventCacheBuster, fromModel(Room.Body) ?? "" body: r.relatedEventCacheBuster, fromModel(Room.Body) ?? ""
callType: r.relatedEventCacheBuster, fromModel(Room.CallType) ?? "" callType: r.relatedEventCacheBuster, fromModel(Room.Voip) ?? ""
duration: r.relatedEventCacheBuster, fromModel(Room.Duration) ?? 0 duration: r.relatedEventCacheBuster, fromModel(Room.Duration) ?? 0
encryptionError: r.relatedEventCacheBuster, fromModel(Room.EncryptionError) ?? 0 encryptionError: r.relatedEventCacheBuster, fromModel(Room.EncryptionError) ?? 0
eventId: fromModel(Room.EventId) ?? "" eventId: fromModel(Room.EventId) ?? ""

@ -8,14 +8,13 @@ import "./device-verification"
import "./emoji" import "./emoji"
import "./ui" import "./ui"
import "./voip" import "./voip"
import Qt.labs.platform 1.1 as Platform import Qt.labs.platform as Platform
import QtQuick 2.15 import QtQuick
import QtQuick.Controls 2.5 import QtQuick.Controls
import QtQuick.Layouts 1.3 import QtQuick.Layouts
import QtQuick.Particles 2.15 import QtQuick.Particles
import QtQuick.Window 2.13 import QtQuick.Window
import im.nheko 1.0 import im.nheko
import im.nheko.EmojiModel 1.0
Item { Item {
id: timelineView id: timelineView
@ -123,7 +122,7 @@ Item {
searchString: topBar.searchString searchString: topBar.searchString
} }
Loader { Loader {
source: CallManager.isOnCall && CallManager.callType != CallType.VOICE ? "voip/VideoCall.qml" : "" source: CallManager.isOnCall && CallManager.callType != Voip.VOICE ? "voip/VideoCall.qml" : ""
onLoaded: TimelineManager.setVideoCallItem() onLoaded: TimelineManager.setVideoCallItem()
} }
@ -249,7 +248,7 @@ Item {
onLinkActivated: Nheko.openLink(link) onLinkActivated: Nheko.openLink(link)
CursorShape { NhekoCursorShape {
anchors.fill: parent anchors.fill: parent
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
} }

@ -369,7 +369,7 @@ Pane {
onAccepted: topBar.searchString = text onAccepted: topBar.searchString = text
} }
} }
CursorShape { NhekoCursorShape {
anchors.bottomMargin: (pinnedMessages.visible ? pinnedMessages.height : 0) + (widgets.visible ? widgets.height : 0) anchors.bottomMargin: (pinnedMessages.visible ? pinnedMessages.height : 0) + (widgets.visible ? widgets.height : 0)
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor

@ -87,7 +87,7 @@ Container {
x: parent.preferredWidth x: parent.preferredWidth
z: 3 z: 3
CursorShape { NhekoCursorShape {
height: parent.height height: parent.height
width: container.splitterGrabMargin * 2 width: container.splitterGrabMargin * 2
x: -container.splitterGrabMargin x: -container.splitterGrabMargin

@ -32,7 +32,7 @@ AbstractButton {
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
} }
CursorShape { NhekoCursorShape {
id: mouseArea id: mouseArea
anchors.fill: parent anchors.fill: parent

@ -49,7 +49,7 @@ Item {
gesturePolicy: TapHandler.ReleaseWithinBounds gesturePolicy: TapHandler.ReleaseWithinBounds
} }
CursorShape { NhekoCursorShape {
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
} }

@ -43,7 +43,7 @@ AbstractButton {
implicitHeight: replyContainer.height implicitHeight: replyContainer.height
implicitWidth: visible? colorLine.width+Math.max(replyContainer.implicitWidth,userName_.fullTextWidth) : 0 // visible? seems to be causing issues implicitWidth: visible? colorLine.width+Math.max(replyContainer.implicitWidth,userName_.fullTextWidth) : 0 // visible? seems to be causing issues
CursorShape { NhekoCursorShape {
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
} }

@ -46,7 +46,7 @@ MatrixText {
enabled: !Settings.mobileMode enabled: !Settings.mobileMode
font.pointSize: (Settings.enlargeEmojiOnlyMessages && isOnlyEmoji > 0 && isOnlyEmoji < 4) ? Settings.fontSize * 3 : Settings.fontSize font.pointSize: (Settings.enlargeEmojiOnlyMessages && isOnlyEmoji > 0 && isOnlyEmoji < 4) ? Settings.fontSize * 3 : Settings.fontSize
CursorShape { NhekoCursorShape {
enabled: isReply enabled: isReply
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor

@ -212,7 +212,7 @@ ApplicationWindow {
onClicked: invitees.removeUser(model.mxid) onClicked: invitees.removeUser(model.mxid)
} }
CursorShape { NhekoCursorShape {
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
} }

@ -110,7 +110,7 @@ ApplicationWindow {
} }
CursorShape { NhekoCursorShape {
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
} }

@ -220,7 +220,7 @@ ApplicationWindow {
} }
CursorShape { NhekoCursorShape {
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
} }

@ -213,7 +213,7 @@ ApplicationWindow {
horizontalAlignment: TextEdit.AlignHCenter horizontalAlignment: TextEdit.AlignHCenter
onLinkActivated: Nheko.openLink(link) onLinkActivated: Nheko.openLink(link)
CursorShape { NhekoCursorShape {
anchors.fill: parent anchors.fill: parent
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
} }

@ -7,7 +7,6 @@ import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import im.nheko import im.nheko
import im.nheko.EmojiModel
Menu { Menu {
id: stickerPopup id: stickerPopup

@ -1,2 +0,0 @@
module im.nheko.UI.Animations
BlinkAnimation 1.0 BlinkAnimation.qml

@ -1,3 +0,0 @@
module im.nheko.UI.Media
VolumeSlider 1.0 VolumeSlider.qml
MediaControls 1.0 MediaControls.qml

@ -1,4 +0,0 @@
module im.nheko.UI
NhekoSlider 1.0 NhekoSlider.qml
Ripple 1.0 Ripple.qml
Spinner 1.0 Spinner.qml

@ -16,7 +16,7 @@ Rectangle {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {
if (CallManager.callType != CallType.VOICE) if (CallManager.callType != Voip.VOICE)
stackLayout.currentIndex = stackLayout.currentIndex ? 0 : 1; stackLayout.currentIndex = stackLayout.currentIndex ? 0 : 1;
} }
@ -58,7 +58,7 @@ Rectangle {
states: [ states: [
State { State {
name: "VOICE" name: "VOICE"
when: CallManager.callType == CallType.VOICE when: CallManager.callType == Voip.VOICE
PropertyChanges { PropertyChanges {
target: callTypeIcon target: callTypeIcon
@ -68,7 +68,7 @@ Rectangle {
}, },
State { State {
name: "VIDEO" name: "VIDEO"
when: CallManager.callType == CallType.VIDEO when: CallManager.callType == Voip.VIDEO
PropertyChanges { PropertyChanges {
target: callTypeIcon target: callTypeIcon
@ -78,7 +78,7 @@ Rectangle {
}, },
State { State {
name: "SCREEN" name: "SCREEN"
when: CallManager.callType == CallType.SCREEN when: CallManager.callType == Voip.SCREEN
PropertyChanges { PropertyChanges {
target: callTypeIcon target: callTypeIcon
@ -100,7 +100,7 @@ Rectangle {
states: [ states: [
State { State {
name: "OFFERSENT" name: "OFFERSENT"
when: CallManager.callState == WebRTCState.OFFERSENT when: CallManager.callState == Voip.OFFERSENT
PropertyChanges { PropertyChanges {
target: callStateLabel target: callStateLabel
@ -110,7 +110,7 @@ Rectangle {
}, },
State { State {
name: "CONNECTING" name: "CONNECTING"
when: CallManager.callState == WebRTCState.CONNECTING when: CallManager.callState == Voip.CONNECTING
PropertyChanges { PropertyChanges {
target: callStateLabel target: callStateLabel
@ -120,7 +120,7 @@ Rectangle {
}, },
State { State {
name: "ANSWERSENT" name: "ANSWERSENT"
when: CallManager.callState == WebRTCState.ANSWERSENT when: CallManager.callState == Voip.ANSWERSENT
PropertyChanges { PropertyChanges {
target: callStateLabel target: callStateLabel
@ -130,7 +130,7 @@ Rectangle {
}, },
State { State {
name: "CONNECTED" name: "CONNECTED"
when: CallManager.callState == WebRTCState.CONNECTED when: CallManager.callState == Voip.CONNECTED
PropertyChanges { PropertyChanges {
target: callStateLabel target: callStateLabel
@ -144,13 +144,13 @@ Rectangle {
PropertyChanges { PropertyChanges {
target: stackLayout target: stackLayout
currentIndex: CallManager.callType != CallType.VOICE ? 1 : 0 currentIndex: CallManager.callType != Voip.VOICE ? 1 : 0
} }
}, },
State { State {
name: "DISCONNECTED" name: "DISCONNECTED"
when: CallManager.callState == WebRTCState.DISCONNECTED when: CallManager.callState == Voip.DISCONNECTED
PropertyChanges { PropertyChanges {
target: callStateLabel target: callStateLabel
@ -176,7 +176,7 @@ Rectangle {
} }
interval: 1000 interval: 1000
running: CallManager.callState == WebRTCState.CONNECTED running: CallManager.callState == Voip.CONNECTED
repeat: true repeat: true
onTriggered: { onTriggered: {
var d = new Date(); var d = new Date();
@ -190,7 +190,7 @@ Rectangle {
Label { Label {
Layout.leftMargin: 16 Layout.leftMargin: 16
visible: CallManager.callType == CallType.SCREEN && CallManager.callState == WebRTCState.CONNECTED visible: CallManager.callType == Voip.SCREEN && CallManager.callState == Voip.CONNECTED
text: qsTr("You are screen sharing") text: qsTr("You are screen sharing")
font.pointSize: fontMetrics.font.pointSize * 1.1 font.pointSize: fontMetrics.font.pointSize * 1.1
color: "#000000" color: "#000000"

@ -43,7 +43,7 @@ Popup {
} }
RowLayout { RowLayout {
visible: CallManager.callType == CallType.VIDEO && CallManager.cameras.length > 0 visible: CallManager.callType == Voip.VIDEO && CallManager.cameras.length > 0
Image { Image {
Layout.preferredWidth: 22 Layout.preferredWidth: 22

@ -62,7 +62,7 @@ Popup {
Layout.bottomMargin: callInv.height / 25 Layout.bottomMargin: callInv.height / 25
Image { Image {
property string image: CallManager.callType == CallType.VIDEO ? ":/icons/icons/ui/video.svg" : ":/icons/icons/ui/place-call.svg" property string image: CallManager.callType == Voip.VIDEO ? ":/icons/icons/ui/video.svg" : ":/icons/icons/ui/place-call.svg"
Layout.alignment: Qt.AlignCenter Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: callInv.height / 10 Layout.preferredWidth: callInv.height / 10
@ -72,7 +72,7 @@ Popup {
Label { Label {
Layout.alignment: Qt.AlignCenter Layout.alignment: Qt.AlignCenter
text: CallManager.callType == CallType.VIDEO ? qsTr("Video Call") : qsTr("Voice Call") text: CallManager.callType == Voip.VIDEO ? qsTr("Video Call") : qsTr("Voice Call")
font.pointSize: fontMetrics.font.pointSize * 2 font.pointSize: fontMetrics.font.pointSize * 2
color: palette.windowText color: palette.windowText
} }
@ -106,7 +106,7 @@ Popup {
} }
RowLayout { RowLayout {
visible: CallManager.callType == CallType.VIDEO && CallManager.cameras.length > 0 visible: CallManager.callType == Voip.VIDEO && CallManager.cameras.length > 0
Layout.alignment: Qt.AlignCenter Layout.alignment: Qt.AlignCenter
Image { Image {
@ -169,7 +169,7 @@ Popup {
RoundButton { RoundButton {
id: acceptButton id: acceptButton
property string image: CallManager.callType == CallType.VIDEO ? ":/icons/icons/ui/video.svg" : ":/icons/icons/ui/place-call.svg" property string image: CallManager.callType == Voip.VIDEO ? ":/icons/icons/ui/video.svg" : ":/icons/icons/ui/place-call.svg"
implicitWidth: buttonLayout.buttonSize implicitWidth: buttonLayout.buttonSize
implicitHeight: buttonLayout.buttonSize implicitHeight: buttonLayout.buttonSize

@ -57,12 +57,12 @@ Rectangle {
Layout.leftMargin: 4 Layout.leftMargin: 4
Layout.preferredWidth: 24 Layout.preferredWidth: 24
Layout.preferredHeight: 24 Layout.preferredHeight: 24
source: CallManager.callType == CallType.VIDEO ? "qrc:/icons/icons/ui/video.svg" : "qrc:/icons/icons/ui/place-call.svg" source: CallManager.callType == Voip.VIDEO ? "qrc:/icons/icons/ui/video.svg" : "qrc:/icons/icons/ui/place-call.svg"
} }
Label { Label {
font.pointSize: fontMetrics.font.pointSize * 1.1 font.pointSize: fontMetrics.font.pointSize * 1.1
text: CallManager.callType == CallType.VIDEO ? qsTr("Video Call") : qsTr("Voice Call") text: CallManager.callType == Voip.VIDEO ? qsTr("Video Call") : qsTr("Voice Call")
color: "#000000" color: "#000000"
} }
@ -88,7 +88,7 @@ Rectangle {
Button { Button {
Layout.rightMargin: 4 Layout.rightMargin: 4
icon.source: CallManager.callType == CallType.VIDEO ? "qrc:/icons/icons/ui/video.svg" : "qrc:/icons/icons/ui/place-call.svg" icon.source: CallManager.callType == Voip.VIDEO ? "qrc:/icons/icons/ui/video.svg" : "qrc:/icons/icons/ui/place-call.svg"
text: qsTr("Accept") text: qsTr("Accept")
onClicked: { onClicked: {
if (CallManager.mics.length == 0) { if (CallManager.mics.length == 0) {
@ -108,7 +108,7 @@ Rectangle {
timelineRoot.destroyOnClose(dialog); timelineRoot.destroyOnClose(dialog);
return ; return ;
} }
if (CallManager.callType == CallType.VIDEO && CallManager.cameras.length > 0 && !CallManager.cameras.includes(Settings.camera)) { if (CallManager.callType == Voip.VIDEO && CallManager.cameras.length > 0 && !CallManager.cameras.includes(Settings.camera)) {
var dialog = deviceError.createObject(timelineRoot, { var dialog = deviceError.createObject(timelineRoot, {
"errorString": qsTr("Unknown camera: %1").arg(Settings.camera), "errorString": qsTr("Unknown camera: %1").arg(Settings.camera),
"image": ":/icons/icons/ui/video.svg" "image": ":/icons/icons/ui/video.svg"

@ -81,7 +81,7 @@ Popup {
onClicked: { onClicked: {
if (buttonLayout.validateMic()) { if (buttonLayout.validateMic()) {
Settings.microphone = micCombo.currentText; Settings.microphone = micCombo.currentText;
CallManager.sendInvite(room.roomId, CallType.VOICE); CallManager.sendInvite(room.roomId, Voip.VOICE);
close(); close();
} }
} }
@ -95,7 +95,7 @@ Popup {
if (buttonLayout.validateMic()) { if (buttonLayout.validateMic()) {
Settings.microphone = micCombo.currentText; Settings.microphone = micCombo.currentText;
Settings.camera = cameraCombo.currentText; Settings.camera = cameraCombo.currentText;
CallManager.sendInvite(room.roomId, CallType.VIDEO); CallManager.sendInvite(room.roomId, Voip.VIDEO);
close(); close();
} }
} }

@ -47,7 +47,7 @@ Popup {
Layout.fillWidth: true Layout.fillWidth: true
model: CallManager.screenShareTypeList() model: CallManager.screenShareTypeList()
onCurrentIndexChanged: CallManager.setScreenShareType(currentIndex); onCurrentIndexChanged: CallManager.setVoip(currentIndex);
} }
} }
@ -63,7 +63,7 @@ Popup {
} }
ComboBox { ComboBox {
visible: CallManager.screenShareType == ScreenShareType.X11 visible: CallManager.screenShareType == Voip.X11
id: windowCombo id: windowCombo
Layout.fillWidth: true Layout.fillWidth: true
@ -71,7 +71,7 @@ Popup {
} }
Button { Button {
visible: CallManager.screenShareType == ScreenShareType.XDP visible: CallManager.screenShareType == Voip.XDP
highlighted: !CallManager.screenShareReady highlighted: !CallManager.screenShareReady
text: qsTr("Request screencast") text: qsTr("Request screencast")
onClicked: { onClicked: {
@ -165,7 +165,7 @@ Popup {
Settings.screenShareRemoteVideo = remoteVideoCheckBox.checked; Settings.screenShareRemoteVideo = remoteVideoCheckBox.checked;
Settings.screenShareHideCursor = hideCursorCheckBox.checked; Settings.screenShareHideCursor = hideCursorCheckBox.checked;
CallManager.sendInvite(room.roomId, CallType.SCREEN, windowCombo.currentIndex); CallManager.sendInvite(room.roomId, Voip.SCREEN, windowCombo.currentIndex);
close(); close();
} }
} }

@ -92,107 +92,7 @@
</qresource> </qresource>
<qresource prefix="/"> <qresource prefix="/">
<file>qtquickcontrols2.conf</file> <file>qtquickcontrols2.conf</file>
<file>qml/Root.qml</file>
<file>qml/ChatPage.qml</file>
<file>qml/CommunitiesList.qml</file>
<file>qml/RoomList.qml</file>
<file>qml/TimelineView.qml</file>
<file>qml/Avatar.qml</file>
<file>qml/Completer.qml</file>
<file>qml/EncryptionIndicator.qml</file>
<file>qml/ImageButton.qml</file>
<file>qml/ElidedLabel.qml</file>
<file>qml/MatrixText.qml</file>
<file>qml/MatrixTextField.qml</file>
<file>qml/ToggleButton.qml</file>
<file>qml/UploadBox.qml</file>
<file>qml/MessageInput.qml</file>
<file>qml/MessageView.qml</file>
<file>qml/PrivacyScreen.qml</file>
<file>qml/Reactions.qml</file>
<file>qml/ReplyPopup.qml</file>
<file>qml/StatusIndicator.qml</file>
<file>qml/TimelineRow.qml</file>
<file>qml/TopBar.qml</file>
<file>qml/QuickSwitcher.qml</file>
<file>qml/ForwardCompleter.qml</file>
<file>qml/SelfVerificationCheck.qml</file>
<file>qml/TypingIndicator.qml</file>
<file>qml/MessageInputWarning.qml</file>
<file>qml/components/AdaptiveLayout.qml</file>
<file>qml/components/AdaptiveLayoutElement.qml</file>
<file>qml/components/AvatarListTile.qml</file>
<file>qml/components/FlatButton.qml</file>
<file>qml/components/MainWindowDialog.qml</file>
<file>qml/components/NhekoTabButton.qml</file>
<file>qml/components/NotificationBubble.qml</file>
<file>qml/components/ReorderableListview.qml</file>
<file>qml/components/SpaceMenuLevel.qml</file>
<file>qml/components/TextButton.qml</file>
<file>qml/components/UserListRow.qml</file>
<file>qml/delegates/Encrypted.qml</file>
<file>qml/delegates/FileMessage.qml</file>
<file>qml/delegates/ImageMessage.qml</file>
<file>qml/delegates/MessageDelegate.qml</file>
<file>qml/delegates/NoticeMessage.qml</file>
<file>qml/delegates/Pill.qml</file>
<file>qml/delegates/Placeholder.qml</file>
<file>qml/delegates/PlayableMediaMessage.qml</file>
<file>qml/delegates/Redacted.qml</file>
<file>qml/delegates/Reply.qml</file>
<file>qml/delegates/TextMessage.qml</file>
<file>qml/device-verification/DeviceVerification.qml</file>
<file>qml/device-verification/DigitVerification.qml</file>
<file>qml/device-verification/EmojiVerification.qml</file>
<file>qml/device-verification/Failed.qml</file>
<file>qml/device-verification/NewVerificationRequest.qml</file>
<file>qml/device-verification/Success.qml</file>
<file>qml/device-verification/Waiting.qml</file>
<file>qml/dialogs/AliasEditor.qml</file>
<file>qml/dialogs/ConfirmJoinRoomDialog.qml</file>
<file>qml/dialogs/CreateDirect.qml</file>
<file>qml/dialogs/CreateRoom.qml</file>
<file>qml/dialogs/HiddenEventsDialog.qml</file>
<file>qml/dialogs/ImageOverlay.qml</file>
<file>qml/dialogs/ImagePackEditorDialog.qml</file>
<file>qml/dialogs/ImagePackSettingsDialog.qml</file>
<file>qml/dialogs/InputDialog.qml</file>
<file>qml/dialogs/InviteDialog.qml</file>
<file>qml/dialogs/JoinRoomDialog.qml</file>
<file>qml/dialogs/LeaveRoomDialog.qml</file>
<file>qml/dialogs/LogoutDialog.qml</file>
<file>qml/dialogs/PhoneNumberInputDialog.qml</file>
<file>qml/dialogs/PowerLevelEditor.qml</file>
<file>qml/dialogs/PowerLevelSpacesApplyDialog.qml</file>
<file>qml/dialogs/RawMessageDialog.qml</file>
<file>qml/dialogs/ReadReceipts.qml</file>
<file>qml/dialogs/RoomDirectory.qml</file>
<file>qml/dialogs/RoomMembers.qml</file>
<file>qml/dialogs/AllowedRoomsSettingsDialog.qml</file>
<file>qml/dialogs/RoomSettings.qml</file>
<file>qml/dialogs/UserProfile.qml</file>
<file>qml/emoji/StickerPicker.qml</file>
<file>qml/pages/LoginPage.qml</file>
<file>qml/pages/RegisterPage.qml</file>
<file>qml/pages/UserSettingsPage.qml</file>
<file>qml/pages/WelcomePage.qml</file>
<file>qml/ui/NhekoSlider.qml</file>
<file>qml/ui/Ripple.qml</file>
<file>qml/ui/Snackbar.qml</file>
<file>qml/ui/Spinner.qml</file>
<file>qml/ui/animations/BlinkAnimation.qml</file>
<file>qml/ui/media/MediaControls.qml</file>
<file>qml/voip/ActiveCallBar.qml</file>
<file>qml/voip/CallDevices.qml</file>
<file>qml/voip/CallInvite.qml</file>
<file>qml/voip/CallInviteBar.qml</file>
<file>qml/voip/DeviceError.qml</file>
<file>qml/voip/PlaceCall.qml</file>
<file>qml/voip/ScreenShare.qml</file>
<file>qml/voip/VideoCall.qml</file>
<file>confettiparticle.svg</file> <file>confettiparticle.svg</file>
<file>qml/delegates/EncryptionEnabled.qml</file>
<file>qml/ui/TimelineEffects.qml</file>
</qresource> </qresource>
<qresource prefix="/media"> <qresource prefix="/media">
<file>media/ring.ogg</file> <file>media/ring.ogg</file>

@ -5,6 +5,7 @@
#pragma once #pragma once
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QQmlEngine>
#include <QVector> #include <QVector>
#include <mtx/events/canonical_alias.hpp> #include <mtx/events/canonical_alias.hpp>
@ -29,6 +30,9 @@ signals:
class AliasEditingModel final : public QAbstractListModel class AliasEditingModel final : public QAbstractListModel
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("Please use editAliases to create the models")
Q_PROPERTY(bool canAdvertize READ canAdvertize CONSTANT) Q_PROPERTY(bool canAdvertize READ canAdvertize CONSTANT)
public: public:

@ -5,6 +5,7 @@
#pragma once #pragma once
#include <QObject> #include <QObject>
#include <QQmlEngine>
#include <map> #include <map>
#include <mutex> #include <mutex>
@ -16,6 +17,8 @@
namespace crypto { namespace crypto {
Q_NAMESPACE Q_NAMESPACE
QML_NAMED_ELEMENT(Crypto)
//! How much a participant is trusted. //! How much a participant is trusted.
enum Trust enum Trust
{ {

@ -5,11 +5,15 @@
#pragma once #pragma once
#include <QObject> #include <QObject>
#include <QQmlEngine>
#include <QString> #include <QString>
class Clipboard final : public QObject class Clipboard final : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
QML_SINGLETON
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
public: public:

@ -5,13 +5,10 @@
#pragma once #pragma once
#include <QObject> #include <QObject>
#include <QQmlEngine>
#include <QVariantList> #include <QVariantList>
namespace mtx { #include <mtx/responses/login.hpp>
namespace responses {
struct Login;
}
}
struct SSOProvider struct SSOProvider
{ {
@ -33,6 +30,7 @@ public:
class LoginPage : public QObject class LoginPage : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
Q_PROPERTY(QString mxid READ mxid WRITE setMxid NOTIFY matrixIdChanged) Q_PROPERTY(QString mxid READ mxid WRITE setMxid NOTIFY matrixIdChanged)
Q_PROPERTY(QString homeserver READ homeserver WRITE setHomeserver NOTIFY homeserverChanged) Q_PROPERTY(QString homeserver READ homeserver WRITE setHomeserver NOTIFY homeserverChanged)

@ -25,21 +25,15 @@
#include "InviteesModel.h" #include "InviteesModel.h"
#include "JdenticonProvider.h" #include "JdenticonProvider.h"
#include "Logging.h" #include "Logging.h"
#include "LoginPage.h"
#include "MainWindow.h" #include "MainWindow.h"
#include "MatrixClient.h" #include "MatrixClient.h"
#include "MemberList.h" #include "MemberList.h"
#include "MxcImageProvider.h" #include "MxcImageProvider.h"
#include "PowerlevelsEditModels.h" #include "PowerlevelsEditModels.h"
#include "ReadReceiptsModel.h"
#include "RegisterPage.h"
#include "RoomDirectoryModel.h"
#include "RoomsModel.h"
#include "SingleImagePackModel.h" #include "SingleImagePackModel.h"
#include "TrayIcon.h" #include "TrayIcon.h"
#include "UserDirectoryModel.h" #include "UserDirectoryModel.h"
#include "UserSettingsPage.h" #include "UserSettingsPage.h"
#include "UsersModel.h"
#include "Utils.h" #include "Utils.h"
#include "dock/Dock.h" #include "dock/Dock.h"
#include "emoji/Provider.h" #include "emoji/Provider.h"
@ -48,12 +42,6 @@
#include "timeline/DelegateChooser.h" #include "timeline/DelegateChooser.h"
#include "timeline/TimelineFilter.h" #include "timeline/TimelineFilter.h"
#include "timeline/TimelineViewManager.h" #include "timeline/TimelineViewManager.h"
#include "ui/HiddenEvents.h"
#include "ui/MxcAnimatedImage.h"
#include "ui/MxcMediaProxy.h"
#include "ui/NhekoCursorShape.h"
#include "ui/NhekoDropArea.h"
#include "ui/NhekoEventObserver.h"
#include "ui/NhekoGlobalObject.h" #include "ui/NhekoGlobalObject.h"
#include "ui/RoomSummary.h" #include "ui/RoomSummary.h"
#include "ui/UIA.h" #include "ui/UIA.h"
@ -83,7 +71,7 @@ MainWindow::MainWindow(QWindow *parent)
registerQmlTypes(); registerQmlTypes();
setColor(Theme::paletteFromTheme(userSettings_->theme()).window().color()); setColor(Theme::paletteFromTheme(userSettings_->theme()).window().color());
setSource(QUrl(QStringLiteral("qrc:///qml/Root.qml"))); setSource(QUrl(QStringLiteral("qrc:///resources/qml/Root.qml")));
trayIcon_ = new TrayIcon(QStringLiteral(":/logos/nheko.svg"), this); trayIcon_ = new TrayIcon(QStringLiteral(":/logos/nheko.svg"), this);
@ -132,156 +120,57 @@ MainWindow::MainWindow(QWindow *parent)
void void
MainWindow::registerQmlTypes() MainWindow::registerQmlTypes()
{ {
qmlRegisterUncreatableMetaObject(qml_mtx_events::staticMetaObject, // qmlRegisterUncreatableType<DeviceVerificationFlow>(
"im.nheko", // "im.nheko",
1, // 1,
0, // 0,
"MtxEvent", // "DeviceVerificationFlow",
QStringLiteral("Can't instantiate enum!")); // QStringLiteral("Can't create verification flow from QML!"));
qmlRegisterUncreatableMetaObject( // qmlRegisterUncreatableType<UserProfile>(
olm::staticMetaObject, "im.nheko", 1, 0, "Olm", QStringLiteral("Can't instantiate enum!")); // "im.nheko",
qmlRegisterUncreatableMetaObject(crypto::staticMetaObject, // 1,
"im.nheko", // 0,
1, // "UserProfileModel",
0, // QStringLiteral("UserProfile needs to be instantiated on the C++ side"));
"Crypto", // qmlRegisterUncreatableType<MemberList>(
QStringLiteral("Can't instantiate enum!")); // "im.nheko",
qmlRegisterUncreatableMetaObject(verification::staticMetaObject, // 1,
"im.nheko", // 0,
1, // "MemberList",
0, // QStringLiteral("MemberList needs to be instantiated on the C++ side"));
"VerificationStatus", // qmlRegisterUncreatableType<RoomSettings>(
QStringLiteral("Can't instantiate enum!")); // "im.nheko",
// 1,
qmlRegisterType<DelegateChoice>("im.nheko", 1, 0, "DelegateChoice"); // 0,
qmlRegisterType<DelegateChooser>("im.nheko", 1, 0, "DelegateChooser"); // "RoomSettingsModel",
qmlRegisterType<NhekoDropArea>("im.nheko", 1, 0, "NhekoDropArea"); // QStringLiteral("Room Settings needs to be instantiated on the C++ side"));
qmlRegisterType<NhekoCursorShape>("im.nheko", 1, 0, "CursorShape"); // qmlRegisterUncreatableType<TimelineModel>(
qmlRegisterType<NhekoEventObserver>("im.nheko", 1, 0, "EventObserver"); // "im.nheko", 1, 0, "Room", QStringLiteral("Room needs to be instantiated on the C++ side"));
qmlRegisterType<MxcAnimatedImage>("im.nheko", 1, 0, "MxcAnimatedImage"); // qmlRegisterUncreatableType<ImagePackListModel>(
qmlRegisterType<MxcMediaProxy>("im.nheko", 1, 0, "MxcMedia"); // "im.nheko",
qmlRegisterType<RoomDirectoryModel>("im.nheko", 1, 0, "RoomDirectoryModel"); // 1,
qmlRegisterType<UserDirectoryModel>("im.nheko", 1, 0, "UserDirectoryModel"); // 0,
qmlRegisterType<LoginPage>("im.nheko", 1, 0, "Login"); // "ImagePackListModel",
qmlRegisterType<RegisterPage>("im.nheko", 1, 0, "Registration"); // QStringLiteral("ImagePackListModel needs to be instantiated on the C++ side"));
qmlRegisterType<HiddenEvents>("im.nheko", 1, 0, "HiddenEvents"); // qmlRegisterUncreatableType<SingleImagePackModel>(
qmlRegisterType<TimelineFilter>("im.nheko", 1, 0, "TimelineFilter"); // "im.nheko",
qmlRegisterUncreatableType<RoomSummary>( // 1,
"im.nheko", // 0,
1, // "SingleImagePackModel",
0, // QStringLiteral("SingleImagePackModel needs to be instantiated on the C++ side"));
"RoomSummary", // qmlRegisterUncreatableType<InviteesModel>(
QStringLiteral("Please use joinRoom to create a room summary.")); // "im.nheko",
qmlRegisterUncreatableType<AliasEditingModel>( // 1,
"im.nheko", // 0,
1, // "InviteesModel",
0, // QStringLiteral("InviteesModel needs to be instantiated on the C++ side"));
"AliasEditingModel",
QStringLiteral("Please use editAliases to create the models")); // qmlRegisterUncreatableMetaObject(emoji::staticMetaObject,
// "im.nheko.EmojiModel",
qmlRegisterUncreatableType<PowerlevelEditingModels>( // 1,
"im.nheko", // 0,
1, // "EmojiCategory",
0, // QStringLiteral("Error: Only enums"));
"PowerlevelEditingModels",
QStringLiteral("Please use editPowerlevels to create the models"));
qmlRegisterUncreatableType<DeviceVerificationFlow>(
"im.nheko",
1,
0,
"DeviceVerificationFlow",
QStringLiteral("Can't create verification flow from QML!"));
qmlRegisterUncreatableType<UserProfile>(
"im.nheko",
1,
0,
"UserProfileModel",
QStringLiteral("UserProfile needs to be instantiated on the C++ side"));
qmlRegisterUncreatableType<MemberList>(
"im.nheko",
1,
0,
"MemberList",
QStringLiteral("MemberList needs to be instantiated on the C++ side"));
qmlRegisterUncreatableType<RoomSettings>(
"im.nheko",
1,
0,
"RoomSettingsModel",
QStringLiteral("Room Settings needs to be instantiated on the C++ side"));
qmlRegisterUncreatableType<TimelineModel>(
"im.nheko", 1, 0, "Room", QStringLiteral("Room needs to be instantiated on the C++ side"));
qmlRegisterUncreatableType<ImagePackListModel>(
"im.nheko",
1,
0,
"ImagePackListModel",
QStringLiteral("ImagePackListModel needs to be instantiated on the C++ side"));
qmlRegisterUncreatableType<SingleImagePackModel>(
"im.nheko",
1,
0,
"SingleImagePackModel",
QStringLiteral("SingleImagePackModel needs to be instantiated on the C++ side"));
qmlRegisterUncreatableType<InviteesModel>(
"im.nheko",
1,
0,
"InviteesModel",
QStringLiteral("InviteesModel needs to be instantiated on the C++ side"));
qmlRegisterUncreatableType<ReadReceiptsProxy>(
"im.nheko",
1,
0,
"ReadReceiptsProxy",
QStringLiteral("ReadReceiptsProxy needs to be instantiated on the C++ side"));
qmlRegisterSingletonType<Clipboard>(
"im.nheko", 1, 0, "Clipboard", [](QQmlEngine *, QJSEngine *) -> QObject * {
return new Clipboard();
});
qmlRegisterSingletonType<Nheko>(
"im.nheko", 1, 0, "Nheko", [](QQmlEngine *, QJSEngine *) -> QObject * {
return new Nheko();
});
qmlRegisterSingletonType<UserSettingsModel>(
"im.nheko", 1, 0, "UserSettingsModel", [](QQmlEngine *, QJSEngine *) -> QObject * {
return new UserSettingsModel();
});
qmlRegisterSingletonInstance("im.nheko", 1, 0, "Settings", userSettings_.data());
qmlRegisterUncreatableType<FilteredCommunitiesModel>(
"im.nheko",
1,
0,
"FilteredCommunitiesModel",
QStringLiteral("Use Communities.filtered() to create a FilteredCommunitiesModel"));
qmlRegisterUncreatableType<MediaUpload>(
"im.nheko", 1, 0, "MediaUpload", QStringLiteral("MediaUploads can not be created in Qml"));
qmlRegisterUncreatableMetaObject(emoji::staticMetaObject,
"im.nheko.EmojiModel",
1,
0,
"EmojiCategory",
QStringLiteral("Error: Only enums"));
qmlRegisterType<RoomDirectoryModel>("im.nheko", 1, 0, "RoomDirectoryModel");
qmlRegisterSingletonType<SelfVerificationStatus>(
"im.nheko", 1, 0, "SelfVerificationStatus", [](QQmlEngine *, QJSEngine *) -> QObject * {
auto ptr = new SelfVerificationStatus();
QObject::connect(ChatPage::instance(),
&ChatPage::initializeEmptyViews,
ptr,
&SelfVerificationStatus::invalidate);
return ptr;
});
qmlRegisterSingletonInstance("im.nheko", 1, 0, "MainWindow", this);
qmlRegisterSingletonInstance("im.nheko", 1, 0, "UIA", UIA::instance());
qmlRegisterSingletonInstance(
"im.nheko", 1, 0, "CallManager", ChatPage::instance()->callManager());
imgProvider = new MxcImageProvider(); imgProvider = new MxcImageProvider();
engine()->addImageProvider(QStringLiteral("MxcImage"), imgProvider); engine()->addImageProvider(QStringLiteral("MxcImage"), imgProvider);

@ -50,14 +50,35 @@ public:
bool eventFilter(QObject *obj, QEvent *event) override; bool eventFilter(QObject *obj, QEvent *event) override;
}; };
class MainWindow final : public QQuickView class MainWindow : public QQuickView
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
QML_SINGLETON
public: public:
explicit MainWindow(QWindow *parent = nullptr); explicit MainWindow(QWindow *parent);
static MainWindow *instance() { return instance_; } static MainWindow *instance() { return instance_; }
static MainWindow *create(QQmlEngine *qmlEngine, QJSEngine *)
{
// The instance has to exist before it is used. We cannot replace it.
Q_ASSERT(instance_);
// The engine has to have the same thread affinity as the singleton.
Q_ASSERT(qmlEngine->thread() == instance_->thread());
// There can only be one engine accessing the singleton.
static QJSEngine *s_engine = nullptr;
if (s_engine)
Q_ASSERT(qmlEngine == s_engine);
else
s_engine = qmlEngine;
QJSEngine::setObjectOwnership(instance_, QJSEngine::CppOwnership);
return instance_;
}
void saveCurrentWindowSize(); void saveCurrentWindowSize();
void openJoinRoomDialog(std::function<void(const QString &room_id)> callback); void openJoinRoomDialog(std::function<void(const QString &room_id)> callback);

@ -5,6 +5,7 @@
#pragma once #pragma once
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QQmlEngine>
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include <mtx/events/power_levels.hpp> #include <mtx/events/power_levels.hpp>
@ -196,6 +197,9 @@ class PowerlevelEditingModels final : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("Please use editPowerlevels to create the models")
Q_PROPERTY(PowerlevelsUserListModel *users READ users CONSTANT) Q_PROPERTY(PowerlevelsUserListModel *users READ users CONSTANT)
Q_PROPERTY(PowerlevelsTypeListModel *types READ types CONSTANT) Q_PROPERTY(PowerlevelsTypeListModel *types READ types CONSTANT)
Q_PROPERTY(PowerlevelsSpacesListModel *spaces READ spaces CONSTANT) Q_PROPERTY(PowerlevelsSpacesListModel *spaces READ spaces CONSTANT)

@ -8,6 +8,7 @@
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QDateTime> #include <QDateTime>
#include <QObject> #include <QObject>
#include <QQmlEngine>
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include <QString> #include <QString>
@ -54,6 +55,9 @@ class ReadReceiptsProxy final : public QSortFilterProxyModel
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
Q_PROPERTY(QString eventId READ eventId CONSTANT) Q_PROPERTY(QString eventId READ eventId CONSTANT)
Q_PROPERTY(QString roomId READ roomId CONSTANT) Q_PROPERTY(QString roomId READ roomId CONSTANT)

@ -5,6 +5,7 @@
#pragma once #pragma once
#include <QObject> #include <QObject>
#include <QQmlEngine>
#include <QString> #include <QString>
#include <mtx/user_interactive.hpp> #include <mtx/user_interactive.hpp>
@ -13,6 +14,7 @@
class RegisterPage : public QObject class RegisterPage : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
Q_PROPERTY(QString error READ error NOTIFY errorChanged) Q_PROPERTY(QString error READ error NOTIFY errorChanged)
Q_PROPERTY(QString hsError READ hsError NOTIFY hsErrorChanged) Q_PROPERTY(QString hsError READ hsError NOTIFY hsErrorChanged)

@ -5,6 +5,7 @@
#pragma once #pragma once
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QQmlEngine>
#include <QString> #include <QString>
#include <string> #include <string>
#include <vector> #include <vector>
@ -32,6 +33,7 @@ signals:
class RoomDirectoryModel : public QAbstractListModel class RoomDirectoryModel : public QAbstractListModel
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
Q_PROPERTY(bool loadingMoreRooms READ loadingMoreRooms NOTIFY loadingMoreRoomsChanged) Q_PROPERTY(bool loadingMoreRooms READ loadingMoreRooms NOTIFY loadingMoreRoomsChanged)
Q_PROPERTY( Q_PROPERTY(

@ -5,6 +5,7 @@
#pragma once #pragma once
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QQmlEngine>
#include <QString> #include <QString>
#include <string> #include <string>
#include <vector> #include <vector>
@ -26,6 +27,7 @@ signals:
class UserDirectoryModel : public QAbstractListModel class UserDirectoryModel : public QAbstractListModel
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
Q_PROPERTY(bool searchingUsers READ searchingUsers NOTIFY searchingUsersChanged) Q_PROPERTY(bool searchingUsers READ searchingUsers NOTIFY searchingUsersChanged)

@ -6,6 +6,7 @@
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QProcessEnvironment> #include <QProcessEnvironment>
#include <QQmlEngine>
#include <QSettings> #include <QSettings>
#include <QSharedPointer> #include <QSharedPointer>
@ -23,6 +24,8 @@ class QVBoxLayout;
class UserSettings final : public QObject class UserSettings final : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_NAMED_ELEMENT(Settings)
QML_SINGLETON
Q_PROPERTY(QString theme READ theme WRITE setTheme NOTIFY themeChanged) Q_PROPERTY(QString theme READ theme WRITE setTheme NOTIFY themeChanged)
Q_PROPERTY(bool messageHoverHighlight READ messageHoverHighlight WRITE setMessageHoverHighlight Q_PROPERTY(bool messageHoverHighlight READ messageHoverHighlight WRITE setMessageHoverHighlight
@ -131,6 +134,24 @@ class UserSettings final : public QObject
public: public:
static QSharedPointer<UserSettings> instance(); static QSharedPointer<UserSettings> instance();
static void initialize(std::optional<QString> profile); static void initialize(std::optional<QString> profile);
static UserSettings *create(QQmlEngine *qmlEngine, QJSEngine *)
{
// The instance has to exist before it is used. We cannot replace it.
Q_ASSERT(instance());
// The engine has to have the same thread affinity as the singleton.
Q_ASSERT(qmlEngine->thread() == instance()->thread());
// There can only be one engine accessing the singleton.
static QJSEngine *s_engine = nullptr;
if (s_engine)
Q_ASSERT(qmlEngine == s_engine);
else
s_engine = qmlEngine;
QJSEngine::setObjectOwnership(instance().get(), QJSEngine::CppOwnership);
return instance().get();
}
QSettings *qsettings() { return &settings; } QSettings *qsettings() { return &settings; }
@ -431,9 +452,10 @@ private:
static QSharedPointer<UserSettings> instance_; static QSharedPointer<UserSettings> instance_;
}; };
class UserSettingsModel final : public QAbstractListModel class UserSettingsModel : public QAbstractListModel
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
enum Indices enum Indices
{ {

@ -9,10 +9,13 @@
#include <mtx/events/encrypted.hpp> #include <mtx/events/encrypted.hpp>
#include <mtxclient/crypto/client.hpp> #include <mtxclient/crypto/client.hpp>
#include <QQmlEngine>
#include <CacheCryptoStructs.h> #include <CacheCryptoStructs.h>
namespace olm { namespace olm {
Q_NAMESPACE Q_NAMESPACE
QML_NAMED_ELEMENT(Olm)
enum DecryptionErrorCode enum DecryptionErrorCode
{ {

@ -29,6 +29,11 @@ SelfVerificationStatus::SelfVerificationStatus(QObject *o)
Qt::UniqueConnection); Qt::UniqueConnection);
cache::client()->markUserKeysOutOfDate({http::client()->user_id().to_string()}); cache::client()->markUserKeysOutOfDate({http::client()->user_id().to_string()});
}); });
connect(ChatPage::instance(),
&ChatPage::initializeEmptyViews,
this,
&SelfVerificationStatus::invalidate);
} }
void void

@ -5,11 +5,15 @@
#pragma once #pragma once
#include <QObject> #include <QObject>
#include <QQmlEngine>
class SelfVerificationStatus final : public QObject class SelfVerificationStatus final : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
QML_SINGLETON
Q_PROPERTY(Status status READ status NOTIFY statusChanged) Q_PROPERTY(Status status READ status NOTIFY statusChanged)
Q_PROPERTY(bool hasSSSS READ hasSSSS NOTIFY hasSSSSChanged) Q_PROPERTY(bool hasSSSS READ hasSSSS NOTIFY hasSSSSChanged)

@ -15,6 +15,7 @@ VerificationManager::VerificationManager(TimelineViewManager *o)
: QObject(o) : QObject(o)
, rooms_(o->rooms()) , rooms_(o->rooms())
{ {
instance_ = this;
} }
static bool static bool

@ -6,6 +6,7 @@
#include <QHash> #include <QHash>
#include <QObject> #include <QObject>
#include <QQmlEngine>
#include <QSharedPointer> #include <QSharedPointer>
#include <mtx/events.hpp> #include <mtx/events.hpp>
@ -21,8 +22,30 @@ class VerificationManager final : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
QML_SINGLETON
public: public:
VerificationManager(TimelineViewManager *o = nullptr); VerificationManager(TimelineViewManager *o);
static VerificationManager *create(QQmlEngine *qmlEngine, QJSEngine *)
{
// The instance has to exist before it is used. We cannot replace it.
Q_ASSERT(instance_);
// The engine has to have the same thread affinity as the singleton.
Q_ASSERT(qmlEngine->thread() == instance_->thread());
// There can only be one engine accessing the singleton.
static QJSEngine *s_engine = nullptr;
if (s_engine)
Q_ASSERT(qmlEngine == s_engine);
else
s_engine = qmlEngine;
QJSEngine::setObjectOwnership(instance_, QJSEngine::CppOwnership);
return instance_;
}
Q_INVOKABLE void removeVerificationFlow(DeviceVerificationFlow *flow); Q_INVOKABLE void removeVerificationFlow(DeviceVerificationFlow *flow);
void verifyUser(QString userid); void verifyUser(QString userid);
@ -45,4 +68,6 @@ private:
QHash<QString, QSharedPointer<DeviceVerificationFlow>> dvList; QHash<QString, QSharedPointer<DeviceVerificationFlow>> dvList;
bool isInitialSync_ = false; bool isInitialSync_ = false;
RoomlistModel *rooms_; RoomlistModel *rooms_;
inline static VerificationManager *instance_ = nullptr;
}; };

@ -346,7 +346,7 @@ main(int argc, char *argv[])
QStringLiteral(":/translations"))) QStringLiteral(":/translations")))
app.installTranslator(&appTranslator); app.installTranslator(&appTranslator);
MainWindow w; MainWindow w(nullptr);
// QQuickView w; // QQuickView w;
// Move the MainWindow to the center // Move the MainWindow to the center

@ -22,6 +22,7 @@ CommunitiesModel::CommunitiesModel(QObject *parent)
, hiddenTagIds_{UserSettings::instance()->hiddenTags()} , hiddenTagIds_{UserSettings::instance()->hiddenTags()}
, mutedTagIds_{UserSettings::instance()->mutedTags()} , mutedTagIds_{UserSettings::instance()->mutedTags()}
{ {
instance_ = this;
} }
QHash<int, QByteArray> QHash<int, QByteArray>

@ -6,6 +6,7 @@
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QHash> #include <QHash>
#include <QQmlEngine>
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
@ -21,6 +22,8 @@ class CommunitiesModel;
class FilteredCommunitiesModel final : public QSortFilterProxyModel class FilteredCommunitiesModel final : public QSortFilterProxyModel
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("Use Communities.filtered() to create a FilteredCommunitiesModel")
public: public:
explicit FilteredCommunitiesModel(CommunitiesModel *model, QObject *parent = nullptr); explicit FilteredCommunitiesModel(CommunitiesModel *model, QObject *parent = nullptr);
@ -73,6 +76,9 @@ public:
class CommunitiesModel final : public QAbstractListModel class CommunitiesModel final : public QAbstractListModel
{ {
Q_OBJECT Q_OBJECT
QML_NAMED_ELEMENT(Communities)
QML_SINGLETON
Q_PROPERTY(QString currentTagId READ currentTagId WRITE setCurrentTagId NOTIFY Q_PROPERTY(QString currentTagId READ currentTagId WRITE setCurrentTagId NOTIFY
currentTagIdChanged RESET resetCurrentTagId) currentTagIdChanged RESET resetCurrentTagId)
Q_PROPERTY(QStringList tags READ tags NOTIFY tagsChanged) Q_PROPERTY(QStringList tags READ tags NOTIFY tagsChanged)
@ -149,6 +155,26 @@ public:
}; };
CommunitiesModel(QObject *parent = nullptr); CommunitiesModel(QObject *parent = nullptr);
static CommunitiesModel *create(QQmlEngine *qmlEngine, QJSEngine *)
{
// The instance has to exist before it is used. We cannot replace it.
Q_ASSERT(instance_);
// The engine has to have the same thread affinity as the singleton.
Q_ASSERT(qmlEngine->thread() == instance_->thread());
// There can only be one engine accessing the singleton.
static QJSEngine *s_engine = nullptr;
if (s_engine)
Q_ASSERT(qmlEngine == s_engine);
else
s_engine = qmlEngine;
QJSEngine::setObjectOwnership(instance_, QJSEngine::CppOwnership);
return instance_;
}
QHash<int, QByteArray> roleNames() const override; QHash<int, QByteArray> roleNames() const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override int rowCount(const QModelIndex &parent = QModelIndex()) const override
{ {
@ -221,4 +247,6 @@ private:
mtx::responses::UnreadNotifications dmUnreads{}; mtx::responses::UnreadNotifications dmUnreads{};
friend class FilteredCommunitiesModel; friend class FilteredCommunitiesModel;
inline static CommunitiesModel *instance_ = nullptr;
}; };

@ -19,6 +19,7 @@ class QQmlAdaptorModel;
class DelegateChoice : public QObject class DelegateChoice : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
Q_CLASSINFO("DefaultProperty", "delegate") Q_CLASSINFO("DefaultProperty", "delegate")
public: public:
@ -45,6 +46,7 @@ private:
class DelegateChooser : public QQuickItem class DelegateChooser : public QQuickItem
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
Q_CLASSINFO("DefaultProperty", "choices") Q_CLASSINFO("DefaultProperty", "choices")
public: public:

@ -7,11 +7,13 @@
#include <QIODevice> #include <QIODevice>
#include <QImage> #include <QImage>
#include <QObject> #include <QObject>
#include <QQmlEngine>
#include <QSize> #include <QSize>
#include <QStringList> #include <QStringList>
#include <QTimer> #include <QTimer>
#include <QUrl> #include <QUrl>
#include <QVariantList> #include <QVariantList>
#include <deque> #include <deque>
#include <memory> #include <memory>
@ -43,6 +45,10 @@ enum class MarkdownOverride
class MediaUpload final : public QObject class MediaUpload final : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
Q_PROPERTY(int mediaType READ type NOTIFY mediaTypeChanged) Q_PROPERTY(int mediaType READ type NOTIFY mediaTypeChanged)
// https://stackoverflow.com/questions/33422265/pass-qimage-to-qml/68554646#68554646 // https://stackoverflow.com/questions/33422265/pass-qimage-to-qml/68554646#68554646
Q_PROPERTY(QUrl thumbnail READ thumbnailDataUrl NOTIFY thumbnailChanged) Q_PROPERTY(QUrl thumbnail READ thumbnailDataUrl NOTIFY thumbnailChanged)

@ -5,6 +5,7 @@
#pragma once #pragma once
#include <QObject> #include <QObject>
#include <QQmlEngine>
#include <vector> #include <vector>
@ -15,10 +16,33 @@ class PresenceEmitter final : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_NAMED_ELEMENT(Presence)
QML_SINGLETON
public: public:
PresenceEmitter(QObject *p = nullptr) PresenceEmitter(QObject *p = nullptr)
: QObject(p) : QObject(p)
{ {
instance_ = this;
}
static PresenceEmitter *create(QQmlEngine *qmlEngine, QJSEngine *)
{
// The instance has to exist before it is used. We cannot replace it.
Q_ASSERT(instance_);
// The engine has to have the same thread affinity as the singleton.
Q_ASSERT(qmlEngine->thread() == instance_->thread());
// There can only be one engine accessing the singleton.
static QJSEngine *s_engine = nullptr;
if (s_engine)
Q_ASSERT(qmlEngine == s_engine);
else
s_engine = qmlEngine;
QJSEngine::setObjectOwnership(instance_, QJSEngine::CppOwnership);
return instance_;
} }
void sync(const std::vector<mtx::events::Event<mtx::events::presence::Presence>> &presences); void sync(const std::vector<mtx::events::Event<mtx::events::presence::Presence>> &presences);
@ -28,4 +52,7 @@ public:
signals: signals:
void presenceChanged(QString userid); void presenceChanged(QString userid);
private:
inline static PresenceEmitter *instance_ = nullptr;
}; };

@ -909,6 +909,8 @@ FilteredRoomlistModel::FilteredRoomlistModel(RoomlistModel *model, QObject *pare
: QSortFilterProxyModel(parent) : QSortFilterProxyModel(parent)
, roomlistmodel(model) , roomlistmodel(model)
{ {
instance_ = this;
this->sortByImportance = UserSettings::instance()->sortByImportance(); this->sortByImportance = UserSettings::instance()->sortByImportance();
this->sortByAlphabet = UserSettings::instance()->sortByAlphabet(); this->sortByAlphabet = UserSettings::instance()->sortByAlphabet();
setSourceModel(model); setSourceModel(model);

@ -167,12 +167,36 @@ private:
class FilteredRoomlistModel final : public QSortFilterProxyModel class FilteredRoomlistModel final : public QSortFilterProxyModel
{ {
Q_OBJECT Q_OBJECT
QML_NAMED_ELEMENT(Rooms)
QML_SINGLETON
Q_PROPERTY( Q_PROPERTY(
TimelineModel *currentRoom READ currentRoom NOTIFY currentRoomChanged RESET resetCurrentRoom) TimelineModel *currentRoom READ currentRoom NOTIFY currentRoomChanged RESET resetCurrentRoom)
Q_PROPERTY(RoomPreview currentRoomPreview READ currentRoomPreview NOTIFY currentRoomChanged Q_PROPERTY(RoomPreview currentRoomPreview READ currentRoomPreview NOTIFY currentRoomChanged
RESET resetCurrentRoom) RESET resetCurrentRoom)
public: public:
FilteredRoomlistModel(RoomlistModel *model, QObject *parent = nullptr); FilteredRoomlistModel(RoomlistModel *model, QObject *parent = nullptr);
static FilteredRoomlistModel *create(QQmlEngine *qmlEngine, QJSEngine *)
{
// The instance has to exist before it is used. We cannot replace it.
Q_ASSERT(instance_);
// The engine has to have the same thread affinity as the singleton.
Q_ASSERT(qmlEngine->thread() == instance_->thread());
// There can only be one engine accessing the singleton.
static QJSEngine *s_engine = nullptr;
if (s_engine)
Q_ASSERT(qmlEngine == s_engine);
else
s_engine = qmlEngine;
QJSEngine::setObjectOwnership(instance_, QJSEngine::CppOwnership);
return instance_;
}
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
bool filterAcceptsRow(int sourceRow, const QModelIndex &) const override; bool filterAcceptsRow(int sourceRow, const QModelIndex &) const override;
@ -249,4 +273,6 @@ private:
FilterBy filterType = FilterBy::Nothing; FilterBy filterType = FilterBy::Nothing;
QStringList hiddenTags, hiddenSpaces; QStringList hiddenTags, hiddenSpaces;
bool hideDMs = false; bool hideDMs = false;
inline static FilteredRoomlistModel *instance_ = nullptr;
}; };

@ -4,6 +4,7 @@
#pragma once #pragma once
#include <QQmlEngine>
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include <QString> #include <QString>
@ -14,6 +15,7 @@
class TimelineFilter : public QSortFilterProxyModel class TimelineFilter : public QSortFilterProxyModel
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
Q_PROPERTY(QString filterByThread READ filterByThread WRITE setThreadId NOTIFY threadIdChanged) Q_PROPERTY(QString filterByThread READ filterByThread WRITE setThreadId NOTIFY threadIdChanged)
Q_PROPERTY(QString filterByContent READ filterByContent WRITE setContentFilter NOTIFY Q_PROPERTY(QString filterByContent READ filterByContent WRITE setContentFilter NOTIFY

@ -11,6 +11,7 @@
#include <QTimer> #include <QTimer>
#include <QVariant> #include <QVariant>
#include <mtx/responses/common.hpp>
#include <mtxclient/http/errors.hpp> #include <mtxclient/http/errors.hpp>
#include "CacheCryptoStructs.h" #include "CacheCryptoStructs.h"
@ -36,6 +37,7 @@ struct RelatedInfo;
namespace qml_mtx_events { namespace qml_mtx_events {
Q_NAMESPACE Q_NAMESPACE
QML_NAMED_ELEMENT(MtxEvent)
enum EventType enum EventType
{ {
@ -193,6 +195,9 @@ class TimelineViewManager;
class TimelineModel final : public QAbstractListModel class TimelineModel final : public QAbstractListModel
{ {
Q_OBJECT Q_OBJECT
QML_NAMED_ELEMENT(Room)
QML_UNCREATABLE("")
Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
Q_PROPERTY(std::vector<QString> typingUsers READ typingUsers WRITE updateTypingUsers NOTIFY Q_PROPERTY(std::vector<QString> typingUsers READ typingUsers WRITE updateTypingUsers NOTIFY
typingUsersChanged) typingUsersChanged)

@ -96,29 +96,21 @@ TimelineViewManager::userColor(QString id, QColor background)
TimelineViewManager::TimelineViewManager(CallManager *, ChatPage *parent) TimelineViewManager::TimelineViewManager(CallManager *, ChatPage *parent)
: QObject(parent) : QObject(parent)
, rooms_(new RoomlistModel(this)) , rooms_(new RoomlistModel(this))
, frooms_(new FilteredRoomlistModel(this->rooms_))
, communities_(new CommunitiesModel(this)) , communities_(new CommunitiesModel(this))
, verificationManager_(new VerificationManager(this)) , verificationManager_(new VerificationManager(this))
, presenceEmitter(new PresenceEmitter(this)) , presenceEmitter(new PresenceEmitter(this))
{ {
static auto self = this; instance_ = this;
qmlRegisterSingletonInstance("im.nheko", 1, 0, "TimelineManager", self);
qmlRegisterSingletonType<RoomlistModel>( connect(this->communities_,
"im.nheko", 1, 0, "Rooms", [](QQmlEngine *, QJSEngine *) -> QObject * { &CommunitiesModel::currentTagIdChanged,
auto ptr = new FilteredRoomlistModel(self->rooms_); frooms_,
&FilteredRoomlistModel::updateFilterTag);
connect(self->communities_, connect(this->communities_,
&CommunitiesModel::currentTagIdChanged, &CommunitiesModel::hiddenTagsChanged,
ptr, frooms_,
&FilteredRoomlistModel::updateFilterTag); &FilteredRoomlistModel::updateHiddenTagsAndSpaces);
connect(self->communities_,
&CommunitiesModel::hiddenTagsChanged,
ptr,
&FilteredRoomlistModel::updateHiddenTagsAndSpaces);
return ptr;
});
qmlRegisterSingletonInstance("im.nheko", 1, 0, "Communities", self->communities_);
qmlRegisterSingletonInstance("im.nheko", 1, 0, "VerificationManager", verificationManager_);
qmlRegisterSingletonInstance("im.nheko", 1, 0, "Presence", presenceEmitter);
updateColorPalette(); updateColorPalette();

@ -34,6 +34,9 @@ class TimelineViewManager final : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_NAMED_ELEMENT(TimelineManager)
QML_SINGLETON
Q_PROPERTY( Q_PROPERTY(
bool isInitialSync MEMBER isInitialSync_ READ isInitialSync NOTIFY initialSyncChanged) bool isInitialSync MEMBER isInitialSync_ READ isInitialSync NOTIFY initialSyncChanged)
Q_PROPERTY(bool isConnected READ isConnected NOTIFY isConnectedChanged) Q_PROPERTY(bool isConnected READ isConnected NOTIFY isConnectedChanged)
@ -41,6 +44,25 @@ class TimelineViewManager final : public QObject
public: public:
TimelineViewManager(CallManager *callManager, ChatPage *parent = nullptr); TimelineViewManager(CallManager *callManager, ChatPage *parent = nullptr);
static TimelineViewManager *create(QQmlEngine *qmlEngine, QJSEngine *)
{
// The instance has to exist before it is used. We cannot replace it.
Q_ASSERT(instance_);
// The engine has to have the same thread affinity as the singleton.
Q_ASSERT(qmlEngine->thread() == instance_->thread());
// There can only be one engine accessing the singleton.
static QJSEngine *s_engine = nullptr;
if (s_engine)
Q_ASSERT(qmlEngine == s_engine);
else
s_engine = qmlEngine;
QJSEngine::setObjectOwnership(instance_, QJSEngine::CppOwnership);
return instance_;
}
void sync(const mtx::responses::Sync &sync_); void sync(const mtx::responses::Sync &sync_);
VerificationManager *verificationManager() { return verificationManager_; } VerificationManager *verificationManager() { return verificationManager_; }
@ -123,6 +145,7 @@ private:
bool isConnected_ = true; bool isConnected_ = true;
RoomlistModel *rooms_ = nullptr; RoomlistModel *rooms_ = nullptr;
FilteredRoomlistModel *frooms_ = nullptr;
CommunitiesModel *communities_ = nullptr; CommunitiesModel *communities_ = nullptr;
// don't move this above the rooms_ // don't move this above the rooms_
@ -130,4 +153,6 @@ private:
PresenceEmitter *presenceEmitter = nullptr; PresenceEmitter *presenceEmitter = nullptr;
QHash<QPair<QString, quint64>, QColor> userColors; QHash<QPair<QString, quint64>, QColor> userColors;
inline static TimelineViewManager *instance_ = nullptr;
}; };

@ -5,6 +5,7 @@
#pragma once #pragma once
#include <QObject> #include <QObject>
#include <QQmlEngine>
#include <QString> #include <QString>
#include <QVariantList> #include <QVariantList>
@ -13,6 +14,7 @@
class HiddenEvents : public QObject class HiddenEvents : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
Q_PROPERTY(QString roomid READ roomid WRITE setRoomid NOTIFY roomidChanged REQUIRED) Q_PROPERTY(QString roomid READ roomid WRITE setRoomid NOTIFY roomidChanged REQUIRED)
Q_PROPERTY(QVariantList hiddenEvents READ hiddenEvents NOTIFY hiddenEventsChanged) Q_PROPERTY(QVariantList hiddenEvents READ hiddenEvents NOTIFY hiddenEventsChanged)
public: public:

@ -15,6 +15,7 @@
class MxcAnimatedImage : public QQuickItem class MxcAnimatedImage : public QQuickItem
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
Q_PROPERTY(TimelineModel *roomm READ room WRITE setRoom NOTIFY roomChanged REQUIRED) Q_PROPERTY(TimelineModel *roomm READ room WRITE setRoom NOTIFY roomChanged REQUIRED)
Q_PROPERTY(QString eventId READ eventId WRITE setEventId NOTIFY eventIdChanged) Q_PROPERTY(QString eventId READ eventId WRITE setEventId NOTIFY eventIdChanged)
Q_PROPERTY(bool animatable READ animatable NOTIFY animatableChanged) Q_PROPERTY(bool animatable READ animatable NOTIFY animatableChanged)

@ -8,6 +8,7 @@
#include <QMediaPlayer> #include <QMediaPlayer>
#include <QObject> #include <QObject>
#include <QPointer> #include <QPointer>
#include <QQuickItem>
#include <QString> #include <QString>
#include <QUrl> #include <QUrl>
#include <QVideoSink> #include <QVideoSink>
@ -21,6 +22,8 @@ class TimelineModel;
class MxcMediaProxy : public QMediaPlayer class MxcMediaProxy : public QMediaPlayer
{ {
Q_OBJECT Q_OBJECT
QML_NAMED_ELEMENT(MxcMedia)
Q_PROPERTY(TimelineModel *roomm READ room WRITE setRoom NOTIFY roomChanged REQUIRED) Q_PROPERTY(TimelineModel *roomm READ room WRITE setRoom NOTIFY roomChanged REQUIRED)
Q_PROPERTY(QString eventId READ eventId WRITE setEventId NOTIFY eventIdChanged) Q_PROPERTY(QString eventId READ eventId WRITE setEventId NOTIFY eventIdChanged)
Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged) Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged)

@ -12,7 +12,7 @@
class NhekoCursorShape : public QQuickItem class NhekoCursorShape : public QQuickItem
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
Q_PROPERTY( Q_PROPERTY(
Qt::CursorShape cursorShape READ cursorShape WRITE setCursorShape NOTIFY cursorShapeChanged) Qt::CursorShape cursorShape READ cursorShape WRITE setCursorShape NOTIFY cursorShapeChanged)

@ -7,6 +7,7 @@
class NhekoDropArea : public QQuickItem class NhekoDropArea : public QQuickItem
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
Q_PROPERTY(QString roomid READ roomid WRITE setRoomid NOTIFY roomidChanged) Q_PROPERTY(QString roomid READ roomid WRITE setRoomid NOTIFY roomidChanged)
public: public:
NhekoDropArea(QQuickItem *parent = nullptr); NhekoDropArea(QQuickItem *parent = nullptr);

@ -1,60 +0,0 @@
// SPDX-FileCopyrightText: Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
#include "NhekoEventObserver.h"
#include <QMouseEvent>
#include "Logging.h"
NhekoEventObserver::NhekoEventObserver(QQuickItem *parent)
: QQuickItem(parent)
{
setFiltersChildMouseEvents(true);
}
bool
NhekoEventObserver::childMouseEventFilter(QQuickItem * /*item*/, QEvent *event)
{
// nhlog::ui()->debug("Touched {}", item->metaObject()->className());
auto setTouched = [this](bool touched) {
if (touched != this->wasTouched_) {
this->wasTouched_ = touched;
emit wasTouchedChanged();
}
};
// see
// https://code.qt.io/cgit/qt/qtdeclarative.git/tree/src/quicktemplates2/qquickscrollview.cpp?id=7f29e89c26ae2babc358b1c4e6f965af6ec759f4#n471
switch (event->type()) {
case QEvent::TouchBegin:
case QEvent::TouchEnd:
setTouched(true);
break;
case QEvent::MouseButtonPress:
if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized) {
setTouched(false);
}
break;
case QEvent::MouseMove:
case QEvent::MouseButtonRelease:
if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized)
setTouched(false);
break;
case QEvent::HoverEnter:
case QEvent::HoverMove:
case QEvent::Wheel:
setTouched(false);
break;
default:
break;
}
return false;
}

@ -1,27 +0,0 @@
// SPDX-FileCopyrightText: Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <QQuickItem>
class NhekoEventObserver : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(bool wasTouched READ wasTouched NOTIFY wasTouchedChanged)
public:
explicit NhekoEventObserver(QQuickItem *parent = 0);
bool childMouseEventFilter(QQuickItem *item, QEvent *event) override;
private:
bool wasTouched() { return wasTouched_; }
bool wasTouched_ = false;
signals:
void wasTouchedChanged();
};

@ -7,6 +7,7 @@
#include <QFontDatabase> #include <QFontDatabase>
#include <QObject> #include <QObject>
#include <QPalette> #include <QPalette>
#include <QQmlEngine>
#include <QWindow> #include <QWindow>
#include "AliasEditModel.h" #include "AliasEditModel.h"
@ -19,6 +20,9 @@ class Nheko final : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
QML_SINGLETON
Q_PROPERTY(QPalette colors READ colors NOTIFY colorsChanged) Q_PROPERTY(QPalette colors READ colors NOTIFY colorsChanged)
Q_PROPERTY(QPalette inactiveColors READ inactiveColors NOTIFY colorsChanged) Q_PROPERTY(QPalette inactiveColors READ inactiveColors NOTIFY colorsChanged)
Q_PROPERTY(Theme theme READ theme NOTIFY colorsChanged) Q_PROPERTY(Theme theme READ theme NOTIFY colorsChanged)

@ -7,6 +7,7 @@
#include <optional> #include <optional>
#include <QObject> #include <QObject>
#include <QQmlEngine>
#include <mtx/responses/public_rooms.hpp> #include <mtx/responses/public_rooms.hpp>
@ -25,6 +26,9 @@ class RoomSummary final : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("Please use joinRoom to create a room summary.")
Q_PROPERTY(QString reason READ reason WRITE setReason NOTIFY reasonChanged) Q_PROPERTY(QString reason READ reason WRITE setReason NOTIFY reasonChanged)
Q_PROPERTY(QString roomid READ roomid NOTIFY loaded) Q_PROPERTY(QString roomid READ roomid NOTIFY loaded)

@ -5,6 +5,7 @@
#pragma once #pragma once
#include <QObject> #include <QObject>
#include <QQmlEngine>
#include <mtxclient/http/client.hpp> #include <mtxclient/http/client.hpp>
@ -12,10 +13,31 @@ class UIA final : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
QML_SINGLETON
Q_PROPERTY(QString title READ title NOTIFY titleChanged) Q_PROPERTY(QString title READ title NOTIFY titleChanged)
public: public:
static UIA *instance(); static UIA *instance();
static UIA *create(QQmlEngine *qmlEngine, QJSEngine *)
{
// The instance has to exist before it is used. We cannot replace it.
Q_ASSERT(instance());
// The engine has to have the same thread affinity as the singleton.
Q_ASSERT(qmlEngine->thread() == instance()->thread());
// There can only be one engine accessing the singleton.
static QJSEngine *s_engine = nullptr;
if (s_engine)
Q_ASSERT(qmlEngine == s_engine);
else
s_engine = qmlEngine;
QJSEngine::setObjectOwnership(instance(), QJSEngine::CppOwnership);
return instance();
}
UIA(QObject *parent = nullptr) UIA(QObject *parent = nullptr)
: QObject(parent) : QObject(parent)

@ -6,6 +6,7 @@
#include <QAbstractListModel> #include <QAbstractListModel>
#include <QObject> #include <QObject>
#include <QQmlEngine>
#include <QString> #include <QString>
#include <QVector> #include <QVector>
#include <mtx/responses.hpp> #include <mtx/responses.hpp>
@ -16,6 +17,7 @@
namespace verification { namespace verification {
Q_NAMESPACE Q_NAMESPACE
QML_NAMED_ELEMENT(VerificationStatus)
enum Status enum Status
{ {

@ -54,6 +54,27 @@ std::vector<std::string>
getTurnURIs(const mtx::responses::TurnServer &turnServer); getTurnURIs(const mtx::responses::TurnServer &turnServer);
} }
CallManager *
CallManager::create(QQmlEngine *qmlEngine, QJSEngine *)
{
// The instance has to exist before it is used. We cannot replace it.
auto instance = ChatPage::instance()->callManager();
Q_ASSERT(instance);
// The engine has to have the same thread affinity as the singleton.
Q_ASSERT(qmlEngine->thread() == instance->thread());
// There can only be one engine accessing the singleton.
static QJSEngine *s_engine = nullptr;
if (s_engine)
Q_ASSERT(qmlEngine == s_engine);
else
s_engine = qmlEngine;
QJSEngine::setObjectOwnership(instance, QJSEngine::CppOwnership);
return instance;
}
CallManager::CallManager(QObject *parent) CallManager::CallManager(QObject *parent)
: QObject(parent) : QObject(parent)
, session_(WebRTCSession::instance()) , session_(WebRTCSession::instance())

@ -9,6 +9,7 @@
#include <QMediaPlayer> #include <QMediaPlayer>
#include <QObject> #include <QObject>
#include <QQmlEngine>
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
#include <QTimer> #include <QTimer>
@ -29,6 +30,10 @@ class QUrl;
class CallManager final : public QObject class CallManager final : public QObject
{ {
Q_OBJECT Q_OBJECT
QML_ELEMENT
QML_SINGLETON
Q_PROPERTY(bool haveCallInvite READ haveCallInvite NOTIFY newInviteState) Q_PROPERTY(bool haveCallInvite READ haveCallInvite NOTIFY newInviteState)
Q_PROPERTY(bool isOnCall READ isOnCall NOTIFY newCallState) Q_PROPERTY(bool isOnCall READ isOnCall NOTIFY newCallState)
Q_PROPERTY(bool isOnCallOnOtherDevice READ isOnCallOnOtherDevice NOTIFY newCallDeviceState) Q_PROPERTY(bool isOnCallOnOtherDevice READ isOnCallOnOtherDevice NOTIFY newCallDeviceState)
@ -49,6 +54,8 @@ class CallManager final : public QObject
public: public:
CallManager(QObject *); CallManager(QObject *);
static CallManager *create(QQmlEngine *qmlEngine, QJSEngine *);
bool haveCallInvite() const { return haveCallInvite_; } bool haveCallInvite() const { return haveCallInvite_; }
bool isOnCall() const { return (session_.state() != webrtc::State::DISCONNECTED); } bool isOnCall() const { return (session_.state() != webrtc::State::DISCONNECTED); }
bool isOnCallOnOtherDevice() const { return (isOnCallOnOtherDevice_ != ""); } bool isOnCallOnOtherDevice() const { return (isOnCallOnOtherDevice_ != ""); }

@ -48,26 +48,26 @@ using webrtc::State;
WebRTCSession::WebRTCSession() WebRTCSession::WebRTCSession()
: devices_(CallDevices::instance()) : devices_(CallDevices::instance())
{ {
qmlRegisterUncreatableMetaObject(webrtc::staticMetaObject, // qmlRegisterUncreatableMetaObject(webrtc::staticMetaObject,
"im.nheko", // "im.nheko",
1, // 1,
0, // 0,
"CallType", // "CallType",
QStringLiteral("Can't instantiate enum")); // QStringLiteral("Can't instantiate enum"));
qmlRegisterUncreatableMetaObject(webrtc::staticMetaObject, // qmlRegisterUncreatableMetaObject(webrtc::staticMetaObject,
"im.nheko", // "im.nheko",
1, // 1,
0, // 0,
"ScreenShareType", // "ScreenShareType",
QStringLiteral("Can't instantiate enum")); // QStringLiteral("Can't instantiate enum"));
qmlRegisterUncreatableMetaObject(webrtc::staticMetaObject, // qmlRegisterUncreatableMetaObject(webrtc::staticMetaObject,
"im.nheko", // "im.nheko",
1, // 1,
0, // 0,
"WebRTCState", // "WebRTCState",
QStringLiteral("Can't instantiate enum")); // QStringLiteral("Can't instantiate enum"));
connect(this, &WebRTCSession::stateChanged, this, &WebRTCSession::setState); connect(this, &WebRTCSession::stateChanged, this, &WebRTCSession::setState);
init(); init();

@ -8,6 +8,7 @@
#include <vector> #include <vector>
#include <QObject> #include <QObject>
#include <QQmlEngine>
#include "mtx/events/voip.hpp" #include "mtx/events/voip.hpp"
@ -17,6 +18,7 @@ class QQuickItem;
namespace webrtc { namespace webrtc {
Q_NAMESPACE Q_NAMESPACE
QML_NAMED_ELEMENT(Voip)
enum class CallType enum class CallType
{ {

Loading…
Cancel
Save