Skip to content

Commit

Permalink
A large number of changes:
Browse files Browse the repository at this point in the history
- Started with the option to launch Plasma without starting the webview in the background, to save memory during boot.
- Added support for opening external links in the system's default browser.
- Added support for file downloads with a progress bar, the option to open the file, open the folder, choose the default folder, and notify when attempting to download the same file more than once simultaneously.
- Added the ability to print to PDF.
- Buttons for back, refresh, forward, auto-hide, downloads, pin, and close can be optionally included.
- The close button terminates the webview, again to reduce memory consumption if needed.
- Auto-hide with 2 pixels of space to hover over and make the header appear.
- The header is automatically moved to the bottom if the plasmoid is placed on the top bar of the screen.
- Moved the Custom URL option inside the dropdown and removed the button from the header.
- Added a simple way to add sites in the settings.
- Added the option to use the site's favicon as the icon.
- Enabled microphone, webcam, screen sharing, notifications, and geolocation options.
- Some sites were added to the default list.
  • Loading branch information
bigbruno committed Jan 26, 2025
1 parent 5e9be68 commit 59402ee
Show file tree
Hide file tree
Showing 9 changed files with 2,203 additions and 381 deletions.
14 changes: 8 additions & 6 deletions contents/config/config.qml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020 Sora Steenvoort <sora@dillbox.me>
* SPDX-FileCopyrightText: 2025 Bruno Gonçalves <bigbruno@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
Expand All @@ -9,14 +10,15 @@ import org.kde.plasma.configuration 2.0

ConfigModel {
ConfigCategory {
name: i18nc("@title", "General")
icon: "plasma"
source: "ConfigGeneral.qml"
name: i18nc("@title", "General")
icon: "plasma"
source: "ConfigGeneral.qml"
}

ConfigCategory {
name: i18nc("@title", "Appearance")
icon: "preferences-desktop-color"
source: "ConfigAppearance.qml"
name: i18nc("@title", "Appearance")
icon: "preferences-desktop-color"
source: "ConfigAppearance.qml"
}

}
156 changes: 146 additions & 10 deletions contents/config/main.xml
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile name=""/>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
<kcfgfile name="" />

<group name="General">
<entry name="url" type="String">
<default>https://duckduckgo.com/chat</default>
<default>https://duckduckgo.com/chat</default>
</entry>
<entry name="icon" type="String">
<label>The name of the icon used in the compact representation (e.g. on a small panel).</label>
<label>i18n("The name of the icon used in the compact representation (e.g. on a small panel).")</label>
<default></default>
</entry>
<entry name="useFilledChatIcon" type="Bool">
<label>Use the filled chat's icon instead of widget icon</label>
<label>i18n("Use the filled chat's icon instead of widget icon")</label>
<default>false</default>
</entry>
<entry name="useOutlinedChatIcon" type="Bool">
Expand All @@ -33,10 +32,22 @@
<label>Use the widget's default light icon</label>
<default>false</default>
</entry>
<entry name="useDefaultDarktIcon" type="Bool">
<entry name="useDefaultDarkIcon" type="Bool">
<label>Use the widget's default dark icon</label>
<default>false</default>
</entry>
<entry name="useFavicon" type="Bool">
<label>Use website favicon as widget icon</label>
<default>false</default>
</entry>
<entry name="favIcon" type="String">
<label>Base64 encoded favicon from website</label>
<default></default>
</entry>
<entry name="lastFavIcon" type="String">
<label>Last successfully loaded favicon URL</label>
<default></default>
</entry>
<entry name="showDuckDuckGoChat" type="Bool">
<default>true</default>
</entry>
Expand All @@ -49,6 +60,9 @@
<entry name="showGoogleGemini" type="Bool">
<default>true</default>
</entry>
<entry name="showClaude" type="Bool">
<default>false</default>
</entry>
<entry name="showYou" type="Bool">
<default>false</default>
</entry>
Expand All @@ -67,7 +81,13 @@
<entry name="showBigAGI" type="Bool">
<default>false</default>
</entry>
<entry name="showClaude" type="Bool">
<entry name="showDeepSeek" type="Bool">
<default>false</default>
</entry>
<entry name="showMetaAI" type="Bool">
<default>false</default>
</entry>
<entry name="showGrok" type="Bool">
<default>false</default>
</entry>
<entry name="hideHeader" type="Bool">
Expand All @@ -82,5 +102,121 @@
<entry name="hideCustomURL" type="Bool">
<default>false</default>
</entry>
<entry name="hidePrintButton" type="Bool">
<default>false</default>
</entry>
<entry name="hideCloseButton" type="Bool">
<default>false</default>
</entry>
<entry name="hideHomeButton" type="Bool">
<default>false</default>
</entry>
<entry name="hideNavigationButtons" type="Bool">
<default>false</default>
</entry>
<entry name="hideRefreshButton" type="Bool">
<default>false</default>
</entry>
<entry name="hideDownloadButton" type="Bool">
<default>false</default>
</entry>
<entry name="microphoneEnabled" type="Bool">
<default>true</default>
</entry>
<entry name="webcamEnabled" type="Bool">
<default>true</default>
</entry>
<entry name="screenShareEnabled" type="Bool">
<default>true</default>
</entry>
<entry name="downloadPath" type="String">
<default></default>
</entry>
<entry name="customSites" type="String">
<label>i18n("List of custom sites")</label>
<default></default>
</entry>
<entry name="keepOpen" type="Bool">
<default>false</default>
</entry>
<entry name="pin" type="Bool">
<default>false</default>
</entry>
<entry name="loadOnStartup" type="Bool">
<label>i18n("Load website on Plasma startup")</label>
<default>false</default>
</entry>
<entry name="spatialNavigationEnabled" type="Bool">
<label>Enable spatial navigation for keyboard-based browsing</label>
<default>false</default>
</entry>
<entry name="javascriptCanPaste" type="Bool">
<label>Allow JavaScript to paste from clipboard</label>
<default>true</default>
</entry>
<entry name="javascriptCanOpenWindows" type="Bool">
<label>Allow JavaScript to open new windows</label>
<default>true</default>
</entry>
<entry name="javascriptCanAccessClipboard" type="Bool">
<label>Allow JavaScript to access clipboard</label>
<default>true</default>
</entry>
<entry name="allowUnknownUrlSchemes" type="Bool">
<label>Allow unknown URL schemes</label>
<default>true</default>
</entry>
<entry name="playbackRequiresUserGesture" type="Bool">
<label>Require user gesture for media playback</label>
<default>false</default>
</entry>
<entry name="focusOnNavigationEnabled" type="Bool">
<label>Enable focus on navigation</label>
<default>true</default>
</entry>
<entry name="centerOnScreen" type="Bool">
<label>Center window on screen when opened</label>
<default>false</default>
</entry>
<entry name="dialogWidth" type="Int">
<label>Last saved dialog width</label>
<default>0</default>
</entry>
<entry name="dialogHeight" type="Int">
<label>Last saved dialog height</label>
<default>0</default>
</entry>
<entry name="notificationsEnabled" type="Bool">
<label>Allow notifications from websites</label>
<default>true</default>
</entry>
<entry name="notificationFlags" type="Int">
<label>Notification display flags</label>
<default>0</default>
</entry>
<entry name="notificationUrgency" type="Int">
<label>Notification urgency level</label>
<default>1</default>
</entry>
<entry name="notificationTimeout" type="Int">
<label>Notification timeout in milliseconds (0 for no timeout)</label>
<default>5000</default>
</entry>
<entry name="geolocationEnabled" type="Bool">
<label>Allow websites to access geolocation</label>
<default>false</default>
</entry>
<entry name="autoHideHeader" type="Bool">
<label>Auto-hide header and show on mouse hover</label>
<default>false</default>
</entry>
<entry name="cachePath" type="String">
<label>Cache directory path</label>
<default></default>
</entry>
<entry name="clearCacheOnExit" type="Bool">
<label>Clear cache when closing</label>
<default>false</default>
</entry>
</group>
</kcfg>
</kcfg>
116 changes: 77 additions & 39 deletions contents/ui/CompactRepresentation.qml
Original file line number Diff line number Diff line change
@@ -1,67 +1,105 @@
import QtQuick
import QtQuick.Layouts 1.1
import org.kde.kirigami 2.20 as Kirigami
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core 2.0 as PlasmaCore

