Fix some issues with completer

This commit is contained in:
Nicolas Werner 2020-11-24 02:35:38 +01:00
parent c2eea5cb55
commit 29625ae253
5 changed files with 146 additions and 70 deletions

View file

@ -53,7 +53,6 @@ Rectangle {
Connections { Connections {
target: TimelineManager target: TimelineManager
onCallStateChanged: { onCallStateChanged: {
switch (state) { switch (state) {
case WebRTCState.INITIATING: case WebRTCState.INITIATING:

View file

@ -9,105 +9,120 @@ Popup {
property int currentIndex: -1 property int currentIndex: -1
property string completerName property string completerName
property var completer property var completer
property bool bottomToTop: true
function up() { function up() {
currentIndex = currentIndex - 1; if (bottomToTop)
if (currentIndex == -2) down_();
currentIndex = repeater.count - 1; else
up_();
} }
function down() { function down() {
if (bottomToTop)
up_();
else
down_();
}
function up_() {
currentIndex = currentIndex - 1;
if (currentIndex == -2)
currentIndex = listView.count - 1;
}
function down_() {
currentIndex = currentIndex + 1; currentIndex = currentIndex + 1;
if (currentIndex >= repeater.count) if (currentIndex >= listView.count)
currentIndex = -1; currentIndex = -1;
} }
function currentCompletion() { function currentCompletion() {
if (currentIndex > -1 && currentIndex < repeater.count) if (currentIndex > -1 && currentIndex < listView.count)
return completer.completionAt(currentIndex); return completer.completionAt(currentIndex);
else else
return null; return null;
} }
onCompleterNameChanged: { onCompleterNameChanged: {
if (completerName) if (completerName) {
completer = TimelineManager.timeline.input.completerFor(completerName); completer = TimelineManager.timeline.input.completerFor(completerName);
else completer.setSearchString("");
} else {
completer = undefined; completer = undefined;
}
} }
padding: 0 padding: 0
onAboutToShow: currentIndex = -1 onAboutToShow: currentIndex = -1
height: listView.contentHeight
Connections { Connections {
onTimelineChanged: completer = null onTimelineChanged: completer = null
target: TimelineManager target: TimelineManager
} }
ColumnLayout { ListView {
id: listView
anchors.fill: parent anchors.fill: parent
spacing: 0 implicitWidth: contentItem.childrenRect.width
model: completer
verticalLayoutDirection: popup.bottomToTop ? ListView.BottomToTop : ListView.TopToBottom
Repeater { delegate: Rectangle {
id: repeater color: model.index == popup.currentIndex ? colors.highlight : colors.base
height: chooser.childrenRect.height + 4
implicitWidth: chooser.childrenRect.width + 4
model: completer DelegateChooser {
id: chooser
delegate: Rectangle { roleValue: popup.completerName
color: model.index == popup.currentIndex ? colors.window : colors.alternateBase anchors.centerIn: parent
height: chooser.childrenRect.height + 4
width: chooser.childrenRect.width + 4
DelegateChooser { DelegateChoice {
id: chooser roleValue: "user"
roleValue: popup.completerName RowLayout {
anchors.centerIn: parent id: del
DelegateChoice { anchors.centerIn: parent
roleValue: "user"
RowLayout { Avatar {
id: del height: 24
width: 24
anchors.centerIn: parent displayName: model.displayName
url: model.avatarUrl.replace("mxc://", "image://MxcImage/")
Avatar { }
height: 24
width: 24
displayName: model.displayName
url: model.avatarUrl.replace("mxc://", "image://MxcImage/")
}
Label {
text: model.displayName
color: colors.text
}
Label {
text: model.displayName
color: model.index == popup.currentIndex ? colors.highlightedText : colors.text
} }
} }
DelegateChoice { }
roleValue: "emoji"
RowLayout { DelegateChoice {
id: del roleValue: "emoji"
anchors.centerIn: parent RowLayout {
id: del
Label { anchors.centerIn: parent
text: model.unicode
color: colors.text
font: Settings.emojiFont
}
Label { Label {
text: model.shortName text: model.unicode
color: colors.text color: model.index == popup.currentIndex ? colors.highlightedText : colors.text
} font: Settings.emojiFont
}
Label {
text: model.shortName
color: model.index == popup.currentIndex ? colors.highlightedText : colors.text
} }
} }
@ -141,7 +156,7 @@ Popup {
} }
background: Rectangle { background: Rectangle {
color: colors.alternateBase color: colors.base
implicitHeight: popup.contentHeight implicitHeight: popup.contentHeight
implicitWidth: popup.contentWidth implicitWidth: popup.contentWidth
} }

View file

@ -182,7 +182,6 @@ ListView {
Connections { Connections {
target: chat target: chat
onMovementEnded: { onMovementEnded: {
if (y + height + 2 * chat.spacing > chat.contentY + chat.height && y < chat.contentY + chat.height) if (y + height + 2 * chat.spacing > chat.contentY + chat.height && y < chat.contentY + chat.height)
chat.model.currentIndex = index; chat.model.currentIndex = index;

View file

@ -131,7 +131,6 @@ Page {
Connections { Connections {
target: TimelineManager target: TimelineManager
onNewDeviceVerificationRequest: { onNewDeviceVerificationRequest: {
var dialog = deviceVerificationDialog.createObject(timelineRoot, { var dialog = deviceVerificationDialog.createObject(timelineRoot, {
"flow": flow "flow": flow
@ -142,7 +141,6 @@ Page {
Connections { Connections {
target: TimelineManager.timeline target: TimelineManager.timeline
onOpenProfile: { onOpenProfile: {
var userProfile = userProfileComponent.createObject(timelineRoot, { var userProfile = userProfileComponent.createObject(timelineRoot, {
"profile": profile "profile": profile

View file

@ -43,29 +43,94 @@ struct trie
return ret; return ret;
else { else {
auto temp = t.valuesAndSubvalues(limit - ret.size()); auto temp = t.valuesAndSubvalues(limit - ret.size());
ret.insert(ret.end(), temp.begin(), temp.end()); for (auto &&v : temp) {
if (ret.size() >= limit)
return ret;
if (std::find(ret.begin(), ret.end(), v) == ret.end()) {
ret.push_back(std::move(v));
}
}
} }
} }
return ret; return ret;
} }
std::vector<Value> search(const QVector<Key> &keys, size_t limit) const std::vector<Value> search(const QVector<Key> &keys,
size_t limit,
size_t max_distance = 2) const
{ {
std::vector<Value> ret; std::vector<Value> ret;
auto t = this; if (!limit)
int i = 0; return ret;
for (; i < (int)keys.size(); i++) {
if (auto e = t->next.find(keys[i]); e != t->next.end()) { auto append = [&ret, limit](std::vector<Value> &&in) {
t = &e->second; for (auto &&v : in) {
} else { if (ret.size() >= limit)
t = nullptr; return;
break;
if (std::find(ret.begin(), ret.end(), v) == ret.end()) {
ret.push_back(std::move(v));
}
}
};
{
auto t = this;
int i = 0;
for (; i < (int)keys.size(); i++) {
if (auto e = t->next.find(keys[i]); e != t->next.end()) {
t = &e->second;
} else {
t = nullptr;
break;
}
}
if (t) {
ret = t->valuesAndSubvalues(limit);
} }
} }
if (t) { if (max_distance && keys.size() < static_cast<int>(limit) && keys.size() > 1) {
ret = t->valuesAndSubvalues(limit); max_distance -= 1;
// swap chars case
if (keys.size() >= 2) {
auto t = this;
for (int i = 1; i >= 0; i--) {
if (auto e = t->next.find(keys[i]); e != t->next.end()) {
t = &e->second;
} else {
t = nullptr;
break;
}
}
if (t) {
append(t->search(
keys.mid(2), (limit - ret.size()) * 2, max_distance));
}
}
// delete character case
append(this->search(keys.mid(1), (limit - ret.size()) * 2, max_distance));
// substitute and insert cases
for (const auto &[k, t] : this->next) {
if (k == keys[0] || ret.size() >= limit)
break;
// substitute
append(this->search(keys.mid(1), limit - ret.size(), max_distance));
if (ret.size() >= limit)
break;
// insert
append(this->search(keys, limit - ret.size(), max_distance));
}
} }
return ret; return ret;