forked from Shinonome/dots-hyprland
persistent states: also use jsonadapter
This commit is contained in:
@@ -0,0 +1,48 @@
|
|||||||
|
pragma Singleton
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
property alias states: persistentStatesJsonAdapter
|
||||||
|
property string fileDir: Directories.state
|
||||||
|
property string fileName: "states.json"
|
||||||
|
property string filePath: `${root.fileDir}/${root.fileName}`
|
||||||
|
|
||||||
|
FileView {
|
||||||
|
path: root.filePath
|
||||||
|
|
||||||
|
watchChanges: true
|
||||||
|
onFileChanged: reload()
|
||||||
|
onAdapterUpdated: {
|
||||||
|
writeAdapter()
|
||||||
|
}
|
||||||
|
onLoadFailed: error => {
|
||||||
|
console.log("Failed to load persistent states file:", error);
|
||||||
|
if (error == FileViewError.FileNotFound) {
|
||||||
|
writeAdapter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter: JsonAdapter {
|
||||||
|
id: persistentStatesJsonAdapter
|
||||||
|
property JsonObject ai: JsonObject {
|
||||||
|
property string model
|
||||||
|
property real temperature: 0.5
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject sidebar: JsonObject {
|
||||||
|
property JsonObject bottomGroup: JsonObject {
|
||||||
|
property bool collapsed: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property JsonObject booru: JsonObject {
|
||||||
|
property bool allowNsfw: false
|
||||||
|
property string provider: "yandere"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -65,14 +65,14 @@ Item {
|
|||||||
name: "safe",
|
name: "safe",
|
||||||
description: qsTr("Disable NSFW content"),
|
description: qsTr("Disable NSFW content"),
|
||||||
execute: () => {
|
execute: () => {
|
||||||
PersistentStateManager.setState("booru.allowNsfw", false);
|
Persistent.states.booru.allowNsfw = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "lewd",
|
name: "lewd",
|
||||||
description: qsTr("Allow NSFW content"),
|
description: qsTr("Allow NSFW content"),
|
||||||
execute: () => {
|
execute: () => {
|
||||||
PersistentStateManager.setState("booru.allowNsfw", true);
|
Persistent.states.booru.allowNsfw = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@@ -106,7 +106,7 @@ Item {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Booru.makeRequest(tagList, PersistentStates.booru.allowNsfw, Config.options.sidebar.booru.limit, pageIndex);
|
Booru.makeRequest(tagList, Persistent.states.booru.allowNsfw, Config.options.sidebar.booru.limit, pageIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -593,10 +593,10 @@ Item {
|
|||||||
enabled: Booru.currentProvider !== "zerochan"
|
enabled: Booru.currentProvider !== "zerochan"
|
||||||
scale: 0.6
|
scale: 0.6
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
checked: (PersistentStates.booru.allowNsfw && Booru.currentProvider !== "zerochan")
|
checked: (Persistent.states.booru.allowNsfw && Booru.currentProvider !== "zerochan")
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
if (!nsfwSwitch.enabled) return;
|
if (!nsfwSwitch.enabled) return;
|
||||||
PersistentStateManager.setState("booru.allowNsfw", checked)
|
Persistent.states.booru.allowNsfw = checked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -610,7 +610,6 @@ Item {
|
|||||||
id: commandRepeater
|
id: commandRepeater
|
||||||
model: commandButtonsRow.commandsShown
|
model: commandButtonsRow.commandsShown
|
||||||
delegate: ApiCommandButton {
|
delegate: ApiCommandButton {
|
||||||
id: tagButton
|
|
||||||
property string commandRepresentation: `${root.commandPrefix}${modelData.name}`
|
property string commandRepresentation: `${root.commandPrefix}${modelData.name}`
|
||||||
buttonText: commandRepresentation
|
buttonText: commandRepresentation
|
||||||
colBackground: Appearance.colors.colLayer2
|
colBackground: Appearance.colors.colLayer2
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ Rectangle {
|
|||||||
clip: true
|
clip: true
|
||||||
implicitHeight: collapsed ? collapsedBottomWidgetGroupRow.implicitHeight : bottomWidgetGroupRow.implicitHeight
|
implicitHeight: collapsed ? collapsedBottomWidgetGroupRow.implicitHeight : bottomWidgetGroupRow.implicitHeight
|
||||||
property int selectedTab: 0
|
property int selectedTab: 0
|
||||||
property bool collapsed: PersistentStates.sidebar.bottomGroup.collapsed
|
property bool collapsed: Persistent.states.sidebar.bottomGroup.collapsed
|
||||||
property var tabs: [
|
property var tabs: [
|
||||||
{"type": "calendar", "name": "Calendar", "icon": "calendar_month", "widget": calendarWidget},
|
{"type": "calendar", "name": "Calendar", "icon": "calendar_month", "widget": calendarWidget},
|
||||||
{"type": "todo", "name": "To Do", "icon": "done_outline", "widget": todoWidget}
|
{"type": "todo", "name": "To Do", "icon": "done_outline", "widget": todoWidget}
|
||||||
@@ -30,7 +30,7 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setCollapsed(state) {
|
function setCollapsed(state) {
|
||||||
PersistentStateManager.setState("sidebar.bottomGroup.collapsed", state)
|
Persistent.states.sidebar.bottomGroup.collapsed = state
|
||||||
if (collapsed) {
|
if (collapsed) {
|
||||||
bottomWidgetGroupRow.opacity = 0
|
bottomWidgetGroupRow.opacity = 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ Singleton {
|
|||||||
readonly property var apiKeys: KeyringStorage.keyringData?.apiKeys ?? {}
|
readonly property var apiKeys: KeyringStorage.keyringData?.apiKeys ?? {}
|
||||||
readonly property var apiKeysLoaded: KeyringStorage.loaded
|
readonly property var apiKeysLoaded: KeyringStorage.loaded
|
||||||
property var postResponseHook
|
property var postResponseHook
|
||||||
property real temperature: PersistentStates?.ai?.temperature ?? 0.5
|
property real temperature: Persistent.states?.ai?.temperature ?? 0.5
|
||||||
|
|
||||||
function idForMessage(message) {
|
function idForMessage(message) {
|
||||||
// Generate a unique ID using timestamp and random value
|
// Generate a unique ID using timestamp and random value
|
||||||
@@ -202,10 +202,10 @@ Singleton {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
property var modelList: Object.keys(root.models)
|
property var modelList: Object.keys(root.models)
|
||||||
property var currentModelId: PersistentStates?.ai?.model || modelList[0]
|
property var currentModelId: Persistent.states?.ai?.model || modelList[0]
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
setModel(currentModelId, false); // Do necessary setup for model
|
setModel(currentModelId, false, false); // Do necessary setup for model
|
||||||
getOllamaModels.running = true
|
getOllamaModels.running = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,7 +293,7 @@ Singleton {
|
|||||||
return models[currentModelId];
|
return models[currentModelId];
|
||||||
}
|
}
|
||||||
|
|
||||||
function setModel(modelId, feedback = true) {
|
function setModel(modelId, feedback = true, setPersistentState = true) {
|
||||||
if (!modelId) modelId = ""
|
if (!modelId) modelId = ""
|
||||||
modelId = modelId.toLowerCase()
|
modelId = modelId.toLowerCase()
|
||||||
if (modelList.indexOf(modelId) !== -1) {
|
if (modelList.indexOf(modelId) !== -1) {
|
||||||
@@ -305,7 +305,7 @@ Singleton {
|
|||||||
root.addMessage(StringUtils.format(StringUtils.format("Online models disallowed\n\nControlled by `policies.ai` config option"), model.name), root.interfaceRole);
|
root.addMessage(StringUtils.format(StringUtils.format("Online models disallowed\n\nControlled by `policies.ai` config option"), model.name), root.interfaceRole);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PersistentStateManager.setState("ai.model", modelId);
|
if (setPersistentState) Persistent.states.ai.model = modelId;
|
||||||
if (feedback) root.addMessage(StringUtils.format(StringUtils.format("Model set to {0}"), model.name), root.interfaceRole);
|
if (feedback) root.addMessage(StringUtils.format(StringUtils.format("Model set to {0}"), model.name), root.interfaceRole);
|
||||||
if (model.requires_key) {
|
if (model.requires_key) {
|
||||||
// If key not there show advice
|
// If key not there show advice
|
||||||
@@ -327,7 +327,7 @@ Singleton {
|
|||||||
root.addMessage(qsTr("Temperature must be between 0 and 2"), Ai.interfaceRole);
|
root.addMessage(qsTr("Temperature must be between 0 and 2"), Ai.interfaceRole);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PersistentStateManager.setState("ai.temperature", value);
|
Persistent.states.ai.temperature = value;
|
||||||
root.temperature = value;
|
root.temperature = value;
|
||||||
root.addMessage(StringUtils.format(qsTr("Temperature set to {0}"), value), Ai.interfaceRole);
|
root.addMessage(StringUtils.format(qsTr("Temperature set to {0}"), value), Ai.interfaceRole);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -274,7 +274,7 @@ Singleton {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
property var currentProvider: PersistentStates.booru.provider
|
property var currentProvider: Persistent.states.booru.provider
|
||||||
|
|
||||||
function getWorkingImageSource(url) {
|
function getWorkingImageSource(url) {
|
||||||
if (url.includes('pximg.net')) {
|
if (url.includes('pximg.net')) {
|
||||||
@@ -286,7 +286,7 @@ Singleton {
|
|||||||
function setProvider(provider) {
|
function setProvider(provider) {
|
||||||
provider = provider.toLowerCase()
|
provider = provider.toLowerCase()
|
||||||
if (providerList.indexOf(provider) !== -1) {
|
if (providerList.indexOf(provider) !== -1) {
|
||||||
PersistentStateManager.setState("booru.provider", provider)
|
Persistent.states.booru.provider = provider
|
||||||
root.addSystemMessage(qsTr("Provider set to ") + providers[provider].name
|
root.addSystemMessage(qsTr("Provider set to ") + providers[provider].name
|
||||||
+ (provider == "zerochan" ? qsTr(". Notes for Zerochan:\n- You must enter a color\n- Set your zerochan username in `sidebar.booru.zerochan.username` config option. You [might be banned for not doing so](https://www.zerochan.net/api#:~:text=The%20request%20may%20still%20be%20completed%20successfully%20without%20this%20custom%20header%2C%20but%20your%20project%20may%20be%20banned%20for%20being%20anonymous.)!") : ""))
|
+ (provider == "zerochan" ? qsTr(". Notes for Zerochan:\n- You must enter a color\n- Set your zerochan username in `sidebar.booru.zerochan.username` config option. You [might be banned for not doing so](https://www.zerochan.net/api#:~:text=The%20request%20may%20still%20be%20completed%20successfully%20without%20this%20custom%20header%2C%20but%20your%20project%20may%20be%20banned%20for%20being%20anonymous.)!") : ""))
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,105 +0,0 @@
|
|||||||
pragma Singleton
|
|
||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import "root:/modules/common"
|
|
||||||
import "root:/modules/common/functions/object_utils.js" as ObjectUtils
|
|
||||||
import QtQuick
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Io
|
|
||||||
import Quickshell.Hyprland
|
|
||||||
import Qt.labs.platform
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manages persistent states across sessions.
|
|
||||||
* Run loadStates() once at startup to load the states, then use setState() and getState() to modify and access them.
|
|
||||||
*/
|
|
||||||
Singleton {
|
|
||||||
id: root
|
|
||||||
property string fileDir: Directories.state
|
|
||||||
property string fileName: "states.json"
|
|
||||||
property string filePath: `${root.fileDir}/${root.fileName}`
|
|
||||||
property bool allowWriteback: false
|
|
||||||
|
|
||||||
function getState(nestedKey) {
|
|
||||||
let keys = nestedKey.split(".");
|
|
||||||
let obj = PersistentStates;
|
|
||||||
for (let i = 0; i < keys.length; ++i) {
|
|
||||||
if (obj[keys[i]] === undefined) {
|
|
||||||
console.error(`[PersistentStateManager] Key "${keys[i]}" not found in PersistentStates`);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
obj = obj[keys[i]];
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setState(nestedKey, value) {
|
|
||||||
if (!root.allowWriteback) return;
|
|
||||||
let keys = nestedKey.split(".");
|
|
||||||
let obj = PersistentStates;
|
|
||||||
let parents = [obj];
|
|
||||||
|
|
||||||
// Traverse and collect parent objects
|
|
||||||
for (let i = 0; i < keys.length - 1; ++i) {
|
|
||||||
if (!obj[keys[i]] || typeof obj[keys[i]] !== "object") {
|
|
||||||
obj[keys[i]] = {};
|
|
||||||
}
|
|
||||||
obj = obj[keys[i]];
|
|
||||||
parents.push(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the value at the innermost key
|
|
||||||
obj[keys[keys.length - 1]] = value;
|
|
||||||
|
|
||||||
saveStates()
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadStates() {
|
|
||||||
stateFileView.reload()
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveStates() {
|
|
||||||
const plainStates = ObjectUtils.toPlainObject(PersistentStates)
|
|
||||||
stateFileView.setText(JSON.stringify(plainStates, null, 2))
|
|
||||||
}
|
|
||||||
|
|
||||||
function applyStates(fileContent) {
|
|
||||||
try {
|
|
||||||
const json = JSON.parse(fileContent);
|
|
||||||
ObjectUtils.applyToQtObject(PersistentStates, json);
|
|
||||||
root.allowWriteback = true
|
|
||||||
} catch (e) {
|
|
||||||
console.error("[PersistentStateManager] Error reading file:", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: delayedFileRead
|
|
||||||
interval: Config.options?.hacks?.arbitraryRaceConditionDelay ?? 100
|
|
||||||
repeat: false
|
|
||||||
running: false
|
|
||||||
onTriggered: {
|
|
||||||
root.applyStates(stateFileView.text())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FileView {
|
|
||||||
id: stateFileView
|
|
||||||
path: root.filePath
|
|
||||||
watchChanges: true
|
|
||||||
// onFileChanged: {
|
|
||||||
// console.log("[PersistentStateManager] File changed, reloading...")
|
|
||||||
// this.reload()
|
|
||||||
// delayedFileRead.start()
|
|
||||||
// }
|
|
||||||
onLoadedChanged: {
|
|
||||||
const fileContent = stateFileView.text()
|
|
||||||
root.applyStates(fileContent)
|
|
||||||
}
|
|
||||||
onLoadFailed: (error) => {
|
|
||||||
console.log("[PersistentStateManager] File not found, creating new file")
|
|
||||||
root.saveStates()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -48,7 +48,6 @@ ShellRoot {
|
|||||||
// Force initialization of some singletons
|
// Force initialization of some singletons
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
MaterialThemeLoader.reapplyTheme()
|
MaterialThemeLoader.reapplyTheme()
|
||||||
PersistentStateManager.loadStates()
|
|
||||||
Cliphist.refresh()
|
Cliphist.refresh()
|
||||||
FirstRunExperience.load()
|
FirstRunExperience.load()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user