Move to automatic type registration

This commit is contained in:
Nicolas Werner 2023-06-19 01:38:40 +02:00
parent 2cb04fd741
commit ce1a64bc19
No known key found for this signature in database
GPG key ID: C8D75E610773F2D9
73 changed files with 570 additions and 472 deletions

View file

@ -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)

View file

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

View file

@ -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

View file

@ -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

View file

@ -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
} }

View file

@ -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

View file

@ -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) ?? ""

View file

@ -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
} }

View file

@ -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

View file

@ -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

View file

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

View file

@ -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
} }

View file

@ -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
} }

View file

@ -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

View file

@ -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
} }

View file

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

View file

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

View file

@ -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
} }

View file

@ -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

View file

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

View file

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

View file

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

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -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"

View file

@ -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();
} }
} }

View file

@ -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();
} }
} }

View file

@ -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>

View 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:

View file

@ -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
{ {

View file

@ -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:

View file

@ -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)

View file

@ -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,
// 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"));
qmlRegisterType<DelegateChoice>("im.nheko", 1, 0, "DelegateChoice"); // qmlRegisterUncreatableMetaObject(emoji::staticMetaObject,
qmlRegisterType<DelegateChooser>("im.nheko", 1, 0, "DelegateChooser"); // "im.nheko.EmojiModel",
qmlRegisterType<NhekoDropArea>("im.nheko", 1, 0, "NhekoDropArea"); // 1,
qmlRegisterType<NhekoCursorShape>("im.nheko", 1, 0, "CursorShape"); // 0,
qmlRegisterType<NhekoEventObserver>("im.nheko", 1, 0, "EventObserver"); // "EmojiCategory",
qmlRegisterType<MxcAnimatedImage>("im.nheko", 1, 0, "MxcAnimatedImage"); // QStringLiteral("Error: Only enums"));
qmlRegisterType<MxcMediaProxy>("im.nheko", 1, 0, "MxcMedia");
qmlRegisterType<RoomDirectoryModel>("im.nheko", 1, 0, "RoomDirectoryModel");
qmlRegisterType<UserDirectoryModel>("im.nheko", 1, 0, "UserDirectoryModel");
qmlRegisterType<LoginPage>("im.nheko", 1, 0, "Login");
qmlRegisterType<RegisterPage>("im.nheko", 1, 0, "Registration");
qmlRegisterType<HiddenEvents>("im.nheko", 1, 0, "HiddenEvents");
qmlRegisterType<TimelineFilter>("im.nheko", 1, 0, "TimelineFilter");
qmlRegisterUncreatableType<RoomSummary>(
"im.nheko",
1,
0,
"RoomSummary",
QStringLiteral("Please use joinRoom to create a room summary."));
qmlRegisterUncreatableType<AliasEditingModel>(
"im.nheko",
1,
0,
"AliasEditingModel",
QStringLiteral("Please use editAliases to create the models"));
qmlRegisterUncreatableType<PowerlevelEditingModels>(
"im.nheko",
1,
0,
"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);

View file

@ -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);

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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(

View file

@ -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)

View file

@ -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
{ {

View file

@ -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
{ {

View file

@ -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

View file

@ -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)

View file

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

View file

@ -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;
}; };

View file

@ -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

View file

@ -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>

View file

@ -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;
}; };

View file

@ -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:

View file

@ -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)

View file

@ -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;
}; };

View file

@ -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);

View file

@ -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;
}; };

View file

@ -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

View file

@ -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)

View file

@ -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>(
"im.nheko", 1, 0, "Rooms", [](QQmlEngine *, QJSEngine *) -> QObject * {
auto ptr = new FilteredRoomlistModel(self->rooms_);
connect(self->communities_, connect(this->communities_,
&CommunitiesModel::currentTagIdChanged, &CommunitiesModel::currentTagIdChanged,
ptr, frooms_,
&FilteredRoomlistModel::updateFilterTag); &FilteredRoomlistModel::updateFilterTag);
connect(self->communities_, connect(this->communities_,
&CommunitiesModel::hiddenTagsChanged, &CommunitiesModel::hiddenTagsChanged,
ptr, frooms_,
&FilteredRoomlistModel::updateHiddenTagsAndSpaces); &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();

View file

@ -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;
}; };

View file

@ -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:

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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);

View file

@ -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;
}

View file

@ -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();
};

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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
{ {

View file

@ -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())

View file

@ -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_ != ""); }

View file

@ -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();

View file

@ -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
{ {