Compare commits

..

No commits in common. "a571a9aa04796915db172e2e60280ecbd5ec8926" and "e2eb36f19fb26c45f437e86831383897b1dd78b5" have entirely different histories.

8 changed files with 53 additions and 86 deletions

View file

@ -161,11 +161,14 @@ jobs:
uses: actions/checkout@v7
- name: "Restore compiler cache (ccache)"
id: restore_ccache
id: ccache_restore
uses: actions/cache/restore@v6
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
with:
key: ccache-${{ matrix.distro }}${{ matrix.version }}
key: ccache-${{ matrix.distro }}${{ matrix.version }}-${{ env.BRANCH_NAME }}
path: ${{ env.CACHE }}
restore-keys: ccache-${{ matrix.distro }}${{ matrix.version }}-
- name: "Build ${{ matrix.distro }} ${{ matrix.version }} Docker image"
shell: bash
@ -200,10 +203,10 @@ jobs:
# Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342
- name: "Delete remote compiler cache (ccache)"
if: github.ref == 'refs/heads/master' && steps.restore_ccache.outputs.cache-hit
if: github.ref == 'refs/heads/master' && steps.ccache_restore.outputs.cache-hit
continue-on-error: true
env:
CACHE_PRIMARY_KEY: ${{ steps.restore_ccache.outputs.cache-primary-key }}
CACHE_PRIMARY_KEY: ${{ steps.ccache_restore.outputs.cache-primary-key }}
GH_TOKEN: ${{ github.token }}
run: |
if gh cache delete --repo "$GITHUB_REPOSITORY" "$CACHE_PRIMARY_KEY"; then
@ -214,7 +217,7 @@ jobs:
if: github.ref == 'refs/heads/master'
uses: actions/cache/save@v6
with:
key: ${{ steps.restore_ccache.outputs.cache-primary-key }}
key: ${{ steps.ccache_restore.outputs.cache-primary-key }}
path: ${{ env.CACHE }}
- name: "Upload artifact"
@ -261,14 +264,13 @@ jobs:
- os: macOS
target: 13 # EOL 2025-09-15
runner: macos-15-intel # https://github.com/actions/runner-images/blob/main/images/macos/macos-15-Readme.md
# macos-26-intel is very slow and fails in CPack during DMG config if not increasing Finder timeout
ccache_eviction_age: 7d
cmake_generator: Ninja
make_package: 1
override_target: 13
package_suffix: "-macOS13_Intel"
qt_version: 6.11.1
qt_version: 6.11.0
qt_modules: qtimageformats qtmultimedia qtwebsockets
soc: Intel
type: Release
@ -277,48 +279,47 @@ jobs:
- os: macOS
target: 14 # EOL 2026-??
runner: macos-26 # https://github.com/actions/runner-images/blob/main/images/macos/macos-26-arm64-Readme.md
runner: macos-15 # https://github.com/actions/runner-images/blob/main/images/macos/macos-15-arm64-Readme.md
ccache_eviction_age: 7d
cmake_generator: Ninja
make_package: 1
override_target: 14
package_suffix: "-macOS14"
qt_version: 6.11.1
qt_version: 6.11.0
qt_modules: qtimageformats qtmultimedia qtwebsockets
soc: Apple
type: Release
use_ccache: 1
xcode: "26.6"
xcode: "26.3"
- os: macOS
target: 15
runner: macos-26 # https://github.com/actions/runner-images/blob/main/images/macos/macos-26-arm64-Readme.md
runner: macos-15 # https://github.com/actions/runner-images/blob/main/images/macos/macos-15-arm64-Readme.md
ccache_eviction_age: 7d
cmake_generator: Ninja
make_package: 1
override_target: 15
package_suffix: "-macOS15"
qt_version: 6.11.1
qt_version: 6.11.0
qt_modules: qtimageformats qtmultimedia qtwebsockets
soc: Apple
type: Release
use_ccache: 1
xcode: "26.6"
xcode: "26.3"
- os: macOS
target: 26
runner: macos-26 # https://github.com/actions/runner-images/blob/main/images/macos/macos-26-arm64-Readme.md
target: 15
runner: macos-15 # https://github.com/actions/runner-images/blob/main/images/macos/macos-15-arm64-Readme.md
ccache_eviction_age: 7d
cmake_generator: Ninja
qt_version: 6.11.1
qt_version: 6.11.0
qt_modules: qtimageformats qtmultimedia qtwebsockets
soc: Apple
type: Debug
use_ccache: 1
xcode: "26.6"
xcode: "26.3"
- os: Windows
target: 10
@ -328,7 +329,7 @@ jobs:
cmake_generator_platform: x64
make_package: 1
package_suffix: "-Win10"
qt_version: 6.11.1
qt_version: 6.11.0
qt_modules: qtimageformats qtmultimedia qtwebsockets
type: Release
@ -348,6 +349,7 @@ jobs:
- name: "[Windows] Add msbuild to PATH"
if: matrix.os == 'Windows'
id: add-msbuild
uses: microsoft/setup-msbuild@v3
with:
msbuild-architecture: x64
@ -358,11 +360,14 @@ jobs:
- name: "[macOS] Restore compiler cache (ccache)"
if: matrix.os == 'macOS' && matrix.use_ccache == 1
id: restore_ccache
id: ccache_restore
uses: actions/cache/restore@v6
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
with:
key: ccache-${{ matrix.runner }}_${{ matrix.override_target }}-Xcode${{ matrix.xcode }}
key: ccache-${{ matrix.runner }}-${{ matrix.soc }}-${{ matrix.type }}-${{ env.BRANCH_NAME }}
path: ${{ env.CCACHE_DIR }}
restore-keys: ccache-${{ matrix.runner }}-${{ matrix.soc }}-${{ matrix.type }}-
- name: "Install aqtinstall"
run: pipx install aqtinstall
@ -380,7 +385,7 @@ jobs:
id: restore_qt
uses: actions/cache/restore@v6
with:
key: Qt-${{ steps.resolve_qt_version.outputs.version }}-macOS-${{ matrix.soc }}-${{ matrix.qt_modules }}-thin
key: thin-qt-macos-${{ matrix.soc }}-${{ steps.resolve_qt_version.outputs.version }}
path: ${{ github.workspace }}/Qt
# Using jurplel/install-qt-action to install Qt without using brew
@ -402,7 +407,7 @@ jobs:
if: matrix.os == 'macOS' && steps.restore_qt.outputs.cache-hit != 'true'
uses: actions/cache/save@v6
with:
key: ${{ steps.restore_qt.outputs.cache-primary-key }}
key: thin-qt-macos-${{ matrix.soc }}-${{ steps.resolve_qt_version.outputs.version }}
path: ${{ github.workspace }}/Qt
- name: "[Windows] Install Qt ${{ matrix.qt_version }}"
@ -412,7 +417,6 @@ jobs:
# Qt 6.11.0 only works with aqtinstall directly from git until aqtinstall 3.4 is released
aqtsource: git+https://github.com/miurahr/aqtinstall.git
cache: true
cache-key-prefix: Qt
modules: ${{ matrix.qt_modules }}
version: ${{ steps.resolve_qt_version.outputs.version }}
@ -453,21 +457,21 @@ jobs:
# Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342
- name: "[macOS] Delete remote compiler cache (ccache)"
if: matrix.os == 'macOS' && matrix.use_ccache == 1 && github.ref == 'refs/heads/master' && steps.restore_ccache.outputs.cache-hit
if: matrix.os == 'macOS' && matrix.use_ccache == 1 && github.ref == 'refs/heads/master' && steps.ccache_restore.outputs.cache-hit
continue-on-error: true
env:
CACHE_PRIMARY_KEY: ${{ steps.restore_ccache.outputs.cache-primary-key }}
CACHE_PRIMARY_KEY: ${{ steps.ccache_restore.outputs.cache-primary-key }}
GH_TOKEN: ${{ github.token }}
run: |
if gh cache delete --repo "$GITHUB_REPOSITORY" "$CACHE_PRIMARY_KEY"; then
echo "Cache deleted successfully"
fi
- name: "[macOS] Cache updated compiler cache (ccache)"
- name: "[macOS] Save updated compiler cache (ccache)"
if: matrix.os == 'macOS' && matrix.use_ccache == 1 && github.ref == 'refs/heads/master'
uses: actions/cache/save@v6
with:
key: ${{ steps.restore_ccache.outputs.cache-primary-key }}
key: ${{ steps.ccache_restore.outputs.cache-primary-key }}
path: ${{ env.CCACHE_DIR }}
- name: "[macOS] Sign app bundle"

