mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-23 03:18:49 +03:00
Working User completer
This commit is contained in:
parent
a3c4fece7e
commit
add5903fb0
9 changed files with 83 additions and 38 deletions
|
@ -492,6 +492,7 @@ qt5_wrap_cpp(MOC_HEADERS
|
||||||
src/ChatPage.h
|
src/ChatPage.h
|
||||||
src/CommunitiesList.h
|
src/CommunitiesList.h
|
||||||
src/CommunitiesListItem.h
|
src/CommunitiesListItem.h
|
||||||
|
src/CompletionProxyModel.h
|
||||||
src/DeviceVerificationFlow.h
|
src/DeviceVerificationFlow.h
|
||||||
src/InviteeItem.h
|
src/InviteeItem.h
|
||||||
src/LoginPage.h
|
src/LoginPage.h
|
||||||
|
@ -508,6 +509,7 @@ qt5_wrap_cpp(MOC_HEADERS
|
||||||
src/TrayIcon.h
|
src/TrayIcon.h
|
||||||
src/UserInfoWidget.h
|
src/UserInfoWidget.h
|
||||||
src/UserSettingsPage.h
|
src/UserSettingsPage.h
|
||||||
|
src/UsersModel.h
|
||||||
src/WebRTCSession.h
|
src/WebRTCSession.h
|
||||||
src/WelcomePage.h
|
src/WelcomePage.h
|
||||||
src/popups/PopupItem.h
|
src/popups/PopupItem.h
|
||||||
|
|
|
@ -34,11 +34,17 @@ Popup {
|
||||||
onCompleterNameChanged: {
|
onCompleterNameChanged: {
|
||||||
if (completerName)
|
if (completerName)
|
||||||
completer = TimelineManager.timeline.input.completerFor(completerName);
|
completer = TimelineManager.timeline.input.completerFor(completerName);
|
||||||
|
else
|
||||||
|
completer = undefined;
|
||||||
}
|
}
|
||||||
padding: 0
|
padding: 0
|
||||||
onAboutToShow: currentIndex = -1
|
onAboutToShow: currentIndex = -1
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
onTimelineChanged: completer = null
|
||||||
|
target: TimelineManager
|
||||||
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
|
@ -77,14 +77,13 @@ Rectangle {
|
||||||
onTextChanged: TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text)
|
onTextChanged: TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text)
|
||||||
onCursorPositionChanged: {
|
onCursorPositionChanged: {
|
||||||
TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text);
|
TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text);
|
||||||
if (cursorPosition < completerTriggeredAt) {
|
if (cursorPosition <= completerTriggeredAt) {
|
||||||
completerTriggeredAt = -1;
|
completerTriggeredAt = -1;
|
||||||
popup.close();
|
popup.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onSelectionStartChanged: TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text)
|
onSelectionStartChanged: TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text)
|
||||||
onSelectionEndChanged: TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text)
|
onSelectionEndChanged: TimelineManager.timeline.input.updateState(selectionStart, selectionEnd, cursorPosition, text)
|
||||||
// Ensure that we get escape key press events first.
|
|
||||||
Keys.onShortcutOverride: event.accepted = (completerTriggeredAt != -1 && (event.key === Qt.Key_Escape || event.key === Qt.Key_Tab || event.key === Qt.Key_Enter))
|
Keys.onShortcutOverride: event.accepted = (completerTriggeredAt != -1 && (event.key === Qt.Key_Escape || event.key === Qt.Key_Tab || event.key === Qt.Key_Enter))
|
||||||
Keys.onPressed: {
|
Keys.onPressed: {
|
||||||
if (event.matches(StandardKey.Paste)) {
|
if (event.matches(StandardKey.Paste)) {
|
||||||
|
@ -97,18 +96,20 @@ Rectangle {
|
||||||
} else if (event.modifiers == Qt.ControlModifier && event.key == Qt.Key_N) {
|
} else if (event.modifiers == Qt.ControlModifier && event.key == Qt.Key_N) {
|
||||||
textArea.text = TimelineManager.timeline.input.nextText();
|
textArea.text = TimelineManager.timeline.input.nextText();
|
||||||
} else if (event.key == Qt.Key_At) {
|
} else if (event.key == Qt.Key_At) {
|
||||||
completerTriggeredAt = cursorPosition + 1;
|
completerTriggeredAt = cursorPosition;
|
||||||
popup.completerName = "user";
|
popup.completerName = "user";
|
||||||
popup.open();
|
popup.open();
|
||||||
} else if (event.key == Qt.Key_Escape && popup.opened) {
|
} else if (event.key == Qt.Key_Escape && popup.opened) {
|
||||||
completerTriggeredAt = -1;
|
completerTriggeredAt = -1;
|
||||||
|
popup.completerName = "";
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
popup.close();
|
popup.close();
|
||||||
} else if (event.matches(StandardKey.InsertParagraphSeparator) && popup.opened) {
|
} else if (event.matches(StandardKey.InsertParagraphSeparator) && popup.opened) {
|
||||||
var currentCompletion = popup.currentCompletion();
|
var currentCompletion = popup.currentCompletion();
|
||||||
|
popup.completerName = "";
|
||||||
popup.close();
|
popup.close();
|
||||||
if (currentCompletion) {
|
if (currentCompletion) {
|
||||||
textArea.remove(completerTriggeredAt - 1, cursorPosition);
|
textArea.remove(completerTriggeredAt, cursorPosition);
|
||||||
textArea.insert(cursorPosition, currentCompletion);
|
textArea.insert(cursorPosition, currentCompletion);
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
return ;
|
return ;
|
||||||
|
@ -129,6 +130,17 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
onTimelineChanged: {
|
||||||
|
textArea.clear();
|
||||||
|
textArea.append(TimelineManager.timeline.input.text());
|
||||||
|
textArea.completerTriggeredAt = -1;
|
||||||
|
popup.completerName = "";
|
||||||
|
}
|
||||||
|
target: TimelineManager
|
||||||
|
}
|
||||||
|
// Ensure that we get escape key press events first.
|
||||||
|
|
||||||
Completer {
|
Completer {
|
||||||
id: popup
|
id: popup
|
||||||
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
// Class for showing a limited amount of completions at a time
|
|
||||||
|
|
||||||
#include <QSortFilterProxyModel>
|
|
||||||
|
|
||||||
class CompletionModel : public QSortFilterProxyModel
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CompletionModel(QAbstractItemModel *model, QObject *parent = nullptr)
|
|
||||||
: QSortFilterProxyModel(parent)
|
|
||||||
{
|
|
||||||
setSourceModel(model);
|
|
||||||
}
|
|
||||||
int rowCount(const QModelIndex &parent) const override
|
|
||||||
{
|
|
||||||
auto row_count = QSortFilterProxyModel::rowCount(parent);
|
|
||||||
return (row_count < 7) ? row_count : 7;
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -10,6 +10,6 @@ enum Roles
|
||||||
{
|
{
|
||||||
CompletionRole = Qt::UserRole * 2, // The string to replace the active completion
|
CompletionRole = Qt::UserRole * 2, // The string to replace the active completion
|
||||||
SearchRole, // String completer uses for search
|
SearchRole, // String completer uses for search
|
||||||
|
SearchRole2, // Secondary string completer uses for search
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,17 +4,36 @@
|
||||||
|
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
|
#include "CompletionModelRoles.h"
|
||||||
|
|
||||||
class CompletionProxyModel : public QSortFilterProxyModel
|
class CompletionProxyModel : public QSortFilterProxyModel
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CompletionProxyModel(QAbstractItemModel *model, QObject *parent = nullptr)
|
CompletionProxyModel(QAbstractItemModel *model, QObject *parent = nullptr)
|
||||||
: QSortFilterProxyModel(parent)
|
: QSortFilterProxyModel(parent)
|
||||||
{
|
{
|
||||||
setSourceModel(model);
|
setSourceModel(model);
|
||||||
}
|
}
|
||||||
int rowCount(const QModelIndex &parent) const override
|
|
||||||
|
QHash<int, QByteArray> roleNames() const override
|
||||||
|
{
|
||||||
|
return this->sourceModel()->roleNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override
|
||||||
{
|
{
|
||||||
auto row_count = QSortFilterProxyModel::rowCount(parent);
|
auto row_count = QSortFilterProxyModel::rowCount(parent);
|
||||||
return (row_count < 7) ? row_count : 7;
|
return (row_count < 7) ? row_count : 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
QVariant completionAt(int i) const
|
||||||
|
{
|
||||||
|
if (i >= 0 && i < rowCount())
|
||||||
|
return data(index(i, 0), CompletionModel::CompletionRole);
|
||||||
|
else
|
||||||
|
return {};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,12 +3,23 @@
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
#include "CompletionModelRoles.h"
|
#include "CompletionModelRoles.h"
|
||||||
|
|
||||||
#include <QPixmap>
|
|
||||||
|
|
||||||
UsersModel::UsersModel(const std::string &roomId, QObject *parent)
|
UsersModel::UsersModel(const std::string &roomId, QObject *parent)
|
||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
|
, room_id(roomId)
|
||||||
{
|
{
|
||||||
roomMembers_ = cache::getMembers(roomId, 0, 9999);
|
roomMembers_ = cache::roomMembers(roomId);
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<int, QByteArray>
|
||||||
|
UsersModel::roleNames() const
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
{CompletionModel::CompletionRole, "completionRole"},
|
||||||
|
{CompletionModel::SearchRole, "searchRole"},
|
||||||
|
{CompletionModel::SearchRole2, "searchRole2"},
|
||||||
|
{Roles::DisplayName, "displayName"},
|
||||||
|
{Roles::AvatarUrl, "avatarUrl"},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant
|
QVariant
|
||||||
|
@ -19,9 +30,14 @@ UsersModel::data(const QModelIndex &index, int role) const
|
||||||
case CompletionModel::CompletionRole:
|
case CompletionModel::CompletionRole:
|
||||||
case CompletionModel::SearchRole:
|
case CompletionModel::SearchRole:
|
||||||
case Qt::DisplayRole:
|
case Qt::DisplayRole:
|
||||||
return roomMembers_[index.row()].display_name;
|
case Roles::DisplayName:
|
||||||
case Avatar:
|
return QString::fromStdString(
|
||||||
return roomMembers_[index.row()].avatar;
|
cache::displayName(room_id, roomMembers_[index.row()]));
|
||||||
|
case CompletionModel::SearchRole2:
|
||||||
|
return QString::fromStdString(roomMembers_[index.row()]);
|
||||||
|
case Roles::AvatarUrl:
|
||||||
|
return cache::avatarUrl(QString::fromStdString(room_id),
|
||||||
|
QString::fromStdString(roomMembers_[index.row()]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -2,23 +2,25 @@
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
|
|
||||||
class RoomMember;
|
|
||||||
|
|
||||||
class UsersModel : public QAbstractListModel
|
class UsersModel : public QAbstractListModel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum Roles
|
enum Roles
|
||||||
{
|
{
|
||||||
Avatar = Qt::UserRole // QImage avatar
|
AvatarUrl = Qt::UserRole,
|
||||||
|
DisplayName,
|
||||||
};
|
};
|
||||||
|
|
||||||
UsersModel(const std::string &roomId, QObject *parent = nullptr);
|
UsersModel(const std::string &roomId, QObject *parent = nullptr);
|
||||||
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override
|
||||||
{
|
{
|
||||||
return (parent == QModelIndex()) ? roomMembers_.size() : 0;
|
(void)parent;
|
||||||
|
return roomMembers_.size();
|
||||||
}
|
}
|
||||||
QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<RoomMember> roomMembers_;
|
std::string room_id;
|
||||||
|
std::vector<std::string> roomMembers_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,12 +14,14 @@
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
#include "CallManager.h"
|
#include "CallManager.h"
|
||||||
#include "ChatPage.h"
|
#include "ChatPage.h"
|
||||||
|
#include "CompletionProxyModel.h"
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
#include "Olm.h"
|
#include "Olm.h"
|
||||||
#include "TimelineModel.h"
|
#include "TimelineModel.h"
|
||||||
#include "UserSettingsPage.h"
|
#include "UserSettingsPage.h"
|
||||||
|
#include "UsersModel.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
#include "dialogs/PlaceCall.h"
|
#include "dialogs/PlaceCall.h"
|
||||||
#include "dialogs/PreviewUploadOverlay.h"
|
#include "dialogs/PreviewUploadOverlay.h"
|
||||||
|
@ -166,6 +168,12 @@ InputBar::nextText()
|
||||||
QObject *
|
QObject *
|
||||||
InputBar::completerFor(QString completerName)
|
InputBar::completerFor(QString completerName)
|
||||||
{
|
{
|
||||||
|
if (completerName == "user") {
|
||||||
|
auto userModel = new UsersModel(room->roomId().toStdString());
|
||||||
|
auto proxy = new CompletionProxyModel(userModel);
|
||||||
|
userModel->setParent(proxy);
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue