summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2023-05-20 00:31:47 +0200
committerNicolas Werner <nicolas.werner@hotmail.de>2023-05-20 00:57:52 +0200
commit62844facf7995f8d730a0f94a6d8a8559ac5410b (patch)
treeed513a8f2bd82c9368592fb3fb9563fd3173f7b8
parent58cfc39ac42633eafb65f17483533ef285b72c38 (diff)
Allow scrolling to specific sections and order packs in sticker search by match quality
-rw-r--r--resources/qml/emoji/StickerPicker.qml72
-rw-r--r--src/GridImagePackModel.cpp67
-rw-r--r--src/GridImagePackModel.h17
3 files changed, 130 insertions, 26 deletions
diff --git a/resources/qml/emoji/StickerPicker.qml b/resources/qml/emoji/StickerPicker.qml
index ce4d5200..2e1956b1 100644
--- a/resources/qml/emoji/StickerPicker.qml
+++ b/resources/qml/emoji/StickerPicker.qml
@@ -24,6 +24,7 @@ Menu {
readonly property int stickerDim: 128
readonly property int stickerDimPad: 128 + Nheko.paddingSmall
readonly property int stickersPerRow: 3
+ readonly property int sidebarAvatarSize: 24
function show(showAt, roomid_, callback) {
console.debug("Showing sticker picker");
@@ -40,28 +41,31 @@ Menu {
modal: true
focus: true
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
- width: stickersPerRow * stickerDimPad + 20
+ width: sidebarAvatarSize + Nheko.paddingSmall + stickersPerRow * stickerDimPad + 20
Rectangle {
color: Nheko.colors.window
height: columnView.implicitHeight + Nheko.paddingSmall*2
- width: stickersPerRow * stickerDimPad + 20
+ width: sidebarAvatarSize + Nheko.paddingSmall + stickersPerRow * stickerDimPad + 20
- ColumnLayout {
+ GridLayout {
id: columnView
- spacing: Nheko.paddingSmall
anchors.leftMargin: Nheko.paddingSmall
anchors.rightMargin: Nheko.paddingSmall
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
+ columns: 2
+ rows: 2
// Search field
TextField {
id: emojiSearch
Layout.preferredWidth: stickersPerRow * stickerDimPad + 20 - Nheko.paddingSmall
+ Layout.row: 0
+ Layout.column: 1
palette: Nheko.colors
background: null
placeholderTextColor: Nheko.colors.buttonText
@@ -102,30 +106,13 @@ Menu {
}
}
- Component {
- id: sectionHeading
- Rectangle {
- width: gridView.width
- height: childrenRect.height
- color: Nheko.colors.alternateBase
-
- required property string section
-
- Text {
- anchors.left: parent.left
- anchors.right: parent.right
- text: parent.section
- color: Nheko.colors.text
- font.bold: true
- }
- }
- }
-
// sticker grid
ListView {
id: gridView
model: roomid ? TimelineManager.completerFor("stickergrid", roomid) : null
+ Layout.row: 1
+ Layout.column: 1
Layout.preferredHeight: cellHeight * 3.5
Layout.preferredWidth: stickersPerRow * stickerDimPad + 20 - Nheko.paddingSmall
property int cellHeight: stickerDimPad
@@ -135,7 +122,21 @@ Menu {
section.property: "packname"
section.criteria: ViewSection.FullString
- section.delegate: sectionHeading
+ section.delegate: Rectangle {
+ width: gridView.width
+ height: childrenRect.height
+ color: Nheko.colors.alternateBase
+
+ required property string section
+
+ Text {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ text: parent.section
+ color: Nheko.colors.text
+ font.bold: true
+ }
+ }
section.labelPositioning: ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart
spacing: Nheko.paddingSmall
@@ -191,6 +192,29 @@ Menu {
}
+ ListView {
+ Layout.row: 1
+ Layout.column: 0
+ Layout.preferredWidth: sidebarAvatarSize
+ Layout.fillHeight: true
+ Layout.rightMargin: Nheko.paddingSmall
+
+ model: gridView.model ? gridView.model.sections : null
+ spacing: Nheko.paddingSmall
+
+ delegate: Avatar {
+ height: sidebarAvatarSize
+ width: sidebarAvatarSize
+ url: modelData.url.replace("mxc://", "image://MxcImage/")
+ displayName: modelData.name
+ roomid: modelData.name
+
+ hoverEnabled: true
+ ToolTip.visible: hovered
+ ToolTip.text: modelData.name
+ onClicked: gridView.positionViewAtIndex(modelData.firstRowWith, ListView.Beginning)
+ }
+ }
}
}
diff --git a/src/GridImagePackModel.cpp b/src/GridImagePackModel.cpp
index 59b1725a..5db8c0cc 100644
--- a/src/GridImagePackModel.cpp
+++ b/src/GridImagePackModel.cpp
@@ -12,12 +12,16 @@
#include "Cache_p.h"
Q_DECLARE_METATYPE(StickerImage)
+Q_DECLARE_METATYPE(SectionDescription)
+Q_DECLARE_METATYPE(QList<SectionDescription>)
GridImagePackModel::GridImagePackModel(const std::string &roomId, bool stickers, QObject *parent)
: QAbstractListModel(parent)
, room_id(roomId)
{
- [[maybe_unused]] static auto id = qRegisterMetaType<StickerImage>();
+ [[maybe_unused]] static auto id = qRegisterMetaType<StickerImage>();
+ [[maybe_unused]] static auto id2 = qRegisterMetaType<SectionDescription>();
+ [[maybe_unused]] static auto id3 = qRegisterMetaType<QList<SectionDescription>>();
auto originalPacks = cache::client()->getImagePacks(room_id, stickers);
@@ -182,6 +186,58 @@ GridImagePackModel::nameFromPack(const PackDesc &pack) const
return tr("Account Pack");
}
+QString
+GridImagePackModel::avatarFromPack(const PackDesc &pack) const
+{
+ if (!pack.packavatar.isEmpty()) {
+ return pack.packavatar;
+ }
+
+ if (!pack.images.empty()) {
+ return QString::fromStdString(pack.images.begin()->first.url);
+ }
+
+ return "";
+}
+
+QList<SectionDescription>
+GridImagePackModel::sections() const
+{
+ QList<SectionDescription> sectionNames;
+ if (searchString_.isEmpty()) {
+ std::size_t packIdx = -1;
+ for (std::size_t i = 0; i < rowToPack.size(); i++) {
+ if (rowToPack[i] != packIdx) {
+ const auto &pack = packs[rowToPack[i]];
+ sectionNames.push_back({
+ .name = nameFromPack(pack),
+ .url = avatarFromPack(pack),
+ .firstRowWith = static_cast<int>(i),
+ });
+ packIdx = rowToPack[i];
+ }
+ }
+ } else {
+ std::uint32_t packIdx = -1;
+ int row = 0;
+ for (const auto &i : rowToFirstRowEntryFromSearch) {
+ const auto res = currentSearchResult[i];
+ if (res.first != packIdx) {
+ packIdx = res.first;
+ const auto &pack = packs[packIdx];
+ sectionNames.push_back({
+ .name = nameFromPack(pack),
+ .url = avatarFromPack(pack),
+ .firstRowWith = row,
+ });
+ }
+ row++;
+ }
+ }
+
+ return sectionNames;
+}
+
void
GridImagePackModel::setSearchString(QString key)
{
@@ -194,7 +250,14 @@ GridImagePackModel::setSearchString(QString key)
auto searchParts = key.toCaseFolded().toUcs4();
auto tempResults =
trie_.search(searchParts, static_cast<std::size_t>(columns * columns * 4));
- std::ranges::sort(tempResults);
+
+ std::map<std::uint32_t, std::size_t> firstPositionOfPack;
+ for (const auto &e : tempResults)
+ firstPositionOfPack.emplace(e.first, firstPositionOfPack.size());
+
+ std::ranges::stable_sort(tempResults, [&firstPositionOfPack](auto a, auto b) {
+ return firstPositionOfPack[a.first] < firstPositionOfPack[b.first];
+ });
currentSearchResult = std::move(tempResults);
std::size_t lastPack = -1;
diff --git a/src/GridImagePackModel.h b/src/GridImagePackModel.h
index 8da61b8e..c6be3346 100644
--- a/src/GridImagePackModel.h
+++ b/src/GridImagePackModel.h
@@ -41,10 +41,24 @@ public:
std::vector<std::string> descriptor_; // roomid, statekey, shortcode
};
+struct SectionDescription
+{
+ Q_GADGET
+ Q_PROPERTY(QString url MEMBER url CONSTANT)
+ Q_PROPERTY(QString name MEMBER name CONSTANT)
+ Q_PROPERTY(int firstRowWith MEMBER firstRowWith CONSTANT)
+
+public:
+ QString name;
+ QString url;
+ int firstRowWith = 0;
+};
+
class GridImagePackModel final : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(QString searchString READ searchString WRITE setSearchString NOTIFY newSearchString)
+ Q_PROPERTY(QList<SectionDescription> sections READ sections NOTIFY newSearchString)
public:
enum Roles
@@ -61,6 +75,8 @@ public:
QString searchString() const { return searchString_; }
void setSearchString(QString newValue);
+ QList<SectionDescription> sections() const;
+
signals:
void newSearchString();
@@ -87,4 +103,5 @@ private:
std::vector<std::size_t> rowToFirstRowEntryFromSearch;
QString nameFromPack(const PackDesc &pack) const;
+ QString avatarFromPack(const PackDesc &pack) const;
};