mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-21 09:05:10 -07:00
[Chat] Render game link buttons (#7135)
* [Chat] Render cockatrice://joingame links in chat as clickable buttons Words starting with cockatrice:// become button-style anchors labelled with the game description, id and server (falling back to id + server for links built without a description). The description is spliced via the multi-arg arg() overloads so a title containing "%…" cannot corrupt the label. Keyboard link access is enabled so the anchors are reachable without a mouse. * [Chat] Fix percent-encoding and scheme gating in game-link chat labels Game descriptions containing '%' were rendered as '%25' in the chat button label because QUrlQuery's default decode leaves %25 untouched. Use QUrl::FullyDecoded for the description item, and restrict the invite-button treatment to cockatrice://joingame links; any other cockatrice:// scheme now falls through to plain text. --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
f466a25893
commit
fe53f9c3eb
2 changed files with 55 additions and 1 deletions
|
|
@ -14,6 +14,8 @@
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QUrlQuery>
|
||||||
#include <libcockatrice/card/database/card_database_manager.h>
|
#include <libcockatrice/card/database/card_database_manager.h>
|
||||||
#include <libcockatrice/network/server/remote/user_level.h>
|
#include <libcockatrice/network/server/remote/user_level.h>
|
||||||
#include <libcockatrice/settings/chat_settings.h>
|
#include <libcockatrice/settings/chat_settings.h>
|
||||||
|
|
@ -49,7 +51,7 @@ ChatView::ChatView(TabSupervisor *_tabSupervisor, AbstractGame *_game, bool _sho
|
||||||
|
|
||||||
viewport()->setCursor(Qt::IBeamCursor);
|
viewport()->setCursor(Qt::IBeamCursor);
|
||||||
setReadOnly(true);
|
setReadOnly(true);
|
||||||
setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse);
|
setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard);
|
||||||
setOpenLinks(false);
|
setOpenLinks(false);
|
||||||
connect(this, &ChatView::anchorClicked, this, &ChatView::openLink);
|
connect(this, &ChatView::anchorClicked, this, &ChatView::openLink);
|
||||||
|
|
||||||
|
|
@ -219,6 +221,46 @@ void ChatView::appendUrlTag(QTextCursor &cursor, QString url)
|
||||||
cursor.setCharFormat(oldFormat);
|
cursor.setCharFormat(oldFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChatView::appendGameLinkTag(QTextCursor &cursor, const QString &url)
|
||||||
|
{
|
||||||
|
const QUrl gameUrl(url);
|
||||||
|
const QUrlQuery query(gameUrl);
|
||||||
|
const QString hostname = query.queryItemValue("hostname");
|
||||||
|
// FullyDecoded undoes every %XX escape, so a description that itself
|
||||||
|
// contains "%" cannot end up displayed as "%25" in the label.
|
||||||
|
const QString description = query.queryItemValue("game", QUrl::FullyDecoded);
|
||||||
|
const int gameId = query.queryItemValue("gameid").toInt();
|
||||||
|
|
||||||
|
QString label;
|
||||||
|
if (gameId > 0 && !hostname.isEmpty()) {
|
||||||
|
// Links built before the description was embedded stay readable: the
|
||||||
|
// id + server fallback below is identical to the old anchor text.
|
||||||
|
if (!description.isEmpty()) {
|
||||||
|
// Multi-arg .arg() replaces all placeholders in a single pass, so a
|
||||||
|
// description containing "%…" cannot corrupt later placeholders.
|
||||||
|
label = tr("Join game \"%1\" (#%2) on %3").arg(description, QString::number(gameId), hostname);
|
||||||
|
} else {
|
||||||
|
label = tr("Join game #%1 on %2").arg(QString::number(gameId), hostname);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
label = tr("Join game");
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextCharFormat oldFormat = cursor.charFormat();
|
||||||
|
QTextCharFormat gameLinkFormat = oldFormat;
|
||||||
|
gameLinkFormat.setForeground(linkColor);
|
||||||
|
gameLinkFormat.setFontWeight(QFont::Bold);
|
||||||
|
gameLinkFormat.setAnchor(true);
|
||||||
|
gameLinkFormat.setAnchorHref(url);
|
||||||
|
QColor background = palette().highlight().color();
|
||||||
|
background.setAlpha(40);
|
||||||
|
gameLinkFormat.setBackground(background);
|
||||||
|
|
||||||
|
cursor.setCharFormat(gameLinkFormat);
|
||||||
|
cursor.insertText(label);
|
||||||
|
cursor.setCharFormat(oldFormat);
|
||||||
|
}
|
||||||
|
|
||||||
void ChatView::appendMessage(QString message,
|
void ChatView::appendMessage(QString message,
|
||||||
RoomMessageTypeFlags messageType,
|
RoomMessageTypeFlags messageType,
|
||||||
const ServerInfo_User &userInfo,
|
const ServerInfo_User &userInfo,
|
||||||
|
|
@ -503,6 +545,17 @@ void ChatView::checkWord(QTextCursor &cursor, QString &message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fullWordUpToSpaceOrEnd.startsWith("cockatrice://", Qt::CaseInsensitive)) {
|
||||||
|
// Only links to a game (cockatrice://joingame) become invite buttons;
|
||||||
|
// any other cockatrice:// scheme falls through to plain text below.
|
||||||
|
const QUrl gameLink(fullWordUpToSpaceOrEnd);
|
||||||
|
if (gameLink.host().compare("joingame", Qt::CaseInsensitive) == 0) {
|
||||||
|
appendGameLinkTag(cursor, fullWordUpToSpaceOrEnd);
|
||||||
|
cursor.insertText(rest, defaultFormat);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// check word mentions
|
// check word mentions
|
||||||
for (const QString &word : highlightedWords) {
|
for (const QString &word : highlightedWords) {
|
||||||
if (fullWordUpToSpaceOrEnd.compare(word, Qt::CaseInsensitive) == 0) {
|
if (fullWordUpToSpaceOrEnd.compare(word, Qt::CaseInsensitive) == 0) {
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ private:
|
||||||
void scrollToBottom();
|
void scrollToBottom();
|
||||||
void appendCardTag(QTextCursor &cursor, const QString &cardName);
|
void appendCardTag(QTextCursor &cursor, const QString &cardName);
|
||||||
void appendUrlTag(QTextCursor &cursor, QString url);
|
void appendUrlTag(QTextCursor &cursor, QString url);
|
||||||
|
void appendGameLinkTag(QTextCursor &cursor, const QString &url);
|
||||||
static QColor getCustomMentionColor();
|
static QColor getCustomMentionColor();
|
||||||
static QColor getCustomHighlightColor();
|
static QColor getCustomHighlightColor();
|
||||||
void showSystemPopup(const QString &userName);
|
void showSystemPopup(const QString &userName);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue