forked from Shinonome/dots-hyprland
improve icon guessing
This commit is contained in:
@@ -2,7 +2,6 @@ import "root:/"
|
|||||||
import "root:/services/"
|
import "root:/services/"
|
||||||
import "root:/modules/common"
|
import "root:/modules/common"
|
||||||
import "root:/modules/common/widgets"
|
import "root:/modules/common/widgets"
|
||||||
import "root:/modules/common/functions/icons.js" as Icons
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
@@ -178,7 +177,7 @@ Item {
|
|||||||
return winArea > maxArea ? win : maxWin
|
return winArea > maxArea ? win : maxWin
|
||||||
}, null)
|
}, null)
|
||||||
}
|
}
|
||||||
property var mainAppIconSource: Quickshell.iconPath(Icons.noKnowledgeIconGuess(biggestWindow?.class), "image-missing")
|
property var mainAppIconSource: Quickshell.iconPath(AppSearch.guessIcon(biggestWindow?.class), "image-missing")
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
opacity: (ConfigOptions.bar.workspaces.alwaysShowNumbers || GlobalStates.workspaceShowNumbers || !workspaceButtonBackground.biggestWindow) ? 1 : 0
|
opacity: (ConfigOptions.bar.workspaces.alwaysShowNumbers || GlobalStates.workspaceShowNumbers || !workspaceButtonBackground.biggestWindow) ? 1 : 0
|
||||||
|
|||||||
@@ -1,92 +0,0 @@
|
|||||||
.pragma library
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {{[key: string]: string}}
|
|
||||||
*/
|
|
||||||
const substitutions = {
|
|
||||||
"code-url-handler": "visual-studio-code",
|
|
||||||
"Code": "visual-studio-code",
|
|
||||||
"GitHub Desktop": "github-desktop",
|
|
||||||
"Minecraft* 1.20.1": "minecraft",
|
|
||||||
"gnome-tweaks": "org.gnome.tweaks",
|
|
||||||
"pavucontrol-qt": "pavucontrol",
|
|
||||||
"wps": "wps-office2019-kprometheus",
|
|
||||||
"wpsoffice": "wps-office2019-kprometheus",
|
|
||||||
"footclient": "foot",
|
|
||||||
"zen": "zen-browser",
|
|
||||||
"": "image-missing"
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {{[key: string]: string}}
|
|
||||||
*/
|
|
||||||
const regexSubstitutions = [
|
|
||||||
{
|
|
||||||
"regex": "/^steam_app_(\\d+)$/",
|
|
||||||
"replace": "steam_icon_$1"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param { string } iconName
|
|
||||||
* @returns { boolean }
|
|
||||||
*/
|
|
||||||
function iconExists(iconName) {
|
|
||||||
return false; // TODO: Make this work without Gtk
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param { string } str
|
|
||||||
* @returns { string }
|
|
||||||
*/
|
|
||||||
function substitute(str) {
|
|
||||||
// Normal substitutions
|
|
||||||
if (substitutions[str])
|
|
||||||
return substitutions[str];
|
|
||||||
|
|
||||||
// Regex substitutions
|
|
||||||
for (let i = 0; i < regexSubstitutions.length; i++) {
|
|
||||||
const substitution = regexSubstitutions[i];
|
|
||||||
const replacedName = str.replace(
|
|
||||||
substitution.regex,
|
|
||||||
substitution.replace,
|
|
||||||
);
|
|
||||||
if (replacedName != str) return replacedName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Guess: convert to kebab case
|
|
||||||
if (!iconExists(str)) str = str.toLowerCase().replace(/\s+/g, "-");
|
|
||||||
|
|
||||||
// Original string
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param { string | undefined } str
|
|
||||||
* @returns { string }
|
|
||||||
*/
|
|
||||||
function noKnowledgeIconGuess(str) {
|
|
||||||
if (!str) return "image-missing";
|
|
||||||
|
|
||||||
// Normal substitutions
|
|
||||||
if (substitutions[str])
|
|
||||||
return substitutions[str];
|
|
||||||
|
|
||||||
// Regex substitutions
|
|
||||||
for (let i = 0; i < regexSubstitutions.length; i++) {
|
|
||||||
const substitution = regexSubstitutions[i];
|
|
||||||
const replacedName = str.replace(
|
|
||||||
substitution.regex,
|
|
||||||
substitution.replace,
|
|
||||||
);
|
|
||||||
if (replacedName != str) return replacedName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Guess: convert to kebab case if it's not reverse domain name notation
|
|
||||||
if (!str.includes('.')) {
|
|
||||||
str = str.toLowerCase().replace(/\s+/g, "-");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Original string
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
@@ -42,19 +42,6 @@ function findSuitableMaterialSymbol(summary = "") {
|
|||||||
return defaultType;
|
return defaultType;
|
||||||
}
|
}
|
||||||
|
|
||||||
// const getFriendlyNotifTimeString = (timeObject) => {
|
|
||||||
// const messageTime = GLib.DateTime.new_from_unix_local(timeObject);
|
|
||||||
// const oneMinuteAgo = GLib.DateTime.new_now_local().add_seconds(-60);
|
|
||||||
// if (messageTime.compare(oneMinuteAgo) > 0)
|
|
||||||
// return getString('Now');
|
|
||||||
// else if (messageTime.get_day_of_year() == GLib.DateTime.new_now_local().get_day_of_year())
|
|
||||||
// return messageTime.format(userOptions.time.format);
|
|
||||||
// else if (messageTime.get_day_of_year() == GLib.DateTime.new_now_local().get_day_of_year() - 1)
|
|
||||||
// return getString('Yesterday');
|
|
||||||
// else
|
|
||||||
// return messageTime.format(userOptions.time.dateFormat);
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param { number | string | Date } timestamp
|
* @param { number | string | Date } timestamp
|
||||||
* @returns { string }
|
* @returns { string }
|
||||||
@@ -63,13 +50,28 @@ const getFriendlyNotifTimeString = (timestamp) => {
|
|||||||
if (!timestamp) return '';
|
if (!timestamp) return '';
|
||||||
const messageTime = new Date(timestamp);
|
const messageTime = new Date(timestamp);
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const oneMinuteAgo = new Date(now.getTime() - 60000);
|
const diffMs = now.getTime() - messageTime.getTime();
|
||||||
|
|
||||||
if (messageTime > oneMinuteAgo)
|
// Less than 1 minute
|
||||||
|
if (diffMs < 60000)
|
||||||
return 'Now';
|
return 'Now';
|
||||||
if (messageTime.toDateString() === now.toDateString())
|
|
||||||
return Qt.formatDateTime(messageTime, "hh:mm");
|
// Same day - show relative time
|
||||||
|
if (messageTime.toDateString() === now.toDateString()) {
|
||||||
|
const diffMinutes = Math.floor(diffMs / 60000);
|
||||||
|
const diffHours = Math.floor(diffMs / 3600000);
|
||||||
|
|
||||||
|
if (diffHours > 0) {
|
||||||
|
return `${diffHours}h`;
|
||||||
|
} else {
|
||||||
|
return `${diffMinutes}m`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Yesterday
|
||||||
if (messageTime.toDateString() === new Date(now.getTime() - 86400000).toDateString())
|
if (messageTime.toDateString() === new Date(now.getTime() - 86400000).toDateString())
|
||||||
return 'Yesterday';
|
return 'Yesterday';
|
||||||
|
|
||||||
|
// Older dates
|
||||||
return Qt.formatDateTime(messageTime, "MMMM dd");
|
return Qt.formatDateTime(messageTime, "MMMM dd");
|
||||||
};
|
};
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import "root:/services/"
|
import "root:/services/"
|
||||||
import "root:/modules/common"
|
import "root:/modules/common"
|
||||||
import "root:/modules/common/widgets"
|
import "root:/modules/common/widgets"
|
||||||
import "root:/modules/common/functions/icons.js" as Icons
|
|
||||||
import "root:/modules/common/functions/color_utils.js" as ColorUtils
|
import "root:/modules/common/functions/color_utils.js" as ColorUtils
|
||||||
import Qt5Compat.GraphicalEffects
|
import Qt5Compat.GraphicalEffects
|
||||||
import QtQuick
|
import QtQuick
|
||||||
@@ -33,7 +32,7 @@ Rectangle { // Window
|
|||||||
property var iconToWindowRatio: 0.35
|
property var iconToWindowRatio: 0.35
|
||||||
property var xwaylandIndicatorToIconRatio: 0.35
|
property var xwaylandIndicatorToIconRatio: 0.35
|
||||||
property var iconToWindowRatioCompact: 0.6
|
property var iconToWindowRatioCompact: 0.6
|
||||||
property var iconPath: Quickshell.iconPath(Icons.noKnowledgeIconGuess(windowData?.class), "image-missing")
|
property var iconPath: Quickshell.iconPath(AppSearch.guessIcon(windowData?.class), "image-missing")
|
||||||
property bool compactMode: Appearance.font.pixelSize.smaller * 4 > targetWindowHeight || Appearance.font.pixelSize.smaller * 4 > targetWindowWidth
|
property bool compactMode: Appearance.font.pixelSize.smaller * 4 > targetWindowHeight || Appearance.font.pixelSize.smaller * 4 > targetWindowWidth
|
||||||
|
|
||||||
x: initX
|
x: initX
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import "root:/modules/common"
|
import "root:/modules/common"
|
||||||
import "root:/modules/common/widgets"
|
import "root:/modules/common/widgets"
|
||||||
import "root:/services"
|
import "root:/services"
|
||||||
import "root:/modules/common/functions/icons.js" as Icons
|
|
||||||
import Qt5Compat.GraphicalEffects
|
import Qt5Compat.GraphicalEffects
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
@@ -48,7 +47,7 @@ Item {
|
|||||||
sourceSize.width: size
|
sourceSize.width: size
|
||||||
sourceSize.height: size
|
sourceSize.height: size
|
||||||
source: {
|
source: {
|
||||||
const icon = Icons.noKnowledgeIconGuess(root.node.properties["application.icon-name"]);
|
const icon = AppSearch.guessIcon(root.node.properties["application.icon-name"]);
|
||||||
return Quickshell.iconPath(icon, "image-missing");
|
return Quickshell.iconPath(icon, "image-missing");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,32 @@ import Quickshell
|
|||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Eases searching for applications by name.
|
* - Eases fuzzy searching for applications by name
|
||||||
|
* - Guesses icon name for window class name with normalization, possibly with desktop entry searching later
|
||||||
*/
|
*/
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
property bool sloppySearch: ConfigOptions?.search.sloppy ?? false
|
property bool sloppySearch: ConfigOptions?.search.sloppy ?? false
|
||||||
property real scoreThreshold: 0.2
|
property real scoreThreshold: 0.2
|
||||||
|
property var substitutions: ({
|
||||||
|
"code-url-handler": "visual-studio-code",
|
||||||
|
"Code": "visual-studio-code",
|
||||||
|
"GitHub Desktop": "github-desktop",
|
||||||
|
"Minecraft* 1.20.1": "minecraft",
|
||||||
|
"gnome-tweaks": "org.gnome.tweaks",
|
||||||
|
"pavucontrol-qt": "pavucontrol",
|
||||||
|
"wps": "wps-office2019-kprometheus",
|
||||||
|
"wpsoffice": "wps-office2019-kprometheus",
|
||||||
|
"footclient": "foot",
|
||||||
|
"zen": "zen-browser",
|
||||||
|
"": "image-missing"
|
||||||
|
})
|
||||||
|
property var regexSubstitutions: [
|
||||||
|
{
|
||||||
|
"regex": "/^steam_app_(\\d+)$/",
|
||||||
|
"replace": "steam_icon_$1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
readonly property list<DesktopEntry> list: Array.from(DesktopEntries.applications.values)
|
readonly property list<DesktopEntry> list: Array.from(DesktopEntries.applications.values)
|
||||||
.sort((a, b) => a.name.localeCompare(b.name))
|
.sort((a, b) => a.name.localeCompare(b.name))
|
||||||
@@ -40,4 +60,40 @@ Singleton {
|
|||||||
return r.obj.entry
|
return r.obj.entry
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function iconExists(iconName) {
|
||||||
|
return Quickshell.iconPath(iconName, true).length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function guessIcon(str) {
|
||||||
|
if (!str) return "image-missing";
|
||||||
|
|
||||||
|
// Normal substitutions
|
||||||
|
if (substitutions[str])
|
||||||
|
return substitutions[str];
|
||||||
|
|
||||||
|
// Regex substitutions
|
||||||
|
for (let i = 0; i < regexSubstitutions.length; i++) {
|
||||||
|
const substitution = regexSubstitutions[i];
|
||||||
|
const replacedName = str.replace(
|
||||||
|
substitution.regex,
|
||||||
|
substitution.replace,
|
||||||
|
);
|
||||||
|
if (replacedName != str) return replacedName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it gets detected normally, no need to guess
|
||||||
|
if (iconExists(str)) return str;
|
||||||
|
|
||||||
|
let guessStr = str;
|
||||||
|
// Guess: Take only app name of reverse domain name notation
|
||||||
|
guessStr = str.split('.').slice(-1)[0].toLowerCase();
|
||||||
|
if (iconExists(guessStr)) return guessStr;
|
||||||
|
// Guess: normalize to kebab case
|
||||||
|
guessStr = str.toLowerCase().replace(/\s+/g, "-");
|
||||||
|
if (iconExists(guessStr)) return guessStr;
|
||||||
|
|
||||||
|
// Give up
|
||||||
|
return str;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user