pragma Singleton import qs.config import Quickshell import Quickshell.Hyprland import Quickshell.Io import Quickshell.Services.Notifications Singleton { id: root readonly property var weatherIcons: ({ "113": "clear_day", "116": "partly_cloudy_day", "119": "cloud", "122": "cloud", "143": "foggy", "176": "rainy_light", "179": "rainy_snow", "182": "rainy_snow", "185": "rainy_snow", "200": "electric_bolt", "227": "snowing", "230": "snowing_heavy", "248": "foggy", "260": "foggy", "263": "rainy_light", "266": "rainy_light", "281": "rainy_snow", "284": "rainy_snow", "293": "rainy_light", "296": "rainy_light", "299": "rainy_heavy", "302": "rainy_heavy", "305": "rainy_heavy", "308": "rainy_heavy", "311": "rainy_snow", "314": "rainy_snow", "317": "rainy_snow", "320": "snowing", "323": "rainy_snow", "326": "rainy_snow", "329": "snowing_heavy", "332": "snowing_heavy", "335": "snowing", "338": "snowing_heavy", "350": "rainy_snow", "353": "rainy_light", "356": "rainy_heavy", "359": "rainy_heavy", "362": "rainy_snow", "365": "rainy_snow", "368": "snowing", "371": "snowing_heavy", "374": "rainy_snow", "377": "rainy_snow", "386": "electric_bolt", "389": "electric_bolt", "392": "electric_bolt", "395": "snowing_heavy" }) readonly property var weatherIconColors: ({ "clear_day": Config.colors.yellow, "partly_cloudy_day": Config.colors.primary, "cloud": Config.colors.tertiary, "foggy": Config.colors.tertiary, "electric_bolt": Config.colors.yellow, "rainy_light": Config.colors.blue, "rainy_heavy": Config.colors.blue, "rainy_snow": Config.colors.blue, "snowing": Config.colors.cyan, "snowing_heavy": Config.colors.cyan, "air": Config.colors.primary }) readonly property var desktopEntrySubs: ({ "gimp-3.0": ["gimp"], "discord": ["discord", "discord-canary"] }) readonly property var categoryIcons: ({ WebBrowser: "language", Printing: "print", Security: "security", Network: "business_messages", Archiving: "archive", Compression: "archive", Development: "code", IDE: "code", TextEditor: "edit_note", Audio: "music_note", Music: "music_note", Player: "music_note", Recorder: "mic", Game: "sports_esports", FileTools: "files", FileManager: "files", Filesystem: "files", FileTransfer: "files", Settings: "settings", DesktopSettings: "settings", HardwareSettings: "settings", TerminalEmulator: "terminal", ConsoleOnly: "terminal", Utility: "build", Monitor: "monitor_heart", Midi: "graphic_eq", Mixer: "graphic_eq", AudioVideoEditing: "video_settings", AudioVideo: "music_video", Video: "videocam", Building: "construction", Graphics: "photo_library", "2DGraphics": "photo_library", RasterGraphics: "photo_library", TV: "tv", System: "host", Office: "content_paste" }) function getDesktopEntry(name: string): DesktopEntry { name = name.toLowerCase().replace(/ /g, "-"); let names = []; if (desktopEntrySubs.hasOwnProperty(name)) names = desktopEntrySubs[name]; else names = [name]; return DesktopEntries.applications.values.find(a => names.includes(a.id.toLowerCase())) ?? null; } function getAppIcon(name: string, fallback: string): string { return Quickshell.iconPath(getDesktopEntry(name)?.icon, fallback); } function getAppCategoryIcon(name: string, fallback: string): string { const categories = getDesktopEntry(name)?.categories; if (categories) for (const [key, value] of Object.entries(categoryIcons)) if (categories.includes(key)) return value; return fallback; } // App icon precedence // Used to preferentially display apps in a workspace readonly property var appIconPrec: ({ sports_esports: 10, code: 9, music_note: 9, content_paste: 9, graphic_eq: 8, tv: 8, edit_note: 6, language: 5, business_messages: 5, files: 4, host: 4, mic: 4, construction: 4, monitor_heart: 3, security: 3, archive: 3, settings: 2, build: 2, photo_library: 1, terminal: 1 }) function getWorkspaceIcon(workspace: HyprlandWorkspace): string { if (!workspace || workspace.toplevels.values.length === 0) return "add"; return [...workspace.toplevels.values] .map(tl => getAppCategoryIcon(tl.lastIpcObject.class, "terminal")) .reduce((a, b) => appIconPrec[a] > appIconPrec[b] ? a : b); } function getNetworkIcon(strength: int): string { if (strength >= 80) return "signal_wifi_4_bar"; if (strength >= 60) return "network_wifi_3_bar"; if (strength >= 40) return "network_wifi_2_bar"; if (strength >= 20) return "network_wifi_1_bar"; return "signal_wifi_0_bar"; } function getBluetoothIcon(icon: string): string { if (icon.includes("headset") || icon.includes("headphones")) return "headphones"; if (icon.includes("audio")) return "speaker"; if (icon.includes("phone")) return "smartphone"; if (icon.includes("mouse")) return "mouse"; return "bluetooth"; } function getWeatherIcon(code: string): string { if (weatherIcons.hasOwnProperty(code)) return weatherIcons[code]; return "air"; } function getHumidityIcon(humidity: real): string { if (humidity >= 0.66) return "humidity_high"; if (humidity >= 0.33) return "humidity_mid"; return "humidity_low"; } function getVolumeIcon(volume: real, isMuted: bool): string { if (isMuted) return "no_sound"; if (volume >= 0.5) return "volume_up"; if (volume > 0) return "volume_down"; return "volume_mute"; } function getMicVolumeIcon(volume: real, isMuted: bool): string { if (!isMuted && volume > 0) return "mic"; return "mic_off"; } function getBrightnessIcon(brightness: real): string { return `brightness_${(Math.round(brightness * 6) + 1)}`; } function getNotifIcon(summary: string, urgency: int): string { summary = summary.toLowerCase(); if (summary.includes("reboot")) return "restart_alt"; if (summary.includes("record")) return "screen_record"; if (summary.includes("battery")) return "power"; if (summary.includes("screenshot")) return "screenshot_monitor"; if (summary.includes("welcome")) return "waving_hand"; if (summary.includes("time") || summary.includes("a break")) return "schedule"; if (summary.includes("installed")) return "download"; if (summary.includes("update")) return "update"; if (summary.includes("unable to")) return "deployed_code_alert"; if (summary.includes("profile")) return "person"; if (summary.includes("image")) return "image"; if (summary.includes("file")) return "folder_copy"; if (urgency === NotificationUrgency.Critical) return "release_alert"; return "chat"; } }