Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 56 additions & 66 deletions contents/ui/CompactRepresentation.qml
Original file line number Diff line number Diff line change
@@ -1,41 +1,15 @@
/*
* SPDX-FileCopyrightText: 2024 Denys Madureira <[email protected]>
* SPDX-FileCopyrightText: 2025 Bruno Gonçalves <[email protected]>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/

import QtQuick
import QtQuick.Layouts

import org.kde.plasma.core as PlasmaCore
import org.kde.kirigami as Kirigami
import org.kde.kirigami 2.20 as Kirigami
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core 2.0 as PlasmaCore

Item {
id: compactRoot

// Icon mode constants (must match ConfigAppearance.qml ComboBox order)
readonly property int iconModeFavicon: 0
readonly property int iconModeAdaptive: 1
readonly property int iconModeDark: 2
readonly property int iconModeLight: 3
readonly property int iconModeOutlined: 4
readonly property int iconModeFilled: 5
readonly property int iconModeColorful: 6
readonly property int iconModeCustom: 7

property var models: []
property var webview: null
property var models
property var webview
property string fallbackIcon: "help-about"

readonly property bool isVertical: plasmoid.formFactor === PlasmaCore.Types.Vertical

Layout.minimumWidth: isVertical ? 0 : Kirigami.Units.iconSizes.medium
Layout.minimumHeight: isVertical ? Kirigami.Units.iconSizes.medium : 0

implicitWidth: Kirigami.Units.iconSizes.medium
implicitHeight: Kirigami.Units.iconSizes.medium

MouseArea {
id: mouseArea
anchors.fill: parent
Expand All @@ -44,74 +18,90 @@ Item {

Kirigami.Icon {
anchors.fill: parent
// Use a function that returns a URL or icon name appropriately
source: getIconSource()
source: Qt.resolvedUrl(getIcon())
}

function getIconSource() {
let icon = getIconNameOrPath();
if (icon.indexOf("/") !== -1 || icon.endsWith(".svg") || icon.endsWith(".png")) {
return Qt.resolvedUrl(icon);
// WebView connection handlers
// Monitor and respond to webview state changes
Connections {
// Parent webview connection
target: parent && parent.webviewRoot && parent.webviewRoot.webview ? parent.webviewRoot.webview : null
enabled: target ? true : false
}

// Direct webview connection for loading state changes
Connections {
target: webview
enabled: webview !== null
function onLoadingChanged(loadingInfo) {
if (loadingInfo?.status === WebEngineLoadRequest.LoadSucceededStatus)
// Handle successful load
{}
}
return icon;
}

// Helper Functions
// Determines and returns the appropriate chat model icon based on:
// - Current chat service
// - System theme (light/dark)
// - User icon style preferences
function getChatModelIcon() {
if (!models || models.length === 0) return `assets/logo-${getBackgroundColorContrast()}.svg`;

const mode = plasmoid.configuration.iconMode;
const currentModel = models.find(model => plasmoid.configuration.url.includes(model.url));
const currentModel = models.find(model => Plasmoid.configuration.url.includes(model.url));
const colorContrast = getBackgroundColorContrast();

// Colorful mode. If not in colorful mode, some models only have colorful icons available
const hasOnlyColorfulIcon = mode !== iconModeColorful && ["lobechat", "bigagi"].includes(currentModel?.id);
const hasOnlyColorfulIcon = !Plasmoid.configuration.useColorfulChatIcon && ["lobechat", "bigagi"].includes(currentModel?.id);

if (!currentModel || currentModel?.id === "blackbox" || hasOnlyColorfulIcon) {
return `assets/logo-${colorContrast}.svg`;
}

// Add custom icon mapping, For CustomModels & New Models when added
if (currentModel.useIcon) {
const style = mode === iconModeFilled ? "filled" : "outlined";
const style = Plasmoid.configuration.useFilledChatIcon ? "filled" : "outlined";
return `assets/${style}/${currentModel.useIcon}-${colorContrast}.svg`;
}

if (mode === iconModeColorful) {
if (Plasmoid.configuration.useColorfulChatIcon) {
return `assets/colorful/${currentModel.id}.svg`;
}

const style = mode === iconModeFilled ? "filled" : "outlined";
const style = Plasmoid.configuration.useFilledChatIcon ? "filled" : "outlined";
return `assets/${style}/${currentModel.id}-${colorContrast}.svg`;
}

function getIconNameOrPath() {
const mode = plasmoid.configuration.iconMode;

if (mode === iconModeCustom) {
return plasmoid.configuration.customIcon || fallbackIcon;
}

if (mode === iconModeFavicon) {
const faviconUrl = plasmoid.configuration.favIcon || plasmoid.configuration.lastFavIcon;
// Main icon selection function that determines which icon to display:
// 1. Website favicon (if enabled)
// 2. Chat model specific icon (if enabled)
// 3. Default icon based on theme
function getIcon() {
if (Plasmoid.configuration.useFavicon) {
const faviconUrl = Plasmoid.configuration.favIcon || Plasmoid.configuration.lastFavIcon;
if (faviconUrl) {
return faviconUrl.replace("image://favicon/", "");
}
}

if (mode >= iconModeOutlined) {
if (Plasmoid.configuration.useFilledChatIcon || Plasmoid.configuration.useOutlinedChatIcon || Plasmoid.configuration.useColorfulChatIcon) {
return getChatModelIcon() || fallbackIcon;
}

const contrast = getBackgroundColorContrast();
if (mode === iconModeDark) return "assets/logo-dark.svg";
if (mode === iconModeLight) return "assets/logo-light.svg";

return `assets/logo-${contrast}.svg`;
return Plasmoid.configuration.useDefaultDarkIcon ? "assets/logo-dark.svg" : Plasmoid.configuration.useDefaultLightIcon ? "assets/logo-light.svg" : `assets/logo-${contrast}.svg`;
}

// Calculates whether to use light or dark icons based on
// the system background color using luminance formula
// Returns: "dark" or "light" based on background contrast
function getBackgroundColorContrast() {
// Use Kirigami.Theme for better Plasma 6 compatibility
const color = Kirigami.Theme.backgroundColor;
const luma = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
return luma > 0.5 ? "dark" : "light";
try {
const color = Kirigami.Theme.backgroundColor;
const hex = color.toString().replace("#", "");
const r = parseInt(hex.substring(0, 2), 16);
const g = parseInt(hex.substring(2, 4), 16);
const b = parseInt(hex.substring(4, 6), 16);
const luma = 0.2126 * r + 0.7152 * g + 0.0722 * b;
return luma > 128 ? "dark" : "light";
} catch(e) {
return "dark";
}
}
}