remove emoji reaction feature (KDE GUI)
This commit is contained in:
parent
d473fb4e4c
commit
5bdab3c616
|
|
@ -47,7 +47,6 @@ Item {
|
||||||
if (chat) {
|
if (chat) {
|
||||||
paneModel.rawText = chat.text
|
paneModel.rawText = chat.text
|
||||||
chatOffset = chat.offset
|
chatOffset = chat.offset
|
||||||
paneModel.setReactions(dbus.getReactions(sessionId))
|
|
||||||
}
|
}
|
||||||
let cfg = dbus.getConfig(sessionId)
|
let cfg = dbus.getConfig(sessionId)
|
||||||
if (cfg && cfg.cwd) paneCwd = cfg.cwd
|
if (cfg && cfg.cwd) paneCwd = cfg.cwd
|
||||||
|
|
@ -67,14 +66,12 @@ Item {
|
||||||
if (offset === paneRoot.chatOffset) {
|
if (offset === paneRoot.chatOffset) {
|
||||||
paneModel.rawText = paneModel.rawText + text
|
paneModel.rawText = paneModel.rawText + text
|
||||||
paneRoot.chatOffset += text.length
|
paneRoot.chatOffset += text.length
|
||||||
paneModel.setReactions(dbus.getReactions(paneRoot.sessionId))
|
|
||||||
} else {
|
} else {
|
||||||
// Offset mismatch - refetch
|
// Offset mismatch - refetch
|
||||||
let chat = dbus.getChat(paneRoot.sessionId, 0)
|
let chat = dbus.getChat(paneRoot.sessionId, 0)
|
||||||
if (chat) {
|
if (chat) {
|
||||||
paneModel.rawText = chat.text
|
paneModel.rawText = chat.text
|
||||||
paneRoot.chatOffset = chat.offset
|
paneRoot.chatOffset = chat.offset
|
||||||
paneModel.setReactions(dbus.getReactions(paneRoot.sessionId))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -687,46 +684,21 @@ Item {
|
||||||
Behavior on opacity { NumberAnimation { duration: 150 } }
|
Behavior on opacity { NumberAnimation { duration: 150 } }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reaction badge (pinned when reacted)
|
// Copy button
|
||||||
Label {
|
ToolButton {
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.margins: 4
|
anchors.margins: 4
|
||||||
z: 10
|
z: 10
|
||||||
text: block ? (block.reaction || "") : ""
|
text: "\uD83D\uDCCB"
|
||||||
font.pixelSize: 18
|
font.pixelSize: 14
|
||||||
visible: block ? block.reaction !== "" : false
|
implicitWidth: 28
|
||||||
}
|
implicitHeight: 28
|
||||||
|
opacity: assistantHover.hovered ? 0.9 : 0
|
||||||
// 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
|
|
||||||
Behavior on opacity { NumberAnimation { duration: 150 } }
|
Behavior on opacity { NumberAnimation { duration: 150 } }
|
||||||
|
onClicked: paneModel.copyToClipboard(block.content)
|
||||||
Repeater {
|
ToolTip.text: "Copy"
|
||||||
model: [
|
ToolTip.visible: hovered
|
||||||
{ 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
|
|
||||||
|
|
@ -74,8 +74,6 @@ QVariant ChatBlockModel::data(const QModelIndex &index, int role) const
|
||||||
return block.content;
|
return block.content;
|
||||||
case ResponseIdRole:
|
case ResponseIdRole:
|
||||||
return block.responseId;
|
return block.responseId;
|
||||||
case ReactionRole:
|
|
||||||
return block.reaction;
|
|
||||||
case SubBlocksRole:
|
case SubBlocksRole:
|
||||||
if (block.cachedContent != block.content) {
|
if (block.cachedContent != block.content) {
|
||||||
block.cachedSubBlocks = parseSubBlocks(block.content);
|
block.cachedSubBlocks = parseSubBlocks(block.content);
|
||||||
|
|
@ -115,40 +113,9 @@ QHash<int, QByteArray> ChatBlockModel::roleNames() const
|
||||||
{SubBlocksRole, "subBlocks"},
|
{SubBlocksRole, "subBlocks"},
|
||||||
{FormattedContentRole, "formattedContent"},
|
{FormattedContentRole, "formattedContent"},
|
||||||
{ResponseIdRole, "responseId"},
|
{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)
|
void ChatBlockModel::setRawText(const QString &text)
|
||||||
{
|
{
|
||||||
if (text == m_rawText) return;
|
if (text == m_rawText) return;
|
||||||
|
|
@ -219,8 +186,7 @@ void ChatBlockModel::updateVisibleWindow()
|
||||||
if (m_blocks[i].content != newBlocks[i].content ||
|
if (m_blocks[i].content != newBlocks[i].content ||
|
||||||
m_blocks[i].type != newBlocks[i].type ||
|
m_blocks[i].type != newBlocks[i].type ||
|
||||||
m_blocks[i].name != newBlocks[i].name ||
|
m_blocks[i].name != newBlocks[i].name ||
|
||||||
m_blocks[i].responseId != newBlocks[i].responseId ||
|
m_blocks[i].responseId != newBlocks[i].responseId) {
|
||||||
m_blocks[i].reaction != newBlocks[i].reaction) {
|
|
||||||
firstDiff = i;
|
firstDiff = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ struct ChatBlock {
|
||||||
Type type;
|
Type type;
|
||||||
QString name; // tool/call name, empty for others
|
QString name; // tool/call name, empty for others
|
||||||
QString responseId; // stable assistant response ID
|
QString responseId; // stable assistant response ID
|
||||||
QString reaction; // emoji reaction text (empty if not reacted)
|
|
||||||
QString content; // raw text content
|
QString content; // raw text content
|
||||||
mutable QVariantList cachedSubBlocks; // cached parseSubBlocks result
|
mutable QVariantList cachedSubBlocks; // cached parseSubBlocks result
|
||||||
mutable QString cachedContent; // content when subBlocks were cached
|
mutable QString cachedContent; // content when subBlocks were cached
|
||||||
|
|
@ -55,7 +54,6 @@ public:
|
||||||
SubBlocksRole, // QVariantList of sub-block maps
|
SubBlocksRole, // QVariantList of sub-block maps
|
||||||
FormattedContentRole, // pre-formatted HTML for call/tool expanded view
|
FormattedContentRole, // pre-formatted HTML for call/tool expanded view
|
||||||
ResponseIdRole,
|
ResponseIdRole,
|
||||||
ReactionRole,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit ChatBlockModel(QObject *parent = nullptr);
|
explicit ChatBlockModel(QObject *parent = nullptr);
|
||||||
|
|
@ -79,7 +77,6 @@ public:
|
||||||
Q_INVOKABLE bool executeInTerminal(const QString &code, const QString &language,
|
Q_INVOKABLE bool executeInTerminal(const QString &code, const QString &language,
|
||||||
const QString &workingDirectory = QString()) const;
|
const QString &workingDirectory = QString()) const;
|
||||||
Q_INVOKABLE bool loadEarlier(); // returns true if more blocks were loaded
|
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 QString diagramUrl(const QString &source, const QString &language) const;
|
||||||
Q_INVOKABLE bool invalidateDiagram(const QString &source, const QString &language) const;
|
Q_INVOKABLE bool invalidateDiagram(const QString &source, const QString &language) const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -398,21 +398,6 @@ QVariantMap OllieDBusClient::getChat(const QString &sessionId, int offset)
|
||||||
return result;
|
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)
|
QVariantMap OllieDBusClient::getConfig(const QString &sessionId)
|
||||||
{
|
{
|
||||||
QDBusReply<QString> reply = m_iface->call("GetConfig", sessionId);
|
QDBusReply<QString> reply = m_iface->call("GetConfig", sessionId);
|
||||||
|
|
@ -485,18 +470,6 @@ bool OllieDBusClient::submit(const QString &sessionId, const QString &prompt)
|
||||||
return true;
|
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)
|
bool OllieDBusClient::interrupt(const QString &sessionId)
|
||||||
{
|
{
|
||||||
m_iface->asyncCall("Interrupt", sessionId);
|
m_iface->asyncCall("Interrupt", sessionId);
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE QStringList peerList(const QString &sessionId);
|
Q_INVOKABLE QStringList peerList(const QString &sessionId);
|
||||||
Q_INVOKABLE QVariantMap getChat(const QString &sessionId, int offset);
|
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 QVariantMap getConfig(const QString &sessionId);
|
||||||
Q_INVOKABLE QString getState(const QString &sessionId);
|
Q_INVOKABLE QString getState(const QString &sessionId);
|
||||||
QString activeSessionId() const { return m_activeSessionId; }
|
QString activeSessionId() const { return m_activeSessionId; }
|
||||||
|
|
@ -55,8 +54,6 @@ public:
|
||||||
Q_INVOKABLE bool renameSession(const QString &sessionId, const QString &newName);
|
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 setConfig(const QString &sessionId, const QString &key, const QString &value);
|
||||||
Q_INVOKABLE bool submit(const QString &sessionId, const QString &prompt);
|
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 bool interrupt(const QString &sessionId);
|
||||||
Q_INVOKABLE QStringList listBackends();
|
Q_INVOKABLE QStringList listBackends();
|
||||||
Q_INVOKABLE QStringList listModels(const QString &sessionId);
|
Q_INVOKABLE QStringList listModels(const QString &sessionId);
|
||||||
|
|
|
||||||
Reference in New Issue