From 2be2c00e4e68ec8d2cafe33e45f713d419cbd9b7 Mon Sep 17 00:00:00 2001 From: Ryosuke Asano Date: Wed, 29 Nov 2023 00:20:12 +0900 Subject: [PATCH] [FB] Workspaces | Create migrator for Workspaces --- browser/base/content/browser-workspace.js | 331 +++++++++++++++++- .../icons/workspace-icons/briefcase.svg | 2 +- browser/themes/icons/workspace-icons/cart.svg | 2 +- .../themes/icons/workspace-icons/chill.svg | 2 +- .../themes/icons/workspace-icons/circle.svg | 2 +- .../themes/icons/workspace-icons/compass.svg | 2 +- .../themes/icons/workspace-icons/dollar.svg | 2 +- .../themes/icons/workspace-icons/fence.svg | 2 +- .../icons/workspace-icons/fingerprint.svg | 2 +- browser/themes/icons/workspace-icons/food.svg | 2 +- .../themes/icons/workspace-icons/fruit.svg | 2 +- browser/themes/icons/workspace-icons/gear.svg | 2 +- browser/themes/icons/workspace-icons/gift.svg | 2 +- browser/themes/icons/workspace-icons/pet.svg | 2 +- .../themes/icons/workspace-icons/question.svg | 2 +- browser/themes/icons/workspace-icons/star.svg | 2 +- browser/themes/icons/workspace-icons/tree.svg | 2 +- .../themes/icons/workspace-icons/vacation.svg | 2 +- 18 files changed, 330 insertions(+), 35 deletions(-) diff --git a/browser/base/content/browser-workspace.js b/browser/base/content/browser-workspace.js index 357a30d2..6b02815c 100644 --- a/browser/base/content/browser-workspace.js +++ b/browser/base/content/browser-workspace.js @@ -4,7 +4,10 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -const l10n = new Localization(["browser/floorp.ftl", "branding/brand.ftl"], true); +const l10n = new Localization( + ["browser/floorp.ftl", "branding/brand.ftl"], + true +); const WorkspaceUtils = ChromeUtils.importESModule( "resource:///modules/WorkspaceUtils.sys.mjs" @@ -307,13 +310,17 @@ const workspaceFunctions = { let workspaceAll = Services.prefs .getStringPref(WorkspaceUtils.workspacesPreferences.WORKSPACE_ALL_PREF) .split(","); - + for (let i = 0; i < workspaceAll.length; i++) { let label = workspaceAll[i]; workspaceFunctions.WorkspaceContextMenu.addWorkspaceElemToMenu(label); - + // Check if workspace tabs are exist - if (!workspaceFunctions.manageWorkspaceFunctions.checkWorkspaceTabsAreExist(workspaceAll[i])) { + if ( + !workspaceFunctions.manageWorkspaceFunctions.checkWorkspaceTabsAreExist( + workspaceAll[i] + ) + ) { workspaceFunctions.manageWorkspaceFunctions.deleteworkspace( workspaceAll[i] ); @@ -1012,7 +1019,10 @@ const workspaceFunctions = { return null; } let iconURL = settings[targetWorkspaceNumber][workspaceName].icon; - let removeSVG = iconURL.replace("chrome://browser/skin/workspace-icons/", ""); + let removeSVG = iconURL.replace( + "chrome://browser/skin/workspace-icons/", + "" + ); let result = removeSVG.replace(".svg", ""); return result; }, @@ -1038,12 +1048,10 @@ const workspaceFunctions = { }, setWorkspaceFromPrompt(label) { - let iconName = workspaceFunctions.iconFunctions.getIconNameByWorkspaceName( - label - ); - let containerNumber = workspaceFunctions.containerFunctions.getWorkspaceUserContextId( - label - ); + let iconName = + workspaceFunctions.iconFunctions.getIconNameByWorkspaceName(label); + let containerNumber = + workspaceFunctions.containerFunctions.getWorkspaceUserContextId(label); let parentWindow = Services.wm.getMostRecentWindow("navigator:browser"); let object = { workspaceName: label, iconName, containerNumber }; @@ -1266,8 +1274,10 @@ const workspaceFunctions = { `); - let iconElem = window.MozXULElement.parseXULToFragment(``); if (nextElem) { @@ -1278,9 +1288,7 @@ const workspaceFunctions = { .before(workspaceItemElem); } - document - .getElementById(`${label}-button`) - .appendChild(iconElem); + document.getElementById(`${label}-button`).appendChild(iconElem); if ( Services.prefs .getStringPref( @@ -1346,8 +1354,7 @@ const workspaceFunctions = { `; let manageOnBMSIsEnabled = Services.prefs.getBoolPref( - WorkspaceUtils.workspacesPreferences - .WORKSPACE_MANAGE_ON_BMS_PREF + WorkspaceUtils.workspacesPreferences.WORKSPACE_MANAGE_ON_BMS_PREF ); if (manageOnBMSIsEnabled) { @@ -1847,6 +1854,289 @@ const startWorkspace = function () { }); }; +const workspacesMigtation = { + async createBackupFileObject() { + // Migration from floorp to Simple Tab Groups. + // Generate Backup file for Simple Tab Groups. This file is can be used for restore Workspaces & Tabs. + // This file is saved in User's personal desktop directory. + + // Create backup JSON file. + let backupData = { + version: "5.2", + groups: [], + lastCreatedGroupPosition: 3, + defaultGroupProps: {}, + closePopupAfterChangeGroup: true, + closePopupAfterSelectTab: false, + openGroupAfterChange: false, + alwaysAskNewGroupName: true, + createNewGroupWhenOpenNewWindow: false, + openManageGroupsInTab: true, + showConfirmDialogBeforeGroupArchiving: true, + showConfirmDialogBeforeGroupDelete: true, + showNotificationAfterGroupDelete: true, + showContextMenuOnTabs: true, + showContextMenuOnLinks: true, + defaultBookmarksParent: "toolbar_____", + showExtendGroupsPopupWithActiveTabs: false, + showTabsWithThumbnailsInManageGroups: true, + fullPopupWidth: false, + temporaryContainerTitle: "⌚一時的なコンテナー", + contextMenuTab: [ + "open-in-new-window", + "reload", + "discard", + "remove", + "update-thumbnail", + "set-group-icon", + "move-tab-to-group", + ], + contextMenuGroup: [ + "open-in-new-window", + "sort-asc", + "sort-desc", + "discard", + "discard-other", + "export-to-bookmarks", + "unload", + "archive", + "rename", + "reload-all-tabs", + ], + autoBackupEnable: true, + autoBackupLastBackupTimeStamp: 1701171548, + autoBackupIntervalKey: "hours", + autoBackupIntervalValue: 3, + autoBackupIncludeTabThumbnails: false, + autoBackupIncludeTabFavIcons: false, + autoBackupFolderName: "STG-backups-FF-115.6.0", + autoBackupByDayIndex: true, + theme: "auto", + hotkeys: [], + pinnedTabs: [], + containers: {}, + }; + + // Get floorp's Workspaces data. + let allWorkspaces = []; + let usedWorkspacesNumber = []; + + allWorkspaces = Services.prefs + .getStringPref(WorkspaceUtils.workspacesPreferences.WORKSPACE_ALL_PREF) + .split(","); + + for (let i = 0; i < allWorkspaces.length; i++) { + let workspace = allWorkspaces[i]; + + let workspaceIcon = + workspaceFunctions.iconFunctions.getWorkspaceIcon(workspace); + let workspacesContainerNo = + workspaceFunctions.containerFunctions.getWorkspaceUserContextId( + workspace + ); + let workspacesContainerName = ""; + + if (workspacesContainerNo == 0) { + workspacesContainerName = "firefox-default"; + } else { + workspacesContainerName = "firefox-container-" + workspacesContainerNo; + + // Add tabContainerName to usedWorkspacesNumber. + if (!usedWorkspacesNumber.includes(workspacesContainerNo)) { + usedWorkspacesNumber.push(workspacesContainerNo); + } + } + + let workspaceObj = { + id: i + 1, + title: workspace, + iconColor: "hsla(70, 100%, 50%, 1)", + iconUrl: await getBase64DataFromPng(workspaceIcon), + iconViewType: null, + tabs: [], + isArchive: false, + discardTabsAfterHide: false, + discardExcludeAudioTabs: false, + prependTitleToWindow: false, + exportToBookmarksWhenAutoBackup: false, + leaveBookmarksOfClosedTabs: false, + newTabContainer: workspacesContainerName, + ifDifferentContainerReOpen: false, + excludeContainersForReOpen: [], + isSticky: false, + catchTabContainers: [], + catchTabRules: "", + moveToGroupIfNoneCatchTabRules: null, + muteTabsWhenGroupCloseAndRestoreWhenOpen: false, + showTabAfterMovingItIntoThisGroup: false, + showOnlyActiveTabAfterMovingItIntoThisGroup: false, + showNotificationAfterMovingTabIntoThisGroup: true, + bookmarkId: null, + }; + + let allTabs = gBrowser.tabs; + + for (let i = 0; i < allTabs.length; i++) { + let tab = allTabs[i]; + if (tab.getAttribute("floorpWorkspace") == workspace && !tab.pinned) { + let tabTitle = tab.label; + let tabUrl = tab.linkedBrowser.currentURI.spec; + let tabContainerNo = tab.getAttribute("usercontextid"); + let tabContainerName = ""; + if (tabContainerNo == 0 || tabContainerNo == undefined || tabContainerNo == null) { + tabContainerName = "firefox-default"; + } else { + tabContainerName = "firefox-container-" + tabContainerNo; + + // Add tabContainerName to usedWorkspacesNumber. + if (!usedWorkspacesNumber.includes(tabContainerNo)) { + usedWorkspacesNumber.push(tabContainerNo); + } + } + + let tabObj = { + url: tabUrl, + title: tabTitle, + cookieStoreId: tabContainerName, + id: i, + }; + + if (tabObj.cookieStoreId == "firefox-default") { + delete tabObj.cookieStoreId; + } + + workspaceObj.tabs.push(tabObj); + } + } + + // Add workspaceObj to backupData. + backupData.groups.push(workspaceObj); + } + + // Pinned tabs + let tabs = gBrowser.tabs; + for (let i = 0; i < tabs.length; i++) { + let tab = tabs[i]; + if (tab.pinned) { + let tabTitle = tab.label; + let tabUrl = tab.linkedBrowser.currentURI.spec; + let tabContainerNo = tab.getAttribute("usercontextid"); + let tabContainerName = ""; + if (tabContainerNo == 0) { + tabContainerName = "firefox-default"; + } else { + tabContainerName = "firefox-container-" + tabContainerNo; + + // Add tabContainerName to usedWorkspacesNumber. + if (!usedWorkspacesNumber.includes(tabContainerName)) { + usedWorkspacesNumber.push(tabContainerNo); + } + } + + let tabObj = { + url: tabUrl, + title: tabTitle, + cookieStoreId: tabContainerName, + id: i, + }; + + backupData.pinnedTabs.push(tabObj); + } + } + + // Containers Object + let { ContextualIdentityService } = ChromeUtils.importESModule( + "resource://gre/modules/ContextualIdentityService.sys.mjs" + ); + + let containers = ContextualIdentityService.getPublicIdentities(); + + for (let i = 0; i < usedWorkspacesNumber.length; i++) { + let containerNo = usedWorkspacesNumber[i]; + let containerName = "firefox-container-" + containerNo; + + for (let j = 0; j < containers.length; j++) { + let container = containers[j]; + if (containerNo == container.userContextId) { + let containerObj = { + name: containerName, + color: container.color, + icon: container.icon, + iconUrl: "resource://usercontext-content/" + container.icon + ".svg", + colorCode: container.color, + cookieStoreId: containerName, + }; + + backupData.containers[containerName] = containerObj; + } + } + } + + // Write backupData to JSON file. + // Save backupData to JSON file. This file is can be used for restore Workspaces & Tabs. + // Save to Desktop. + let path = PathUtils.join( + Services.dirsvc.get("Desk", Ci.nsIFile).path, + "floorp-workspace-backup.json" + ); + IOUtils.writeJSON(path, backupData); + } +}; + +async function getBase64DataFromPng(iconURL) { + return new Promise((resolve, reject) => { + let xhr = new XMLHttpRequest(); + + if (iconURL.endsWith(".png")) { + xhr.open("GET", iconURL, true); + xhr.responseType = "arraybuffer"; + + xhr.onload = function () { + if (xhr.status == 200) { + let imgData = new Uint8Array(xhr.response); + let base64Data = arrayBufferToBase64(imgData); + let imageDataUri = "data:image/png;base64," + base64Data; + + resolve(imageDataUri); + } else { + reject(new Error("Failed to fetch PNG image")); + } + }; + + xhr.send(); + + function arrayBufferToBase64(buffer) { + var binary = ""; + var bytes = new Uint8Array(buffer); + var len = bytes.byteLength; + for (var i = 0; i < len; i++) { + binary += String.fromCharCode(bytes[i]); + } + return btoa(binary); + } + } else { + xhr.open("GET", iconURL, true); + xhr.onreadystatechange = function () { + if (xhr.readyState == 4) { + if (xhr.status == 200) { + let svgData = xhr.responseText; + + let base64Data = btoa(svgData); + let imageDataUri = "data:image/svg+xml;base64," + base64Data; + + resolve(imageDataUri); + } else { + reject(new Error("Failed to fetch SVG image")); + } + } + }; + + xhr.send(); + } + }); +} + + // If you want to enable workspaces by default, Remove these lines. "checkTabGroupAddonInstalledAndStartWorkspace();" is enough. const tempDisabled = "floorp.browser.workspaces.disabledBySystem"; function disableWorkspacesByDefaultCheck() { @@ -1875,3 +2165,8 @@ function disableWorkspacesByDefaultCheck() { } disableWorkspacesByDefaultCheck(); + +Services.obs.addObserver( + workspacesMigtation.createBackupFileObject, + "migrationFromFloorpToSTG" +); diff --git a/browser/themes/icons/workspace-icons/briefcase.svg b/browser/themes/icons/workspace-icons/briefcase.svg index c49d49e2..bb7d828e 100644 --- a/browser/themes/icons/workspace-icons/briefcase.svg +++ b/browser/themes/icons/workspace-icons/briefcase.svg @@ -3,7 +3,7 @@ - + diff --git a/browser/themes/icons/workspace-icons/cart.svg b/browser/themes/icons/workspace-icons/cart.svg index 12fcee73..b3803de7 100644 --- a/browser/themes/icons/workspace-icons/cart.svg +++ b/browser/themes/icons/workspace-icons/cart.svg @@ -3,7 +3,7 @@ - + diff --git a/browser/themes/icons/workspace-icons/chill.svg b/browser/themes/icons/workspace-icons/chill.svg index 97dba3e4..c080bde0 100644 --- a/browser/themes/icons/workspace-icons/chill.svg +++ b/browser/themes/icons/workspace-icons/chill.svg @@ -3,7 +3,7 @@ - + diff --git a/browser/themes/icons/workspace-icons/circle.svg b/browser/themes/icons/workspace-icons/circle.svg index b7e13011..4c37eb05 100644 --- a/browser/themes/icons/workspace-icons/circle.svg +++ b/browser/themes/icons/workspace-icons/circle.svg @@ -3,7 +3,7 @@ - + diff --git a/browser/themes/icons/workspace-icons/compass.svg b/browser/themes/icons/workspace-icons/compass.svg index b3404b6f..7faddae4 100644 --- a/browser/themes/icons/workspace-icons/compass.svg +++ b/browser/themes/icons/workspace-icons/compass.svg @@ -3,7 +3,7 @@ - + diff --git a/browser/themes/icons/workspace-icons/dollar.svg b/browser/themes/icons/workspace-icons/dollar.svg index dade5cdb..d5c59eb2 100644 --- a/browser/themes/icons/workspace-icons/dollar.svg +++ b/browser/themes/icons/workspace-icons/dollar.svg @@ -3,7 +3,7 @@ - + diff --git a/browser/themes/icons/workspace-icons/fence.svg b/browser/themes/icons/workspace-icons/fence.svg index 48a4b447..1e01b3dd 100644 --- a/browser/themes/icons/workspace-icons/fence.svg +++ b/browser/themes/icons/workspace-icons/fence.svg @@ -3,7 +3,7 @@ - + diff --git a/browser/themes/icons/workspace-icons/fingerprint.svg b/browser/themes/icons/workspace-icons/fingerprint.svg index a0e1178b..0b311be0 100644 --- a/browser/themes/icons/workspace-icons/fingerprint.svg +++ b/browser/themes/icons/workspace-icons/fingerprint.svg @@ -3,7 +3,7 @@ - + diff --git a/browser/themes/icons/workspace-icons/food.svg b/browser/themes/icons/workspace-icons/food.svg index d91a15dd..dac4f996 100644 --- a/browser/themes/icons/workspace-icons/food.svg +++ b/browser/themes/icons/workspace-icons/food.svg @@ -3,7 +3,7 @@ - + diff --git a/browser/themes/icons/workspace-icons/fruit.svg b/browser/themes/icons/workspace-icons/fruit.svg index f33e0fc5..e0952cee 100644 --- a/browser/themes/icons/workspace-icons/fruit.svg +++ b/browser/themes/icons/workspace-icons/fruit.svg @@ -3,7 +3,7 @@ - + diff --git a/browser/themes/icons/workspace-icons/gear.svg b/browser/themes/icons/workspace-icons/gear.svg index 76cadc07..b18eb2f2 100644 --- a/browser/themes/icons/workspace-icons/gear.svg +++ b/browser/themes/icons/workspace-icons/gear.svg @@ -3,7 +3,7 @@ - + diff --git a/browser/themes/icons/workspace-icons/gift.svg b/browser/themes/icons/workspace-icons/gift.svg index 357b4cca..e597a43d 100644 --- a/browser/themes/icons/workspace-icons/gift.svg +++ b/browser/themes/icons/workspace-icons/gift.svg @@ -3,7 +3,7 @@ - + diff --git a/browser/themes/icons/workspace-icons/pet.svg b/browser/themes/icons/workspace-icons/pet.svg index 2c8f46a7..e9945996 100644 --- a/browser/themes/icons/workspace-icons/pet.svg +++ b/browser/themes/icons/workspace-icons/pet.svg @@ -3,7 +3,7 @@ - + diff --git a/browser/themes/icons/workspace-icons/question.svg b/browser/themes/icons/workspace-icons/question.svg index 5ef26f8c..24863e27 100644 --- a/browser/themes/icons/workspace-icons/question.svg +++ b/browser/themes/icons/workspace-icons/question.svg @@ -3,7 +3,7 @@ - + diff --git a/browser/themes/icons/workspace-icons/star.svg b/browser/themes/icons/workspace-icons/star.svg index 469291ae..17aa0d4d 100644 --- a/browser/themes/icons/workspace-icons/star.svg +++ b/browser/themes/icons/workspace-icons/star.svg @@ -3,7 +3,7 @@ - + diff --git a/browser/themes/icons/workspace-icons/tree.svg b/browser/themes/icons/workspace-icons/tree.svg index 40a4c9c0..f093690f 100644 --- a/browser/themes/icons/workspace-icons/tree.svg +++ b/browser/themes/icons/workspace-icons/tree.svg @@ -3,7 +3,7 @@ - + diff --git a/browser/themes/icons/workspace-icons/vacation.svg b/browser/themes/icons/workspace-icons/vacation.svg index 97310ab5..4fb0821f 100644 --- a/browser/themes/icons/workspace-icons/vacation.svg +++ b/browser/themes/icons/workspace-icons/vacation.svg @@ -3,7 +3,7 @@ - +