Loader {
property var models;
Item {
id: compactRoot

property var models
property var webview
property string fallbackIcon: "help-about"

TapHandler {
property bool wasExpanded: false

acceptedButtons: Qt.LeftButton

onPressedChanged: if (pressed) {
wasExpanded = root.expanded;
}
onTapped: root.expanded = !wasExpanded
MouseArea {
id: mouseArea
anchors.fill: parent
onClicked: root.expanded = !root.expanded
}

Kirigami.Icon {
anchors.fill: parent
source: Qt.resolvedUrl(getIcon())
}

// 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
}
}
}

// 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() {
const currentModel = models.find(model => Plasmoid.configuration.url.includes(model.url));
const colorContrast = getBackgroundColorContrast();
const isNotColorfulAndIsOneOfChatModelsThatHaveOnlyColorfulIcons = !Plasmoid.configuration.useColorfulChatIcon && ["lobechat", "bigagi"].includes(currentModel?.id);
const currentModel = models.find(model => Plasmoid.configuration.url.includes(model.url))
const colorContrast = getBackgroundColorContrast()
const hasOnlyColorfulIcon = !Plasmoid.configuration.useColorfulChatIcon &&
["lobechat", "bigagi"].includes(currentModel?.id)

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

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

const filledOrOutlined = Plasmoid.configuration.useFilledChatIcon ? "filled" : "outlined";

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

// 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.useFilledChatIcon || Plasmoid.configuration.useOutlinedChatIcon || Plasmoid.configuration.useColorfulChatIcon) {
return getChatModelIcon();
} else if (Plasmoid.configuration.useDefaultDarkIcon) {
return "assets/logo-dark.svg";
} else if (Plasmoid.configuration.useDefaultLightIcon) {
return "assets/logo-light.svg";
} else {
const colorContrast = getBackgroundColorContrast();

return `assets/logo-${colorContrast}.svg`;
if (Plasmoid.configuration.useFavicon) {
const faviconUrl = Plasmoid.configuration.favIcon || Plasmoid.configuration.lastFavIcon
if (faviconUrl) {
return faviconUrl.replace("image://favicon/", "")
}
}

if (Plasmoid.configuration.useFilledChatIcon ||
Plasmoid.configuration.useOutlinedChatIcon ||
Plasmoid.configuration.useColorfulChatIcon) {
return getChatModelIcon() || fallbackIcon
}

const contrast = getBackgroundColorContrast()
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() {
const hex = `${PlasmaCore.Theme.backgroundColor}`.substring(1);
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";
const hex = `${PlasmaCore.Theme.backgroundColor}`.substring(1)
const [r, g, b] = [
parseInt(hex.substring(0, 2), 16),
parseInt(hex.substring(2, 4), 16),
parseInt(hex.substring(4, 6), 16)
]
const luma = 0.2126 * r + 0.7152 * g + 0.0722 * b
return luma > 128 ? "dark" : "light"
}
}
}
Loading

0 comments on commit 59402ee

Please sign in to comment.