View file

@ -52,7 +52,8 @@
id="defs8">
<polygon
id="s"
points="-0.587785,0.809017 0,-1 0.587785,0.809017 -0.951057,-0.309017 0.951057,-0.309017 "
points="-301930,415571 0,-513674 301930,415571 -488533,-158734 488533,-158734 "
transform="scale(1.94676e-6,1.94676e-6)"
style="fill:#ffde00" />
<clipPath
clipPathUnits="userSpaceOnUse"

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Before After
Before After

View file

@ -16,6 +16,6 @@
<rect id="rect10" height="2.88" width="12.8" y="4.278e-9" x="0"/>
<rect id="rect12" height="2.88" width="12.8" y="3.36" x="0" fill="#da121a"/>
<polygon id="polygon14" points="0 0 8.6603 5 0 10" fill="#0f47af" transform="scale(.96)"/>
<polygon id="polygon16" points="4.01394 3.897169 1.23532 4.8 4.01394 5.702831 2.296666 3.3392 2.296666 6.2608" fill="#fcdd09"/>
<polygon id="polygon16" points="4.1557e5 -3.0193e5 -5.1367e5 0 4.1557e5 3.0193e5 -1.5873e5 -4.8853e5 -1.5873e5 4.8853e5" fill="#fcdd09" transform="matrix(.0000029902 0 0 .0000029902 2.7713 4.8)"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Before After
Before After

