feat(workspace): Add workspace theme persistence to zen_workspaces table and caching improvements

This commit introduces several improvements related to workspace themes:

- **Theme Persistence:** Workspaces now persist their themes in zen_workspaces table alongside other workspace data.
- **Theme Propagation:** The `_propagateWorkspaceData` function now includes an option to clear the workspace cache, preventing stale data from being used when propagating workspace data.
- **Theme Handling:** The `onWorkspaceChange` function now uses the theme from the workspace object or a passed theme, simplifying theme handling.
- **Theme Data Structure:** The `zen_workspaces` table has been updated to store theme data directly, eliminating the need for a separate `zen_workspace_themes` table.
- **Database Schema Changes:** This commit introduces new columns to the `zen_workspaces` table to store theme information, making the database schema more efficient and less redundant.
This commit is contained in:
Kristijan Ribarić 2024-10-26 18:42:12 +02:00
parent 8c3b9110b3
commit ceefcbecef
3 changed files with 99 additions and 46 deletions

View file

@ -333,7 +333,7 @@
} }
return `color-mix(in srgb, rgb(${color.c[0]}, ${color.c[1]}, ${color.c[2]}) ${this.currentOpacity * 100}%, var(--zen-themed-toolbar-bg) ${(1 - this.currentOpacity) * 100}%)`; return `color-mix(in srgb, rgb(${color.c[0]}, ${color.c[1]}, ${color.c[2]}) ${this.currentOpacity * 100}%, var(--zen-themed-toolbar-bg) ${(1 - this.currentOpacity) * 100}%)`;
} }
getGradient(colors) { getGradient(colors) {
const themedColors = this.themedColors(colors); const themedColors = this.themedColors(colors);
@ -360,23 +360,25 @@
async onWorkspaceChange(workspace, skipUpdate = false, theme = null) { async onWorkspaceChange(workspace, skipUpdate = false, theme = null) {
const uuid = workspace.uuid; const uuid = workspace.uuid;
// Use theme from workspace object or passed theme
const workspaceTheme = theme || workspace.theme;
if(!theme) { const appWrapper = document.getElementById('zen-main-app-wrapper');
theme = await ZenWorkspacesStorage.getWorkspaceTheme(uuid);
}
const appWrapepr = document.getElementById('zen-main-app-wrapper');
if (!skipUpdate) { if (!skipUpdate) {
appWrapepr.removeAttribute('animating'); appWrapper.removeAttribute('animating');
appWrapepr.setAttribute('animating', 'true'); appWrapper.setAttribute('animating', 'true');
document.body.style.setProperty('--zen-main-browser-background-old', document.body.style.getPropertyValue('--zen-main-browser-background')); document.body.style.setProperty('--zen-main-browser-background-old',
document.body.style.getPropertyValue('--zen-main-browser-background')
);
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
setTimeout(() => { setTimeout(() => {
appWrapepr.removeAttribute('animating'); appWrapper.removeAttribute('animating');
}, 600); }, 600);
}); });
} }
this.customColorList.innerHTML = ''; this.customColorList.innerHTML = '';
if (!theme || theme.type !== 'gradient') { if (!workspaceTheme || workspaceTheme.type !== 'gradient') {
document.body.style.removeProperty('--zen-main-browser-background'); document.body.style.removeProperty('--zen-main-browser-background');
this.updateNoise(0); this.updateNoise(0);
if (!skipUpdate) { if (!skipUpdate) {
@ -386,22 +388,27 @@
} }
return; return;
} }
this.currentOpacity = theme.opacity || 0.5;
this.currentRotation = theme.rotation || 45; this.currentOpacity = workspaceTheme.opacity || 0.5;
this.currentTexture = theme.texture || 0; this.currentRotation = workspaceTheme.rotation || 45;
this.currentTexture = workspaceTheme.texture || 0;
document.getElementById('PanelUI-zen-gradient-generator-opacity').value = this.currentOpacity; document.getElementById('PanelUI-zen-gradient-generator-opacity').value = this.currentOpacity;
document.getElementById('PanelUI-zen-gradient-generator-texture').value = this.currentTexture; document.getElementById('PanelUI-zen-gradient-generator-texture').value = this.currentTexture;
this.setRotationInput(this.currentRotation); this.setRotationInput(this.currentRotation);
const gradient = this.getGradient(theme.gradientColors);
this.updateNoise(theme.texture); const gradient = this.getGradient(workspaceTheme.gradientColors);
for (const dot of theme.gradientColors) { this.updateNoise(workspaceTheme.texture);
for (const dot of workspaceTheme.gradientColors) {
if (dot.isCustom) { if (dot.isCustom) {
this.addColorToCustomList(dot.c); this.addColorToCustomList(dot.c);
} }
} }
document.body.style.setProperty('--zen-main-browser-background', gradient); document.body.style.setProperty('--zen-main-browser-background', gradient);
if (!skipUpdate) { if (!skipUpdate) {
this.recalculateDots(theme.gradientColors); this.recalculateDots(workspaceTheme.gradientColors);
} }
} }
@ -441,12 +448,15 @@
return {c: isCustom ? color : color.match(/\d+/g).map(Number), isCustom}; return {c: isCustom ? color : color.match(/\d+/g).map(Number), isCustom};
}); });
const gradient = this.getTheme(colors, this.currentOpacity, this.currentRotation, this.currentTexture); const gradient = this.getTheme(colors, this.currentOpacity, this.currentRotation, this.currentTexture);
let currentWorkspace = await ZenWorkspaces.getActiveWorkspace();
const currentWorkspace = await ZenWorkspaces.getActiveWorkspace();
if(!skipSave) { if(!skipSave) {
await ZenWorkspacesStorage.saveWorkspaceTheme(currentWorkspace.uuid, gradient); await ZenWorkspacesStorage.saveWorkspaceTheme(currentWorkspace.uuid, gradient);
await ZenWorkspaces._propagateWorkspaceData();
currentWorkspace = await ZenWorkspaces.getActiveWorkspace();
} }
await this.onWorkspaceChange(currentWorkspace, true,skipSave ? gradient : null);
await this.onWorkspaceChange(currentWorkspace, true, skipSave ? gradient : null);
} }
async handlePanelClose() { async handlePanelClose() {

View file

@ -64,7 +64,6 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
!this._workspaceCache.lastChangeTimestamp || !this._workspaceCache.lastChangeTimestamp ||
lastChangeTimestamp > this._workspaceCache.lastChangeTimestamp lastChangeTimestamp > this._workspaceCache.lastChangeTimestamp
) { ) {
this._workspaceCache = null;
await this._propagateWorkspaceData(); await this._propagateWorkspaceData();
} }
} catch (error) { } catch (error) {
@ -236,7 +235,6 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
async saveWorkspace(workspaceData) { async saveWorkspace(workspaceData) {
await ZenWorkspacesStorage.saveWorkspace(workspaceData); await ZenWorkspacesStorage.saveWorkspace(workspaceData);
this._workspaceCache = null;
await this._propagateWorkspaceData(); await this._propagateWorkspaceData();
await this._updateWorkspacesChangeContextMenu(); await this._updateWorkspacesChangeContextMenu();
} }
@ -248,7 +246,6 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
this._deleteAllTabsInWorkspace(windowID); this._deleteAllTabsInWorkspace(windowID);
delete this._lastSelectedWorkspaceTabs[windowID]; delete this._lastSelectedWorkspaceTabs[windowID];
await ZenWorkspacesStorage.removeWorkspace(windowID); await ZenWorkspacesStorage.removeWorkspace(windowID);
this._workspaceCache = null;
await this._propagateWorkspaceData(); await this._propagateWorkspaceData();
await this._updateWorkspacesChangeContextMenu(); await this._updateWorkspacesChangeContextMenu();
} }
@ -332,7 +329,7 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
); );
} }
async _propagateWorkspaceData({ ignoreStrip = false } = {}) { async _propagateWorkspaceData({ ignoreStrip = false, clearCache = true } = {}) {
await this.foreachWindowAsActive(async (browser) => { await this.foreachWindowAsActive(async (browser) => {
let workspaceList = browser.document.getElementById('PanelUI-zen-workspaces-list'); let workspaceList = browser.document.getElementById('PanelUI-zen-workspaces-list');
const createWorkspaceElement = (workspace) => { const createWorkspaceElement = (workspace) => {
@ -407,7 +404,6 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
const targetWorkspaceId = element.getAttribute('zen-workspace-id'); const targetWorkspaceId = element.getAttribute('zen-workspace-id');
if (draggedWorkspaceId !== targetWorkspaceId) { if (draggedWorkspaceId !== targetWorkspaceId) {
await this.moveWorkspace(draggedWorkspaceId, targetWorkspaceId); await this.moveWorkspace(draggedWorkspaceId, targetWorkspaceId);
await this._propagateWorkspaceData();
} }
if (this.draggedElement) { if (this.draggedElement) {
this.draggedElement.classList.remove('dragging'); this.draggedElement.classList.remove('dragging');
@ -522,7 +518,6 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
if (this.isReorderModeOn(browser)) { if (this.isReorderModeOn(browser)) {
const draggedWorkspaceId = event.dataTransfer.getData('text/plain'); const draggedWorkspaceId = event.dataTransfer.getData('text/plain');
await this.moveWorkspaceToEnd(draggedWorkspaceId); await this.moveWorkspaceToEnd(draggedWorkspaceId);
await this._propagateWorkspaceData();
if (this.draggedElement) { if (this.draggedElement) {
this.draggedElement.classList.remove('dragging'); this.draggedElement.classList.remove('dragging');
@ -535,7 +530,9 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
return element; return element;
}; };
browser.ZenWorkspaces._workspaceCache = null; if(clearCache) {
browser.ZenWorkspaces._workspaceCache = null;
}
let workspaces = await browser.ZenWorkspaces._workspaces(); let workspaces = await browser.ZenWorkspaces._workspaces();
workspaceList.innerHTML = ''; workspaceList.innerHTML = '';
workspaceList.parentNode.style.display = 'flex'; workspaceList.parentNode.style.display = 'flex';
@ -574,6 +571,7 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
workspaces.push(draggedWorkspace); workspaces.push(draggedWorkspace);
await ZenWorkspacesStorage.updateWorkspacePositions(workspaces); await ZenWorkspacesStorage.updateWorkspacePositions(workspaces);
await this._propagateWorkspaceData();
} }
isReorderModeOn(browser) { isReorderModeOn(browser) {
@ -611,6 +609,7 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
workspaces.splice(targetIndex, 0, draggedWorkspace); workspaces.splice(targetIndex, 0, draggedWorkspace);
await ZenWorkspacesStorage.updateWorkspacePositions(workspaces); await ZenWorkspacesStorage.updateWorkspacePositions(workspaces);
await this._propagateWorkspaceData();
} }
async openWorkspacesDialog(event) { async openWorkspacesDialog(event) {
@ -621,6 +620,7 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
let panel = document.getElementById('PanelUI-zen-workspaces'); let panel = document.getElementById('PanelUI-zen-workspaces');
await this._propagateWorkspaceData({ await this._propagateWorkspaceData({
ignoreStrip: true, ignoreStrip: true,
clearCache: false
}); });
PanelMultiView.openPopup(panel, target, { PanelMultiView.openPopup(panel, target, {
position: 'bottomright topright', position: 'bottomright topright',
@ -814,7 +814,6 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
let icon = document.querySelector('#PanelUI-zen-workspaces-icon-picker-wrapper [selected]'); let icon = document.querySelector('#PanelUI-zen-workspaces-icon-picker-wrapper [selected]');
icon?.removeAttribute('selected'); icon?.removeAttribute('selected');
await this.createAndSaveWorkspace(workspaceName, false, icon?.label); await this.createAndSaveWorkspace(workspaceName, false, icon?.label);
await this._propagateWorkspaceData();
this.goToPreviousSubView(); this.goToPreviousSubView();
} }
@ -832,7 +831,6 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
workspaceData.name = workspaceName; workspaceData.name = workspaceName;
workspaceData.icon = icon?.label; workspaceData.icon = icon?.label;
await this.saveWorkspace(workspaceData); await this.saveWorkspace(workspaceData);
await this._propagateWorkspaceData();
this.goToPreviousSubView(); this.goToPreviousSubView();
} }
@ -916,7 +914,7 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
document.getElementById('tabbrowser-tabs')._positionPinnedTabs(); document.getElementById('tabbrowser-tabs')._positionPinnedTabs();
await this._propagateWorkspaceData(); await this._propagateWorkspaceData({clearCache: false});
this._inChangingWorkspace = false; this._inChangingWorkspace = false;
for (let listener of this._changeListeners ?? []) { for (let listener of this._changeListeners ?? []) {
@ -1045,7 +1043,6 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
let userContextId = parseInt(event.target.getAttribute('data-usercontextid')); let userContextId = parseInt(event.target.getAttribute('data-usercontextid'));
workspace.containerTabId = userContextId; workspace.containerTabId = userContextId;
await this.saveWorkspace(workspace); await this.saveWorkspace(workspace);
await this._propagateWorkspaceData();
} }
onContextMenuClose() { onContextMenuClose() {
@ -1060,7 +1057,6 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
async setDefaultWorkspace() { async setDefaultWorkspace() {
await ZenWorkspacesStorage.setDefaultWorkspace(this._contextMenuId); await ZenWorkspacesStorage.setDefaultWorkspace(this._contextMenuId);
this._workspaceCache = null;
await this._propagateWorkspaceData(); await this._propagateWorkspaceData();
} }
@ -1118,7 +1114,6 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature {
delete this._lastSelectedWorkspaceTabs[previousWorkspaceID]; delete this._lastSelectedWorkspaceTabs[previousWorkspaceID];
} }
} }
this._workspaceCache = null;
const workspaces = await this._workspaces(); const workspaces = await this._workspaces();
await this.changeWorkspace(workspaces.workspaces.find((workspace) => workspace.uuid === workspaceID)); await this.changeWorkspace(workspaces.workspaces.find((workspace) => workspace.uuid === workspaceID));
} }

View file

@ -21,6 +21,26 @@ var ZenWorkspacesStorage = {
) )
`); `);
// Add new columns if they don't exist
// SQLite doesn't have a direct "ADD COLUMN IF NOT EXISTS" syntax,
// so we need to check if the columns exist first
const columns = await db.execute(`PRAGMA table_info(zen_workspaces)`);
const columnNames = columns.map(row => row.getResultByName('name'));
// Helper function to add column if it doesn't exist
const addColumnIfNotExists = async (columnName, definition) => {
if (!columnNames.includes(columnName)) {
await db.execute(`ALTER TABLE zen_workspaces ADD COLUMN ${columnName} ${definition}`);
}
};
// Add each new column if it doesn't exist
await addColumnIfNotExists('theme_type', 'TEXT');
await addColumnIfNotExists('theme_colors', 'TEXT');
await addColumnIfNotExists('theme_opacity', 'REAL');
await addColumnIfNotExists('theme_rotation', 'INTEGER');
await addColumnIfNotExists('theme_texture', 'REAL');
// Create an index on the uuid column // Create an index on the uuid column
await db.execute(` await db.execute(`
CREATE INDEX IF NOT EXISTS idx_zen_workspaces_uuid ON zen_workspaces(uuid) CREATE INDEX IF NOT EXISTS idx_zen_workspaces_uuid ON zen_workspaces(uuid)
@ -38,14 +58,6 @@ var ZenWorkspacesStorage = {
await db.execute(` await db.execute(`
CREATE INDEX IF NOT EXISTS idx_zen_workspaces_changes_uuid ON zen_workspaces_changes(uuid) CREATE INDEX IF NOT EXISTS idx_zen_workspaces_changes_uuid ON zen_workspaces_changes(uuid)
`); `);
// Create a workspace theme table if it doesn't exist, theme can be null
await db.execute(`
CREATE TABLE IF NOT EXISTS zen_workspace_themes (
uuid TEXT PRIMARY KEY,
json TEXT
)
`);
}); });
}, },
@ -252,20 +264,56 @@ var ZenWorkspacesStorage = {
}, },
async saveWorkspaceTheme(uuid, theme) { async saveWorkspaceTheme(uuid, theme) {
await PlacesUtils.withConnectionWrapper('ZenWorkspacesStorage.saveWorkspaceTheme', async (db) => { await PlacesUtils.withConnectionWrapper('saveWorkspaceTheme', async (db) => {
await db.execute(` await db.execute(`
INSERT OR REPLACE INTO zen_workspace_themes (uuid, json) UPDATE zen_workspaces
VALUES (:uuid, :json) SET
`, { uuid, json: JSON.stringify(theme) }); theme_type = :type,
theme_colors = :colors,
theme_opacity = :opacity,
theme_rotation = :rotation,
theme_texture = :texture,
updated_at = :now
WHERE uuid = :uuid
`, {
type: theme.type,
colors: JSON.stringify(theme.gradientColors),
opacity: theme.opacity,
rotation: theme.rotation,
texture: theme.texture,
now: Date.now(),
uuid
});
await this.markChanged(uuid);
await this.updateLastChangeTimestamp(db);
}); });
}, },
async getWorkspaceTheme(uuid) { async getWorkspaceTheme(uuid) {
const db = await PlacesUtils.promiseDBConnection(); const db = await PlacesUtils.promiseDBConnection();
const result = await db.executeCached(` const result = await db.executeCached(`
SELECT json FROM zen_workspace_themes WHERE uuid = :uuid SELECT
theme_type,
theme_colors,
theme_opacity,
theme_rotation,
theme_texture
FROM zen_workspaces
WHERE uuid = :uuid
`, { uuid }); `, { uuid });
return result.length ? JSON.parse(result[0].getResultByName('json')) : null;
if (!result.length || !result[0].getResultByName('theme_type')) {
return null;
}
return {
type: result[0].getResultByName('theme_type'),
gradientColors: JSON.parse(result[0].getResultByName('theme_colors')),
opacity: result[0].getResultByName('theme_opacity'),
rotation: result[0].getResultByName('theme_rotation'),
texture: result[0].getResultByName('theme_texture')
};
}, },
async getChangedIDs() { async getChangedIDs() {