mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-27 13:38:49 +03:00
Allow scrolling to specific sections and order packs in sticker search by match quality
This commit is contained in:
parent
c153619b68
commit
c1b7c026e4
3 changed files with 130 additions and 26 deletions
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue