diff --git a/imports/Spectral/Panel/RoomPanelInput.qml b/imports/Spectral/Panel/RoomPanelInput.qml index fa3d6f1..d2af892 100644 --- a/imports/Spectral/Panel/RoomPanelInput.qml +++ b/imports/Spectral/Panel/RoomPanelInput.qml @@ -18,6 +18,7 @@ Rectangle { property string replyEventID property string replyContent + color: MSettings.darkTheme ? "#303030" : "#fafafa" layer.enabled: true @@ -25,6 +26,56 @@ Rectangle { elevation: 2 } + Popup { + x: 0 + y: -height - 10 + width: Math.min(userAutoCompleteListView.contentWidth, parent.width) + height: 36 + padding: 0 + + Material.elevation: 2 + + id: userAutoComplete + + contentItem: ListView { + id: userAutoCompleteListView + + clip: true + + orientation: ListView.Horizontal + + highlightFollowsCurrentItem: true + + highlight: Rectangle { + color: Material.accent + opacity: 0.4 + } + + delegate: ItemDelegate { + property string displayName: modelData.displayName + + height: parent.height + padding: 4 + + contentItem: Row { + spacing: 8 + ImageItem { + width: parent.height + height: parent.height + image: modelData.avatar + } + Label { + height: parent.height + text: modelData.displayName + verticalAlignment: Text.AlignVCenter + } + } + + text: modelData.displayName + } + } + } + Rectangle { width: currentRoom && currentRoom.hasFileUploading ? parent.width * currentRoom.fileUploadingProgress / 100 : 0 height: parent.height @@ -125,16 +176,36 @@ Rectangle { Keys.onReturnPressed: { if (event.modifiers & Qt.ShiftModifier) { insert(cursorPosition, "\n") + } else if (userAutoComplete.visible) { + text = text.substring(0, text.lastIndexOf(" ")); + insert(cursorPosition, userAutoCompleteListView.currentItem.displayName) + userAutoComplete.visible = false } else { postMessage(text) text = "" } } + Keys.onTabPressed: { + if (userAutoComplete.visible) { + if (userAutoCompleteListView.currentIndex + 1 == userAutoCompleteListView.count) userAutoCompleteListView.currentIndex = 0 + else userAutoCompleteListView.currentIndex++ + } else { + var lastWord = text.substring(0, cursorPosition).split(" ").pop() + if (!lastWord) return + var model = currentRoom.getUsers(lastWord) + if (model.length === 0) return + userAutoCompleteListView.model = model + userAutoComplete.visible = true + } + } + onTextChanged: { timeoutTimer.restart() repeatTimer.start() currentRoom.cachedInput = text + + if (userAutoComplete.visible) userAutoComplete.visible = false } function postMessage(text) { @@ -206,16 +277,14 @@ Rectangle { onClicked: emojiPicker.visible ? emojiPicker.close() : emojiPicker.open() EmojiPicker { - x: window.width - 370 - y: window.height - 400 + x: -width + parent.width + y: -height - 16 width: 360 height: 320 id: emojiPicker - parent: ApplicationWindow.overlay - Material.elevation: 2 textArea: inputField diff --git a/src/main.cpp b/src/main.cpp index 2107a44..8af73bb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,6 +12,7 @@ #include "room.h" #include "roomlistmodel.h" #include "spectralroom.h" +#include "spectraluser.h" #include "userlistmodel.h" #include "csapi/joining.h" @@ -50,6 +51,7 @@ int main(int argc, char *argv[]) { qRegisterMetaType("Room*"); qRegisterMetaType("MessageEventType"); qRegisterMetaType("SpectralRoom*"); + qRegisterMetaType("SpectralUser*"); QQmlApplicationEngine engine; diff --git a/src/spectralroom.cpp b/src/spectralroom.cpp index 16078b7..89233d3 100644 --- a/src/spectralroom.cpp +++ b/src/spectralroom.cpp @@ -195,3 +195,13 @@ void SpectralRoom::getPreviousContent(int limit) { setBusy(true); Room::getPreviousContent(limit); } + +QVariantList SpectralRoom::getUsers(const QString& prefix) { + auto userList = users(); + QVariantList matchedList; + for (auto u : userList) + if (u->displayname(this).toLower().startsWith(prefix.toLower())) + matchedList.append(QVariant::fromValue(u)); + + return matchedList; +} diff --git a/src/spectralroom.h b/src/spectralroom.h index 955150d..d3a4a9b 100644 --- a/src/spectralroom.h +++ b/src/spectralroom.h @@ -2,6 +2,7 @@ #define SpectralRoom_H #include "room.h" +#include "spectraluser.h" #include #include @@ -74,6 +75,8 @@ class SpectralRoom : public Room { Q_INVOKABLE void getPreviousContent(int limit = 10); + Q_INVOKABLE QVariantList getUsers(const QString& prefix); + private: QString m_cachedInput; QSet highlights;