remove emoji reaction feature (KDE GUI)

This commit is contained in:
Levi Neely 2026-07-31 09:09:30 +02:00
parent d473fb4e4c
commit 5bdab3c616
5 changed files with 11 additions and 106 deletions

View File

@ -47,7 +47,6 @@ Item {
if (chat) {
paneModel.rawText = chat.text
chatOffset = chat.offset
paneModel.setReactions(dbus.getReactions(sessionId))
}
let cfg = dbus.getConfig(sessionId)
if (cfg && cfg.cwd) paneCwd = cfg.cwd
@ -67,14 +66,12 @@ Item {
if (offset === paneRoot.chatOffset) {
paneModel.rawText = paneModel.rawText + text
paneRoot.chatOffset += text.length
paneModel.setReactions(dbus.getReactions(paneRoot.sessionId))
} else {
// Offset mismatch - refetch
let chat = dbus.getChat(paneRoot.sessionId, 0)
if (chat) {
paneModel.rawText = chat.text
paneRoot.chatOffset = chat.offset
paneModel.setReactions(dbus.getReactions(paneRoot.sessionId))
}
}
}
@ -687,46 +684,21 @@ Item {
Behavior on opacity { NumberAnimation { duration: 150 } }
}
// Reaction badge (pinned when reacted)
Label {
// Copy button
ToolButton {
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.margins: 4
z: 10
text: block ? (block.reaction || "") : ""
font.pixelSize: 18
visible: block ? block.reaction !== "" : false
}
// Reaction buttons (hover only, hidden when already reacted)
Row {
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.rightMargin: block && block.reaction !== "" ? 36 : 4
anchors.margins: 4
z: 10
spacing: 2
opacity: (assistantHover.hovered && (block ? block.reaction : "") === "") ? 0.9 : 0
text: "\uD83D\uDCCB"
font.pixelSize: 14
implicitWidth: 28
implicitHeight: 28
opacity: assistantHover.hovered ? 0.9 : 0
Behavior on opacity { NumberAnimation { duration: 150 } }
Repeater {
model: [
{ emoji: "\uD83D\uDC4D", tip: "Good" },
{ emoji: "\uD83D\uDC4E", tip: "Bad" },
{ emoji: "\uD83D\uDE80", tip: "Excellent" },
{ emoji: "\uD83D\uDCA9", tip: "Very bad" },
{ emoji: "\uD83E\uDD14", tip: "Confused" }
]
ToolButton {
text: modelData.emoji
font.pixelSize: 14
implicitWidth: 28
implicitHeight: 28
onClicked: { dbus.reactTo(paneRoot.sessionId, block.responseId, modelData.emoji); paneModel.setReactions(dbus.getReactions(paneRoot.sessionId)) }
ToolTip.text: modelData.tip
ToolTip.visible: hovered
}
}
onClicked: paneModel.copyToClipboard(block.content)
ToolTip.text: "Copy"
ToolTip.visible: hovered
}
ColumnLayout {

View File

@ -74,8 +74,6 @@ QVariant ChatBlockModel::data(const QModelIndex &index, int role) const
return block.content;
case ResponseIdRole:
return block.responseId;
case ReactionRole:
return block.reaction;
case SubBlocksRole:
if (block.cachedContent != block.content) {
block.cachedSubBlocks = parseSubBlocks(block.content);
@ -115,40 +113,9 @@ QHash<int, QByteArray> ChatBlockModel::roleNames() const
{SubBlocksRole, "subBlocks"},
{FormattedContentRole, "formattedContent"},
{ResponseIdRole, "responseId"},
{ReactionRole, "reaction"},
};
}
void ChatBlockModel::setReactions(const QVariantMap &reactions)
{
QHash<QString, QString> reactionMap;
for (auto it = reactions.constBegin(); it != reactions.constEnd(); ++it)
reactionMap[it.key()] = it.value().toString();
// Update m_allBlocks for future scroll/loadEarlier
for (int i = 0; i < m_allBlocks.size(); ++i) {
if (m_allBlocks[i].type == ChatBlock::Assistant && !m_allBlocks[i].responseId.isEmpty())
m_allBlocks[i].reaction = reactionMap.value(m_allBlocks[i].responseId);
}
// Update visible m_blocks with dataChanged signal
for (int i = 0; i < m_blocks.size(); ++i) {
if (m_blocks[i].type == ChatBlock::Assistant && !m_blocks[i].responseId.isEmpty()) {
QString emoji = reactionMap.value(m_blocks[i].responseId);
if (m_blocks[i].reaction != emoji) {
m_blocks[i].reaction = emoji;
emit dataChanged(index(i), index(i));
}
}
}
// Update filtered blocks too
for (int i = 0; i < m_filteredBlocks.size(); ++i) {
if (m_filteredBlocks[i].type == ChatBlock::Assistant && !m_filteredBlocks[i].responseId.isEmpty())
m_filteredBlocks[i].reaction = reactionMap.value(m_filteredBlocks[i].responseId);
}
}
void ChatBlockModel::setRawText(const QString &text)
{
if (text == m_rawText) return;
@ -219,8 +186,7 @@ void ChatBlockModel::updateVisibleWindow()
if (m_blocks[i].content != newBlocks[i].content ||
m_blocks[i].type != newBlocks[i].type ||
m_blocks[i].name != newBlocks[i].name ||
m_blocks[i].responseId != newBlocks[i].responseId ||
m_blocks[i].reaction != newBlocks[i].reaction) {
m_blocks[i].responseId != newBlocks[i].responseId) {
firstDiff = i;
break;
}

View File

@ -20,7 +20,6 @@ struct ChatBlock {
Type type;
QString name; // tool/call name, empty for others
QString responseId; // stable assistant response ID
QString reaction; // emoji reaction text (empty if not reacted)
QString content; // raw text content
mutable QVariantList cachedSubBlocks; // cached parseSubBlocks result
mutable QString cachedContent; // content when subBlocks were cached
@ -55,7 +54,6 @@ public:
SubBlocksRole, // QVariantList of sub-block maps
FormattedContentRole, // pre-formatted HTML for call/tool expanded view
ResponseIdRole,
ReactionRole,
};
explicit ChatBlockModel(QObject *parent = nullptr);
@ -79,7 +77,6 @@ public:
Q_INVOKABLE bool executeInTerminal(const QString &code, const QString &language,
const QString &workingDirectory = QString()) const;
Q_INVOKABLE bool loadEarlier(); // returns true if more blocks were loaded
Q_INVOKABLE void setReactions(const QVariantMap &reactions);
Q_INVOKABLE QString diagramUrl(const QString &source, const QString &language) const;
Q_INVOKABLE bool invalidateDiagram(const QString &source, const QString &language) const;

View File

@ -398,21 +398,6 @@ QVariantMap OllieDBusClient::getChat(const QString &sessionId, int offset)
return result;
}
QVariantMap OllieDBusClient::getReactions(const QString &sessionId)
{
QDBusReply<QString> reply = m_iface->call("GetReactions", sessionId);
QVariantMap result;
if (reply.isValid()) {
QJsonDocument doc = QJsonDocument::fromJson(reply.value().toUtf8());
if (doc.isObject()) {
QJsonObject obj = doc.object();
for (auto it = obj.begin(); it != obj.end(); ++it)
result[it.key()] = it.value().toString();
}
}
return result;
}
QVariantMap OllieDBusClient::getConfig(const QString &sessionId)
{
QDBusReply<QString> reply = m_iface->call("GetConfig", sessionId);
@ -485,18 +470,6 @@ bool OllieDBusClient::submit(const QString &sessionId, const QString &prompt)
return true;
}
bool OllieDBusClient::react(const QString &sessionId, const QString &emoji)
{
m_iface->asyncCall("React", sessionId, emoji);
return true;
}
bool OllieDBusClient::reactTo(const QString &sessionId, const QString &responseId, const QString &emoji)
{
m_iface->asyncCall("ReactTo", sessionId, responseId, emoji);
return true;
}
bool OllieDBusClient::interrupt(const QString &sessionId)
{
m_iface->asyncCall("Interrupt", sessionId);

View File

@ -35,7 +35,6 @@ public:
Q_INVOKABLE QStringList peerList(const QString &sessionId);
Q_INVOKABLE QVariantMap getChat(const QString &sessionId, int offset);
Q_INVOKABLE QVariantMap getReactions(const QString &sessionId);
Q_INVOKABLE QVariantMap getConfig(const QString &sessionId);
Q_INVOKABLE QString getState(const QString &sessionId);
QString activeSessionId() const { return m_activeSessionId; }
@ -55,8 +54,6 @@ public:
Q_INVOKABLE bool renameSession(const QString &sessionId, const QString &newName);
Q_INVOKABLE bool setConfig(const QString &sessionId, const QString &key, const QString &value);
Q_INVOKABLE bool submit(const QString &sessionId, const QString &prompt);
Q_INVOKABLE bool react(const QString &sessionId, const QString &emoji);
Q_INVOKABLE bool reactTo(const QString &sessionId, const QString &responseId, const QString &emoji);
Q_INVOKABLE bool interrupt(const QString &sessionId);
Q_INVOKABLE QStringList listBackends();
Q_INVOKABLE QStringList listModels(const QString &sessionId);