pragma Singleton import Quickshell import Quickshell.Io import QtQuick Singleton { id: root property alias initialized: values.initialized property alias favorites: values.favorites property string saveError: "" FileView { id: preferencesFile path: Quickshell.stateDir + "/panama-home.json" blockLoading: true printErrors: false atomicWrites: true onSaved: root.saveError = "" onSaveFailed: error => root.saveError = "Could not save Home favorites." JsonAdapter { id: values property bool initialized: false property var favorites: [] } } Connections { target: values function onInitializedChanged(): void { persistTimer.restart(); } function onFavoritesChanged(): void { persistTimer.restart(); } } Component.onCompleted: preferencesFile.reload() Timer { id: persistTimer interval: 180 repeat: false onTriggered: preferencesFile.writeAdapter() } function cloneFavorites(): var { var clone = []; for (var index = 0; index < values.favorites.length; index++) { var favorite = values.favorites[index]; clone.push({ id: favorite.id, alias: favorite.alias }); } return clone; } function isValidEntityId(entityId: var): bool { return typeof entityId === "string" && /^light\.[a-z0-9_]+$/.test(entityId); } function initialize(legacyIds: var): void { if (values.initialized) { return; } var seededFavorites = []; var seen = {}; if (legacyIds && typeof legacyIds.length === "number") { for (var index = 0; index < legacyIds.length; index++) { var entityId = legacyIds[index]; if (!isValidEntityId(entityId) || seen[entityId]) { continue; } seen[entityId] = true; seededFavorites.push({ id: entityId, alias: "" }); } } values.favorites = seededFavorites; values.initialized = true; } function resetHomeDefaults(): void { persistTimer.stop(); values.favorites = []; values.initialized = false; root.saveError = ""; preferencesFile.writeAdapter(); } function isSelected(entityId: string): bool { for (var index = 0; index < values.favorites.length; index++) { if (values.favorites[index].id === entityId) { return true; } } return false; } function aliasFor(entityId: string, sourceName: string): string { for (var index = 0; index < values.favorites.length; index++) { var favorite = values.favorites[index]; if (favorite.id === entityId && favorite.alias !== "") { return favorite.alias; } } return sourceName; } function add(entityId: string): void { if (!isValidEntityId(entityId) || isSelected(entityId)) { return; } var nextFavorites = cloneFavorites(); nextFavorites.push({ id: entityId, alias: "" }); values.favorites = nextFavorites; } function remove(entityId: string): void { var nextFavorites = []; var removed = false; for (var index = 0; index < values.favorites.length; index++) { var favorite = values.favorites[index]; if (favorite.id === entityId) { removed = true; continue; } nextFavorites.push({ id: favorite.id, alias: favorite.alias }); } if (removed) { values.favorites = nextFavorites; } } function setAlias(entityId: string, alias: string): void { var nextFavorites = cloneFavorites(); var updated = false; var trimmedAlias = String(alias).trim(); for (var index = 0; index < nextFavorites.length; index++) { if (nextFavorites[index].id === entityId) { nextFavorites[index] = { id: entityId, alias: trimmedAlias }; updated = true; break; } } if (updated) { values.favorites = nextFavorites; } } function move(entityId: string, targetIndex: int): void { var nextFavorites = cloneFavorites(); var currentIndex = -1; for (var index = 0; index < nextFavorites.length; index++) { if (nextFavorites[index].id === entityId) { currentIndex = index; break; } } if (currentIndex === -1) { return; } var favorite = nextFavorites.splice(currentIndex, 1)[0]; var clampedIndex = Math.max(0, Math.min(targetIndex, nextFavorites.length)); nextFavorites.splice(clampedIndex, 0, favorite); values.favorites = nextFavorites; } function retrySave(): void { preferencesFile.writeAdapter(); } }