View file

@ -14,32 +14,6 @@
#define DEFAULT_COLOR_MODERATOR_RIGHT "#000000";
#define DEFAULT_COLOR_ADMIN "#ff2701";
/**
* Clamps an svg render size so that rendering does not exceed a multiple of the requested size.
*
* Rendering at the full native size of an svg just to scale it down afterwards wastes memory,
* and canvases with extreme coordinates can exceed Qt's rasterizer coordinate limit which makes
* Qt silently drop shapes from the rendered image.
*
* @param renderSize The size the svg would be rendered at.
* @param requestedSize The size that was actually requested.
*
* @return A size with the aspect ratio of renderSize whose longest side is at most four times
* the longest side of requestedSize.
*/
static QSize capRenderSize(const QSize &renderSize, const QSize &requestedSize)
{
const int longestRequestedSide = qMax(requestedSize.width(), requestedSize.height());
if (longestRequestedSide <= 0) {
return renderSize;
}
const int longestRenderSide = qMax(renderSize.width(), renderSize.height());
const qreal scale = qMin<qreal>(1.0, static_cast<qreal>(longestRequestedSide * 4) / longestRenderSide);
return QSize(qMax(1, static_cast<int>(renderSize.width() * scale)),
qMax(1, static_cast<int>(renderSize.height() * scale)));
}
/**
* Loads in an svg from file and scales it without affecting image quality.
*
@ -61,9 +35,6 @@ static QPixmap loadSvg(const QString &svgPath, const QSize &size, bool expandOnl
// If expandOnly, make sure the pixmap is at least as large as the svg, so that we don't lose any detail.
// QIcon.pixmap(size) will automatically scale down the image, but it won't scale it up.
QSize pixmapSize = expandOnly ? svgRenderer.defaultSize().expandedTo(size) : size;
if (expandOnly) {
pixmapSize = capRenderSize(pixmapSize, size);
}
QPixmap pix(pixmapSize);
pix.fill(Qt::transparent);
@ -276,9 +247,7 @@ static QIcon loadAndColorSvg(const QString &iconPath,
QSvgRenderer svgRenderer(doc.toByteArray());
const QSize pixmapSize =
capRenderSize(svgRenderer.defaultSize().expandedTo(QSize(minSize, minSize)), QSize(minSize, minSize));
QPixmap pix(pixmapSize);
QPixmap pix(svgRenderer.defaultSize().expandedTo(QSize(minSize, minSize)));
pix.fill(Qt::transparent);
QPainter pixPainter(&pix);

View file

@ -39,10 +39,7 @@ void UserCardArtProvider::requestCardArt(const QString &userName, const QString
const QString key = makeKey(userName, cardName, providerId);
if (pending.contains(key)) {
return;
}
if (cardArtCache.contains(key) && !cardArtCache.value(key).isNull()) {
if (cardArtCache.contains(key) || pending.contains(key)) {
return;
}
@ -66,10 +63,6 @@ QPixmap UserCardArtProvider::cropCardArt(const QPixmap &fullRes)
void UserCardArtProvider::insertIntoCache(const QString &key, const QPixmap &pixmap)
{
if (pixmap.isNull()) {
return;
}
if (!cardArtCache.contains(key)) {
cacheInsertionOrder.append(key);
while (cacheInsertionOrder.size() > MaxCacheEntries) {
@ -136,6 +129,8 @@ void UserCardArtProvider::processQueue()
if (!fullRes.isNull()) {
self->insertIntoCache(key, self->cropCardArt(fullRes));
} else {
self->insertIntoCache(key, QPixmap());
}
self->pending.remove(key);

View file

@ -26,7 +26,7 @@ public slots:
private:
bool dbReady = false;
static constexpr int MaxCacheEntries = 1024;
static constexpr int MaxCacheEntries = 300;
QList<QString> cacheInsertionOrder; // FIFO eviction
QMap<QString, QPixmap> cardArtCache;
QSet<QString> pending;

View file

@ -101,21 +101,23 @@ void UserListPainter::drawBackground(QPainter *painter,
bg.setColorAt(0, blend(style.cardStart, accentColor, selected ? 0.75 : 0.65));
bg.setColorAt(1, blend(style.cardEnd, accentColor, selected ? 0.18 : 0.10));
} else {
// Regular users keep a scaled-down accent tint so the banner card art
// stays legible over a colored backdrop (the pre-branch painter was
// always dark-styled) while the role hierarchy still reads.
bg.setColorAt(0, blend(style.cardStart, accentColor, (selected ? 0.75 : 0.65) * 0.7));
bg.setColorAt(1, blend(style.cardEnd, accentColor, (selected ? 0.18 : 0.10) * 0.7));
// Regular users are the light theme's neutral paper cards. A flat
// warm card fill (the normal row surface, slightly deepened) keeps
// every row clearly visible without borrowing a role color. Selection
// shifts the fill toward a soft slate so the highlight still reads.
const QColor paper = style.cardEnd.darker(108);
bg.setColorAt(0, blend(paper, accentColor, selected ? 0.35 : 0.0));
bg.setColorAt(1, blend(paper, accentColor, selected ? 0.25 : 0.0));
}
painter->setPen(Qt::NoPen);
painter->setBrush(bg);
painter->drawRoundedRect(cardRect, 6, 6);
// The 3px accent bar anchors every row so the banner card art reads as a
// consistent strip in either scheme (pre-branch parity).
painter->setBrush(accentColor);
painter->drawRoundedRect(QRectF(cardRect.left(), cardRect.top(), 3, cardRect.height()), 2, 2);
if (style.dark || hasRole || selected) {
painter->setBrush(accentColor);
painter->drawRoundedRect(QRectF(cardRect.left(), cardRect.top(), 3, cardRect.height()), 2, 2);
}
}
static QString makeKey(const QString &user, const QString &card, const QString &providerId)

View file

@ -1372,13 +1372,9 @@ void UserListWidget::updateCardArtParams(const ServerInfo_User &user, const QStr
params.zoom = cap.zoom();
cardArtParamsMap.insert(userName, params);
cardArtProvider->requestCardArt(userName, params.cardName, params.cardProviderId);
} else {
cardArtParamsMap.remove(userName); // clear stale params on removal
}
// Intentionally no removal branch: buddy/ignore list copies never carry
// card_art_params (the server omits the column), so a params-less copy here
// means "this snapshot doesn't include it", not "the banner was removed".
// Removing on such copies would wipe banners that the live online list set.
// The map is rebuilt from scratch (clear() + repopulate) on every rebuild,
// which is what actually drops stale entries.
}
void UserListWidget::processUserInfo(const ServerInfo_User &user, bool online)