Allow scrolling to specific sections and order packs in sticker search by match quality

This commit is contained in:
Nicolas Werner 2023-05-20 00:31:47 +02:00
parent 58cfc39ac4
commit 62844facf7
No known key found for this signature in database
GPG key ID: C8D75E610773F2D9
3 changed files with 130 additions and 26 deletions

View file

@ -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,9 +106,23 @@ Menu {
}
}
Component {
id: sectionHeading
Rectangle {
// 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
boundsBehavior: Flickable.StopAtBounds
clip: true
currentIndex: -1 // prevent sorting from stealing focus
section.property: "packname"
section.criteria: ViewSection.FullString
section.delegate: Rectangle {
width: gridView.width
height: childrenRect.height
color: Nheko.colors.alternateBase
@ -119,23 +137,6 @@ Menu {
font.bold: true
}
}
}
// sticker grid
ListView {
id: gridView
model: roomid ? TimelineManager.completerFor("stickergrid", roomid) : null
Layout.preferredHeight: cellHeight * 3.5
Layout.preferredWidth: stickersPerRow * stickerDimPad + 20 - Nheko.paddingSmall
property int cellHeight: stickerDimPad
boundsBehavior: Flickable.StopAtBounds
clip: true
currentIndex: -1 // prevent sorting from stealing focus
section.property: "packname"
section.criteria: ViewSection.FullString
section.delegate: sectionHeading
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)
}
}
}
}

View file

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

View file

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