diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000000..5285e53904 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,26 @@ +version: 2.1 + +setup: true + +orbs: + continuation: circleci/continuation@0.1.2 + droidian-buildd: droidian-releng/droidian-buildd-orb@volatile + +jobs: + setup: + executor: continuation/default + resource_class: small + steps: + - droidian-buildd/checkout + - droidian-buildd/generate + - continuation/continue: + configuration_path: generated_config.yml + +workflows: + setup: + jobs: + - setup: + filters: + tags: + only: /^droidian\/.*\/.*/ + diff --git a/app/main.main.ts b/app/main.main.ts index a906a6beb0..71b7c7d033 100644 --- a/app/main.main.ts +++ b/app/main.main.ts @@ -7,6 +7,7 @@ import * as os from 'node:os'; import fsExtra from 'fs-extra'; import { randomBytes } from 'node:crypto'; import { createParser } from 'dashdash'; +import dbus from 'dbus-native'; import fastGlob from 'fast-glob'; import PQueue from 'p-queue'; @@ -81,21 +82,10 @@ import * as bounce from '../ts/services/bounce.main.js'; import * as updater from '../ts/updater/index.main.js'; import { updateDefaultSession } from './updateDefaultSession.main.js'; import { PreventDisplaySleepService } from './PreventDisplaySleepService.std.js'; -import { - SystemTrayService, - focusAndForceToTop, -} from './SystemTrayService.main.js'; import { SystemTraySettingCache } from './SystemTraySettingCache.node.js'; import { OptionalResourceService } from './OptionalResourceService.main.js'; import { EmojiService } from './EmojiService.main.js'; import { - SystemTraySetting, - shouldMinimizeToSystemTray, - parseSystemTraySetting, -} from '../ts/types/SystemTraySetting.std.js'; -import { - getDefaultSystemTraySetting, - isSystemTraySupported, isContentProtectionEnabledByDefault, } from '../ts/types/Settings.std.js'; import * as ephemeralConfig from './ephemeral_config.main.js'; @@ -177,6 +167,47 @@ function getMainWindow() { return mainWindow; } +function setupDbus() { + const sessionBus = dbus.sessionBus(); + + if (!sessionBus) { + log.error('Could not connect to D-Bus session bus.'); + return; + } + + const serviceName = 'org.signal.Signal'; + const objectPath = '/org/signal/Signal'; + const interfaceName = 'org.signal.Signal'; + + sessionBus.requestName(serviceName, 0x4, (err, retCode) => { + if (err) { + log.error('Failed to request D-Bus name:', err); + return; + } + if (retCode !== 1) { + log.error('D-Bus name already taken.'); + return; + } + + const obj = { + 'org.signal.Signal': { + ShowWindow(callback: () => void) { + showWindow(); + }, + }, + }; + + sessionBus.exportInterface(obj['org.signal.Signal'], objectPath, { + name: interfaceName, + methods: { + ShowWindow: ['', '', [], []], + }, + signals: {}, + properties: {}, + }); + }); +} + const development = getEnvironment() === Environment.Development || getEnvironment() === Environment.Staging; @@ -244,15 +275,7 @@ function showWindow() { return; } - // Using focus() instead of show() seems to be important on Windows when our window - // has been docked using Aero Snap/Snap Assist. A full .show() call here will cause - // the window to reposition: - // https://github.com/signalapp/Signal-Desktop/issues/1429 - if (mainWindow.isVisible()) { - focusAndForceToTop(mainWindow); - } else { - mainWindow.show(); - } + mainWindow.show(); } if (!process.mas) { @@ -263,20 +286,7 @@ if (!process.mas) { app.exit(); } else { app.on('second-instance', (_e: Electron.Event, argv: Array) => { - // Workaround to let AllowSetForegroundWindow succeed. - // See https://www.npmjs.com/package/@signalapp/windows-dummy-keystroke for a full explanation of why this is needed. - if (OS.isWindows()) { - sendDummyKeystroke(); - } - - // Someone tried to run a second instance, we should focus our window - if (mainWindow) { - if (mainWindow.isMinimized()) { - mainWindow.restore(); - } - - showWindow(); - } + showWindow(); const route = maybeGetIncomingSignalRoute(argv); if (route != null) { @@ -416,12 +426,6 @@ const zoomFactorService = new ZoomFactorService({ }, }); -let systemTrayService: SystemTrayService | undefined; -const systemTraySettingCache = new SystemTraySettingCache( - ephemeralConfig, - process.argv -); - const windowFromUserConfig = userConfig.get('window'); const windowFromEphemeral = ephemeralConfig.get('window'); export const windowConfigSchema = z.object({ @@ -635,14 +639,7 @@ if (OS.isWindows()) { windowIcon = join(__dirname, '../build/icons/png/512x512.png'); } -// The titlebar is hidden on: -// - Windows < 10 (7, 8) -// - macOS (but no custom titlebar is displayed, see -// `--title-bar-drag-area-height` in `stylesheets/_titlebar.scss` -const mainTitleBarStyle = OS.isMacOS() - ? ('hidden' as const) - : ('default' as const); - +const mainTitleBarStyle = 'hidden' as const; const nonMainTitleBarStyle = 'default' as const; async function safeLoadURL(window: BrowserWindow, url: string): Promise { @@ -691,21 +688,13 @@ async function createWindow() { ? Math.min(windowConfig.height, maxHeight) : DEFAULT_HEIGHT; - const [systemTraySetting, backgroundColor, spellcheck] = await Promise.all([ - systemTraySettingCache.get(), + const [backgroundColor, spellcheck] = await Promise.all([ isTestEnvironment(getEnvironment()) ? '#ffffff' // Tests should always be rendered on a white background : getBackgroundColor(), getSpellCheckSetting(), ]); - const startInTray = - isTestEnvironment(getEnvironment()) || - systemTraySetting === SystemTraySetting.MinimizeToAndStartInSystemTray; - - const shouldShowWindow = - !app.getLoginItemSettings().wasOpenedAsHidden && !startInTray; - const windowOptions: Electron.BrowserWindowConstructorOptions = { show: false, width, @@ -787,15 +776,8 @@ async function createWindow() { getResolvedMessagesLocale().i18n, log ); - if (!startInTray && windowConfig && windowConfig.maximized) { - mainWindow.maximize(); - } - if (!startInTray && windowConfig && windowConfig.fullscreen) { - mainWindow.setFullScreen(true); - } - if (systemTrayService) { - systemTrayService.setMainWindow(mainWindow); - } + + setupDbus(); function saveWindowStats() { if (!windowConfig) { @@ -871,113 +853,13 @@ async function createWindow() { readyForShutdown: windowState.readyForShutdown(), shouldQuit: windowState.shouldQuit(), }); - // If the application is terminating, just do the default - if ( - isTestEnvironment(getEnvironment()) || - (windowState.readyForShutdown() && windowState.shouldQuit()) - ) { - return; - } - // Prevent the shutdown e.preventDefault(); // Disable media playback mainWindow.webContents.send('set-media-playback-disabled', true); - // In certain cases such as during an active call, we ask the user to confirm close - // which includes shutdown, clicking X on MacOS or closing to tray. - let shouldClose = true; - try { - shouldClose = await maybeRequestCloseConfirmation(); - } catch (error) { - log.warn( - 'Error while requesting close confirmation.', - Errors.toLogFormat(error) - ); - } - if (!shouldClose) { - updater.onRestartCanceled(); - return; - } - - /** - * if the user is in fullscreen mode and closes the window, not the - * application, we need them leave fullscreen first before closing it to - * prevent a black screen. - * Also check for mainWindow because it might become undefined while - * waiting for close confirmation. - * - * issue: https://github.com/signalapp/Signal-Desktop/issues/4348 - */ - if (mainWindow) { - if (mainWindow.isFullScreen()) { - mainWindow.once('leave-full-screen', () => mainWindow?.hide()); - mainWindow.setFullScreen(false); - } else { - mainWindow.hide(); - } - } - - // On Mac, or on other platforms when the tray icon is in use, the window - // should be only hidden, not closed, when the user clicks the close button - const usingTrayIcon = shouldMinimizeToSystemTray( - await systemTraySettingCache.get() - ); - if ( - mainWindow && - !windowState.shouldQuit() && - (usingTrayIcon || OS.isMacOS()) - ) { - if (!usingTrayIcon) { - return; - } - - const shownTrayNotice = ephemeralConfig.get('shown-tray-notice'); - if (shownTrayNotice) { - log.info('close: not showing tray notice'); - return; - } - - ephemeralConfig.set('shown-tray-notice', true); - log.info('close: showing tray notice'); - - if (OS.isWindows()) { - showWindowsNotification({ - type: NotificationType.MinimizedToTray, - token: 'unused', - heading: getResolvedMessagesLocale().i18n( - 'icu:minimizeToTrayNotification--title' - ), - body: getResolvedMessagesLocale().i18n( - 'icu:minimizeToTrayNotification--body' - ), - }); - return; - } - - const n = new Notification({ - title: getResolvedMessagesLocale().i18n( - 'icu:minimizeToTrayNotification--title' - ), - body: getResolvedMessagesLocale().i18n( - 'icu:minimizeToTrayNotification--body' - ), - }); - - n.show(); - return; - } - - // Persist pending window settings to ephemeralConfig - debouncedSaveStats.flush(); - - windowState.markRequestedShutdown(); - await requestShutdown(); - windowState.markReadyForShutdown(); - - await sql.close(); - app.quit(); + mainWindow.hide(); }); // Emitted when the window is closed. @@ -990,9 +872,6 @@ async function createWindow() { if (settingsChannel) { settingsChannel.setMainWindow(mainWindow); } - if (systemTrayService) { - systemTrayService.setMainWindow(mainWindow); - } }); mainWindow.on('enter-full-screen', () => { @@ -1031,10 +910,7 @@ async function createWindow() { mainWindow.webContents.send('ci:event', 'db-initialized', {}); - if (shouldShowWindow) { - log.info('showing main window'); - mainWindow.show(); - } + mainWindow.show(); }; if (OS.isLinux() && OS.isWaylandEnabled()) { @@ -1998,23 +1874,7 @@ function loadPreferredSystemLocales(): Array { } async function getDefaultLoginItemSettings(): Promise { - if (!OS.isWindows()) { - return {}; - } - - const systemTraySetting = await systemTraySettingCache.get(); - if ( - systemTraySetting !== SystemTraySetting.MinimizeToSystemTray && - // This is true when we just started with `--start-in-tray` - systemTraySetting !== SystemTraySetting.MinimizeToAndStartInSystemTray - ) { - return {}; - } - - // The effect of this is that if both auto-launch and minimize to system tray - // are enabled on Windows - we will start the app in tray automatically, - // letting the Desktop shortcuts still start the Signal not in tray. - return { args: ['--start-in-tray'] }; + return {}; } // Signal doesn't really use media keys so we set this switch here to unblock @@ -2100,55 +1960,11 @@ app.on('ready', async () => { sqlInitPromise = initializeSQL(userDataPath); - // First run: configure Signal to minimize to tray. Additionally, on Windows - // enable auto-start with start-in-tray so that starting from a Desktop icon - // would still show the window. - // (User can change these settings later) - if ( - isSystemTraySupported(OS) && - (await systemTraySettingCache.get()) === SystemTraySetting.Uninitialized - ) { - const newValue = getDefaultSystemTraySetting(OS, app.getVersion()); - log.info(`app.ready: setting system-tray-setting to ${newValue}`); - systemTraySettingCache.set(newValue); - - ephemeralConfig.set('system-tray-setting', newValue); - - if (OS.isWindows()) { - log.info('app.ready: enabling open at login'); - app.setLoginItemSettings({ - ...(await getDefaultLoginItemSettings()), - openAtLogin: true, - }); - } - } - const startTime = Date.now(); settingsChannel = new SettingsChannel(); settingsChannel.install(); - settingsChannel.on('change:systemTraySetting', async rawSystemTraySetting => { - const { openAtLogin } = app.getLoginItemSettings( - await getDefaultLoginItemSettings() - ); - - const systemTraySetting = parseSystemTraySetting(rawSystemTraySetting); - systemTraySettingCache.set(systemTraySetting); - - if (systemTrayService) { - const isEnabled = shouldMinimizeToSystemTray(systemTraySetting); - systemTrayService.setEnabled(isEnabled); - } - - // Default login item settings might have changed, so update the object. - log.info('refresh-auto-launch: new value', openAtLogin); - app.setLoginItemSettings({ - ...(await getDefaultLoginItemSettings()), - openAtLogin, - }); - }); - settingsChannel.on( 'ephemeral-setting-changed', sendPreferencesChangedEventToWindows @@ -2261,6 +2077,7 @@ app.on('ready', async () => { nodeIntegration: false, sandbox: true, contextIsolation: true, + backgroundThrottling: false, preload: join(__dirname, '../bundles/loading/preload.preload.js'), }, icon: windowIcon, @@ -2347,14 +2164,6 @@ app.on('ready', async () => { setupMenu(); - systemTrayService = new SystemTrayService({ - i18n: resolvedTranslationsLocale.i18n, - }); - systemTrayService.setMainWindow(mainWindow); - systemTrayService.setEnabled( - shouldMinimizeToSystemTray(await systemTraySettingCache.get()) - ); - await ensureFilePermissions([ 'config.json', 'sql/db.sqlite', @@ -2556,7 +2365,6 @@ app.on('before-quit', e => { ...getWindowDebugInfo(), }); - systemTrayService?.markShouldQuit(); windowState.markShouldQuit(); }); @@ -2728,12 +2536,6 @@ ipc.on( } ); -ipc.on('update-tray-icon', (_event: Electron.Event, unreadCount: number) => { - if (systemTrayService) { - systemTrayService.setUnreadCount(unreadCount); - } -}); - // Debug Log-related IPC calls ipc.on( diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000000..3d73598b8d --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +signal-desktop (7.35-1) unstable; urgency=medium + + * Initial release. + + -- Cédric Bellegarde Fri, 10 May 2024 19:10:29 +0100 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000000..53ca58dc08 --- /dev/null +++ b/debian/control @@ -0,0 +1,31 @@ +Source: signal-desktop +Section: utils +Priority: optional +Maintainer: Cédric Bellegarde +Rules-Requires-Root: no +Build-Depends: + debhelper-compat (= 13), + build-essential, + nodejs, + npm, + git, + git-lfs, + libnotify4, + libxtst6, + libnss3, + libasound2t64, + libpulse0, + libxss1, + libc6 (>= 2.31), + libgtk-3-0, + libgbm1, + libx11-xcb1 +Standards-Version: 4.6.2 +Homepage: https://github.com/droidian/Signal-Desktop + +Package: signal-desktop +Architecture: any +Depends: + ${shlibs:Depends}, + ${misc:Depends}, +Description: A private messenger for Windows, macOS, and Linux. diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000000..e5df58bdfe --- /dev/null +++ b/debian/rules @@ -0,0 +1,51 @@ +#!/usr/bin/make -f + +# See debhelper(7) (uncomment to enable). +# Output every command that modifies files on the build system. +#export DH_VERBOSE = 1 + + +# See FEATURE AREAS in dpkg-buildflags(1). +#export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +# See ENVIRONMENT in dpkg-buildflags(1). +# Package maintainers to append CFLAGS. +#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic +# Package maintainers to append LDFLAGS. +#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed + +export PATH := /tmp/signal-desktop/node_modules/.bin:$(PATH) + +override_dh_dwz: + +override_dh_shlibdeps: + dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info + + +override_dh_auto_build: + git lfs install + sed 's#"node": "#&>=#' -i package.json + npm install --prefix /tmp/signal-desktop pnpm + pnpm install --dir ./sticker-creator/ + pnpm install + pnpm run build + +override_dh_auto_install: + install -d debian/signal-desktop/usr/bin + install -d debian/signal-desktop/usr/lib + mv release/linux-unpacked debian/signal-desktop/usr/lib/signal-desktop || true + mv release/linux-arm64-unpacked debian/signal-desktop/usr/lib/signal-desktop || true + chmod u+s debian/signal-desktop/usr/lib/signal-desktop/chrome-sandbox + for i in 16 24 32 48 64 128 256 512 1024; do install -Dm 644 "build/icons/png/$${i}x$${i}.png" "debian/signal-desktop/usr/share/icons/hicolor/$${i}x$${i}/apps/signal-desktop.png"; done + install -Dm 644 ./signal-desktop.desktop -t debian/signal-desktop/usr/share/applications + install -Dm 755 ./signal-desktop-mobile -t debian/signal-desktop/usr/bin + +%: + dh $@ + + +# dh_make generated override targets. +# This is an example for Cmake (see ). +#override_dh_auto_configure: +# dh_auto_configure -- \ +# -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000000..163aaf8d82 --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/package.json b/package.json index 633ec1e109..0cf044e5f6 100644 --- a/package.json +++ b/package.json @@ -156,6 +156,7 @@ "country-codes-list": "2.0.0", "credit-card-type": "10.0.2", "dashdash": "2.0.0", + "dbus-native": "0.4.0", "direction": "1.0.4", "dom-accessibility-api": "0.7.0", "emoji-datasource": "16.0.0", @@ -310,7 +311,7 @@ "csv-parse": "5.5.6", "danger": "12.3.3", "debug": "4.3.7", - "electron": "40.4.1", + "electron": "41.0.0", "electron-builder": "26.0.14", "electron-mocha": "13.0.1", "endanger": "7.0.4", @@ -527,7 +528,7 @@ }, "artifactName": "${name}_${version}_${arch}.${ext}", "target": [ - "deb" + "dir" ], "icon": "build/icons/png", "publish": [ @@ -551,20 +552,6 @@ } ] }, - "deb": { - "depends": [ - "libnotify4", - "libxtst6", - "libnss3", - "libasound2", - "libpulse0", - "libxss1", - "libc6 (>= 2.34)", - "libgtk-3-0", - "libgbm1", - "libx11-xcb1" - ] - }, "protocols": { "name": "sgnl-url-scheme", "schemes": [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c62c130b9e..59af48f035 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -194,6 +194,9 @@ importers: dashdash: specifier: 2.0.0 version: 2.0.0 + dbus-native: + specifier: 0.4.0 + version: 0.4.0 direction: specifier: 1.0.4 version: 1.0.4 @@ -652,8 +655,8 @@ importers: specifier: 4.3.7 version: 4.3.7(supports-color@8.1.1) electron: - specifier: 40.4.1 - version: 40.4.1 + specifier: 41.0.0 + version: 41.0.0 electron-builder: specifier: 26.0.14 version: 26.0.14(electron-builder-squirrel-windows@26.0.14) @@ -3533,6 +3536,9 @@ packages: '@sinonjs/text-encoding@0.7.3': resolution: {integrity: sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==} + deprecated: |- + Deprecated: no longer maintained and no longer used by Sinon packages. See + https://github.com/sinonjs/nise/issues/243 for replacement details. '@storybook/addon-a11y@8.4.4': resolution: {integrity: sha512-xXNOG4Bw/v8rg2Zq/ZJnZSLWfpfkfnZjn0sQVLOe5JcDxavkh5o+WvQ6Tc2w/kK/ophCd7nbTotywrtdQYGNKw==} @@ -4144,11 +4150,8 @@ packages: '@types/node@22.13.4': resolution: {integrity: sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==} - '@types/node@22.19.1': - resolution: {integrity: sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==} - - '@types/node@24.10.9': - resolution: {integrity: sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==} + '@types/node@24.11.0': + resolution: {integrity: sha512-fPxQqz4VTgPI/IQ+lj9r0h+fDR66bzoeMGHp8ASee+32OSGIkeASsoZuJixsQoVef1QJbeubcPBxKk22QVoWdw==} '@types/normalize-path@3.0.2': resolution: {integrity: sha512-DO++toKYPaFn0Z8hQ7Tx+3iT9t77IJo/nDiqTXilgEP+kPNIYdpS9kh3fXuc53ugqwp9pxC1PVjCpV1tQDyqMA==} @@ -4497,6 +4500,12 @@ packages: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} + abstract-socket@2.1.1: + resolution: {integrity: sha512-YZJizsvS1aBua5Gd01woe4zuyYBGgSMeqDOB6/ChwdTI904KP6QGtJswXl4hcqWxbz86hQBe++HWV0hF1aGUtA==} + engines: {node: '>=4.0.0'} + os: [linux] + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} @@ -4836,6 +4845,7 @@ packages: basic-ftp@5.0.5: resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} engines: {node: '>=10.0.0'} + deprecated: Security vulnerability fixed in 5.2.0, please upgrade batch@0.6.1: resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} @@ -5514,6 +5524,10 @@ packages: resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} + dbus-native@0.4.0: + resolution: {integrity: sha512-i3zvY3tdPEOaMgmK4riwupjDYRJ53rcE1Kj8rAgnLOFmBd0DekUih59qv8v+Oyils/U9p+s4sSsaBzHWLztI+Q==} + hasBin: true + debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -5800,6 +5814,9 @@ packages: duplexer3@0.1.5: resolution: {integrity: sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==} + duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + duplexify@4.1.3: resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==} @@ -5848,8 +5865,8 @@ packages: engines: {node: '>= 12.20.55'} hasBin: true - electron@40.4.1: - resolution: {integrity: sha512-N1ZXybQZL8kYemO8vAeh9nrk4mSvqlAO8xs0QCHkXIvRnuB/7VGwEehjvQbsU5/f4bmTKpG+2GQERe/zmKpudQ==} + electron@41.0.0: + resolution: {integrity: sha512-U7QueSj1cFj9QM0Qamgh/MK08662FVK555iMfapqU7mcAmIm4A8bZuZptpjMXrT4JNAMGjgWu9sOeO1+RPCJNw==} engines: {node: '>= 12.20.55'} hasBin: true @@ -6226,6 +6243,9 @@ packages: event-emitter@0.3.5: resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==} + event-stream@4.0.1: + resolution: {integrity: sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==} + event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} @@ -6487,6 +6507,9 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + from@0.1.7: + resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} + fromentries@1.3.2: resolution: {integrity: sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==} @@ -6781,6 +6804,10 @@ packages: resolution: {integrity: sha512-NU+zsiDvdL+EebyTjrEqjkO2XYI7FgLhQzsbmO8dnnYce3S0PBSDm/ZyI4KpcGPXYEdb5W72vp/AQFuc4F8ASg==} engines: {node: '>=8.0.0'} + hexy@0.2.11: + resolution: {integrity: sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==} + hasBin: true + hey-listen@1.0.8: resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==} @@ -7881,6 +7908,9 @@ packages: resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} engines: {node: '>= 0.6.0'} + long@4.0.0: + resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} + long@5.2.3: resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} @@ -7968,6 +7998,9 @@ packages: map-or-similar@1.5.0: resolution: {integrity: sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==} + map-stream@0.0.7: + resolution: {integrity: sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==} + markdown-it-anchor@8.6.7: resolution: {integrity: sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==} peerDependencies: @@ -8192,6 +8225,9 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + minimist@0.0.10: + resolution: {integrity: sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==} + minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -8285,6 +8321,9 @@ packages: mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nan@2.25.0: + resolution: {integrity: sha512-0M90Ag7Xn5KMLLZ7zliPWP3rT90P6PN+IzVFS0VqmnPktBk3700xUVv8Ikm9EUaUE5SDWdp/BIxdENzVznpm1g==} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -8513,6 +8552,9 @@ packages: resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} hasBin: true + optimist@0.6.1: + resolution: {integrity: sha512-snN4O4TkigujZphWLN0E//nQmm7790RYaE53DdL7ZYwee2D8DDo9/EyYiKUfN3rneWUjhJnueija3G9I2i0h3g==} + optionator@0.8.3: resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} engines: {node: '>= 0.8.0'} @@ -8740,6 +8782,9 @@ packages: resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} engines: {node: '>= 14.16'} + pause-stream@0.0.11: + resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} + pe-library@0.4.1: resolution: {integrity: sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==} engines: {node: '>=12', npm: '>=6'} @@ -9096,6 +9141,9 @@ packages: pump@3.0.3: resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + pumpify@2.0.1: resolution: {integrity: sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==} @@ -9113,6 +9161,10 @@ packages: pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + put@0.0.6: + resolution: {integrity: sha512-w0szIZ2NkqznMFqxYPRETCIi+q/S8UKis9F4yOl6/N9NDCZmbjZZT85aI4FgJf3vIPrzMPX60+odCLOaYxNWWw==} + engines: {node: '>=0.3.0'} + qrcode-generator@1.4.4: resolution: {integrity: sha512-HM7yY8O2ilqhmULxGMpcHSF1EhJJ9yBj8gvDEuZ6M+KGJ0YY2hKpnXvRD+hZPLrDVck3ExIGhmPtSdcjC+guuw==} @@ -9605,6 +9657,10 @@ packages: sax@1.4.1: resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} + sax@1.4.4: + resolution: {integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==} + engines: {node: '>=11.0.0'} + scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} @@ -9828,6 +9884,9 @@ packages: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} + split@1.0.1: + resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==} + sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} @@ -9874,6 +9933,9 @@ packages: prettier: optional: true + stream-combiner@0.2.2: + resolution: {integrity: sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==} + stream-shift@1.0.3: resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} @@ -10183,6 +10245,9 @@ packages: through2@2.0.5: resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + thunky@1.1.0: resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==} @@ -10399,9 +10464,6 @@ packages: undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} @@ -10762,6 +10824,10 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wordwrap@0.0.3: + resolution: {integrity: sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==} + engines: {node: '>=0.4.0'} + workerpool@6.5.1: resolution: {integrity: sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==} @@ -10833,9 +10899,17 @@ packages: resolution: {integrity: sha512-1Dly4xqlulvPD3fZUQJLY+FUIeqN3N2MM3uqe4rCJftAvOjFa3jFGfctOgluGx4ahPbUCsZkmJILiP0Vi4T6lQ==} engines: {node: '>=4'} + xml2js@0.4.23: + resolution: {integrity: sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==} + engines: {node: '>=4.0.0'} + xml@1.0.1: resolution: {integrity: sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==} + xmlbuilder@11.0.1: + resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} + engines: {node: '>=4.0'} + xmlbuilder@15.1.1: resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} engines: {node: '>=8.0'} @@ -14421,7 +14495,7 @@ snapshots: '@storybook/builder-webpack5@8.4.4(@swc/core@1.10.16(@swc/helpers@0.5.15))(esbuild@0.25.9)(storybook@8.4.4(bufferutil@4.0.9)(prettier@3.7.4)(utf-8-validate@5.0.10))(typescript@5.6.3)(webpack-cli@5.1.4)': dependencies: '@storybook/core-webpack': 8.4.4(storybook@8.4.4(bufferutil@4.0.9)(prettier@3.7.4)(utf-8-validate@5.0.10)) - '@types/node': 22.19.1 + '@types/node': 22.13.4 '@types/semver': 7.5.8 browser-assert: 1.2.1 case-sensitive-paths-webpack-plugin: 2.4.0 @@ -14478,7 +14552,7 @@ snapshots: '@storybook/core-webpack@8.4.4(storybook@8.4.4(bufferutil@4.0.9)(prettier@3.7.4)(utf-8-validate@5.0.10))': dependencies: - '@types/node': 22.19.1 + '@types/node': 22.13.4 storybook: 8.4.4(bufferutil@4.0.9)(prettier@3.7.4)(utf-8-validate@5.0.10) ts-dedent: 2.2.0 @@ -14523,7 +14597,7 @@ snapshots: '@storybook/core-webpack': 8.4.4(storybook@8.4.4(bufferutil@4.0.9)(prettier@3.7.4)(utf-8-validate@5.0.10)) '@storybook/react': 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(bufferutil@4.0.9)(prettier@3.7.4)(utf-8-validate@5.0.10)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(bufferutil@4.0.9)(prettier@3.7.4)(utf-8-validate@5.0.10))(typescript@5.6.3) '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.6.3)(webpack@5.96.1) - '@types/node': 22.19.1 + '@types/node': 22.13.4 '@types/semver': 7.5.8 find-up: 5.0.0 magic-string: 0.30.17 @@ -15093,11 +15167,7 @@ snapshots: dependencies: undici-types: 6.20.0 - '@types/node@22.19.1': - dependencies: - undici-types: 6.21.0 - - '@types/node@24.10.9': + '@types/node@24.11.0': dependencies: undici-types: 7.16.0 @@ -15542,6 +15612,12 @@ snapshots: dependencies: event-target-shim: 5.0.1 + abstract-socket@2.1.1: + dependencies: + bindings: 1.5.0 + nan: 2.25.0 + optional: true + accepts@1.3.8: dependencies: mime-types: 2.1.35 @@ -16734,6 +16810,18 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.2 + dbus-native@0.4.0: + dependencies: + event-stream: 4.0.1 + hexy: 0.2.11 + long: 4.0.0 + optimist: 0.6.1 + put: 0.0.6 + safe-buffer: 5.2.1 + xml2js: 0.4.23 + optionalDependencies: + abstract-socket: 2.1.1 + debug@2.6.9: dependencies: ms: 2.0.0 @@ -16994,6 +17082,8 @@ snapshots: duplexer3@0.1.5: {} + duplexer@0.1.2: {} + duplexify@4.1.3: dependencies: end-of-stream: 1.4.5 @@ -17087,10 +17177,10 @@ snapshots: transitivePeerDependencies: - supports-color - electron@40.4.1: + electron@41.0.0: dependencies: '@electron/get': 2.0.3 - '@types/node': 24.10.9 + '@types/node': 24.11.0 extract-zip: 2.0.1 transitivePeerDependencies: - supports-color @@ -17741,6 +17831,16 @@ snapshots: d: 1.0.2 es5-ext: 0.10.64 + event-stream@4.0.1: + dependencies: + duplexer: 0.1.2 + from: 0.1.7 + map-stream: 0.0.7 + pause-stream: 0.0.11 + split: 1.0.1 + stream-combiner: 0.2.2 + through: 2.3.8 + event-target-shim@5.0.1: {} eventemitter3@4.0.7: {} @@ -18069,6 +18169,8 @@ snapshots: fresh@0.5.2: {} + from@0.1.7: {} + fromentries@1.3.2: {} fs-exists-sync@0.1.0: {} @@ -18198,7 +18300,7 @@ snapshots: get-stream@5.2.0: dependencies: - pump: 3.0.3 + pump: 3.0.4 get-stream@6.0.1: {} @@ -18418,6 +18520,8 @@ snapshots: dependencies: libheif-js: 1.18.2 + hexy@0.2.11: {} + hey-listen@1.0.8: {} hoist-non-react-statics@3.3.2: @@ -19730,6 +19834,8 @@ snapshots: loglevel@1.9.2: {} + long@4.0.0: {} + long@5.2.3: {} longest-streak@2.0.4: {} @@ -19839,6 +19945,8 @@ snapshots: map-or-similar@1.5.0: {} + map-stream@0.0.7: {} + markdown-it-anchor@8.6.7(@types/markdown-it@14.1.2)(markdown-it@14.1.0): dependencies: '@types/markdown-it': 14.1.2 @@ -20095,6 +20203,8 @@ snapshots: dependencies: brace-expansion: 2.0.1 + minimist@0.0.10: {} + minimist@1.2.8: {} minipass-collect@1.0.2: @@ -20202,6 +20312,9 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 + nan@2.25.0: + optional: true + nanoid@3.3.11: {} nanoid@3.3.8: {} @@ -20452,6 +20565,11 @@ snapshots: opener@1.5.2: {} + optimist@0.6.1: + dependencies: + minimist: 0.0.10 + wordwrap: 0.0.3 + optionator@0.8.3: dependencies: deep-is: 0.1.4 @@ -20689,6 +20807,10 @@ snapshots: pathval@2.0.0: {} + pause-stream@0.0.11: + dependencies: + through: 2.3.8 + pe-library@0.4.1: {} pe-library@1.0.1: {} @@ -20992,6 +21114,11 @@ snapshots: end-of-stream: 1.4.5 once: 1.4.0 + pump@3.0.4: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + pumpify@2.0.1: dependencies: duplexify: 4.1.3 @@ -21006,6 +21133,8 @@ snapshots: pure-rand@6.1.0: {} + put@0.0.6: {} + qrcode-generator@1.4.4(patch_hash=1f10c592d849ed4cfc9f81301196d39857b79240997ef5772138218cb3717e80): {} qs@6.13.0: @@ -21688,6 +21817,8 @@ snapshots: sax@1.4.1: {} + sax@1.4.4: {} + scheduler@0.23.2: dependencies: loose-envify: 1.4.0 @@ -21989,6 +22120,10 @@ snapshots: split2@4.2.0: {} + split@1.0.1: + dependencies: + through: 2.3.8 + sprintf-js@1.0.3: {} sprintf-js@1.1.3: {} @@ -22029,6 +22164,11 @@ snapshots: - supports-color - utf-8-validate + stream-combiner@0.2.2: + dependencies: + duplexer: 0.1.2 + through: 2.3.8 + stream-shift@1.0.3: {} streamsearch@1.1.0: {} @@ -22424,6 +22564,8 @@ snapshots: readable-stream: 2.3.8 xtend: 4.0.2 + through@2.3.8: {} + thunky@1.1.0: {} timed-out@4.0.1: {} @@ -22625,8 +22767,6 @@ snapshots: undici-types@6.20.0: {} - undici-types@6.21.0: {} - undici-types@7.16.0: {} unified@9.2.2: @@ -23090,6 +23230,8 @@ snapshots: word-wrap@1.2.5: {} + wordwrap@0.0.3: {} + workerpool@6.5.1: {} wrap-ansi@5.1.0: @@ -23160,8 +23302,15 @@ snapshots: xdg-basedir@3.0.0: {} + xml2js@0.4.23: + dependencies: + sax: 1.4.4 + xmlbuilder: 11.0.1 + xml@1.0.1: {} + xmlbuilder@11.0.1: {} + xmlbuilder@15.1.1: {} xmlcreate@2.0.4: {} diff --git a/signal-desktop-mobile b/signal-desktop-mobile new file mode 100644 index 0000000000..5350b82ceb --- /dev/null +++ b/signal-desktop-mobile @@ -0,0 +1,3 @@ +#!/bin/sh + +gdbus call -e -d org.signal.Signal -o /org/signal/Signal -m org.signal.Signal.ShowWindow >/dev/null 2>&1|| /usr/lib/signal-desktop/signal-desktop --enable-features=UseOzonePlatform --ozone-platform=wayland --enable-wayland-ime --wayland-text-input-version=3 $@ diff --git a/signal-desktop.desktop b/signal-desktop.desktop new file mode 100644 index 0000000000..424b72e521 --- /dev/null +++ b/signal-desktop.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Type=Application +Name=Signal +Comment=Signal Messenger +Icon=signal-desktop +Exec=/usr/bin/signal-desktop-mobile %u +Terminal=false +Categories=Network;InstantMessaging; +StartupWMClass=signal +MimeType=x-scheme-handler/sgnl;x-scheme-handler/signalcaptcha; +Keywords=sgnl;chat;im;messaging;messenger;security;privat; +X-GNOME-UsesNotifications=true diff --git a/stylesheets/components/Droidian.scss b/stylesheets/components/Droidian.scss new file mode 100644 index 0000000000..6b7af8fbc7 --- /dev/null +++ b/stylesheets/components/Droidian.scss @@ -0,0 +1,135 @@ +.Preferences > .NavSidebar { + &:has(.NavSidebar__Header) { + max-width: 70px !important; + } +} + +.module-ConversationHeader__header { + justify-content: center; +} + +.module-ConversationHeader__button.module-ConversationHeader__button--video { + display: none !important; +} +.module-conversation-list__item--contact-or-conversation__avatar-container { + margin-left: 4px !important; + .module-conversation-list__item--contact-or-conversation__unread-indicator { + margin-right: 4px !important; + } +} +::-webkit-scrollbar { + display: none !important; +} +.module-reaction-viewer { + width: 220px !important; + height: 220px !important; +} +.Preferences__page-selector { + min-width: 48px !important; + padding-top: 0px !important; +} +.Preferences__button { + font-size: 0px !important; + width: 48px !important; +} +.Preferences__profile-chip { + margin-inline-start: 8px !important; + padding-inline-start: 8px !important; +} +.Preferences { + width: 100% !important; +} +.Preferences__control { + flex-direction: column !important; +} +.ConversationDetails-panel-row__root { + flex-direction: column !important; + align-items: stretch !important; +} + +.module-message--incoming { + .module-message__buttons { + opacity: 1 !important; + } +} +.module-sticker-manager__preview-modal__modal.module-Modal { + width: initial !important; +} +.react-contextmenu-submenu { + >.react-contextmenu { + right: 10px !important; + } +} +.module-InstallScreenQrCodeNotScannedStep__contents { + flex-direction: column !important; + top: 44px !important; +} +.module-InstallScreenQrCodeNotScannedStep__qr-code { + margin-inline: 50% !important; +} + +.Lightbox__main-container { + min-height: 100% !important; +} +.Lightbox__zoomable-container { + margin-inline: 0px !important; +} + +.CompositionArea__button-cell:first-child { + margin-inline-start: 5px !important; +} + +.CompositionArea__button-cell { + margin-inline: 1px !important; +} + +.CompositionArea__toggle-large { + display: none; +} + +.NavTabs__Container { + flex-direction: column-reverse !important; +} + +.NavTabs { + height: initial !important; + width: 100% !important; + flex-direction: row !important; +} + +.NavTabs__Item.NavTabs__Toggle { + display: none !important; +} + +.NavTabs__TabList { + display: flex !important; + flex-direction: row !important; +} + +.NavTabs__TabPanel { + overflow: hidden !important; +} + +.CallsTab__EmptyState { + display: none !important; +} + +.CallsTab__ConversationCallDetails { + display: none !important; +} + +.Stories__placeholder { + display: none !important; +} + +.NavSidebar { + width: 100% !important; +} + +.module-tooltip { + display: none !important; +} + +.MediaEditor__tools--input { + width: 150px; +} \ No newline at end of file diff --git a/stylesheets/components/NavSidebar.scss b/stylesheets/components/NavSidebar.scss index ba5f39d483..21540684c4 100644 --- a/stylesheets/components/NavSidebar.scss +++ b/stylesheets/components/NavSidebar.scss @@ -143,37 +143,12 @@ flex-direction: column; } -.NavSidebar__DragHandle { - position: absolute; - z-index: variables.$z-index-above-above-base; - top: 0; - bottom: 0; - inset-inline-start: 100%; - width: 8px; - background: transparent; +.NavSidebar__document--draggingHandle { cursor: col-resize; - // Disable browser handling of gestures so element can be dragged with touch events - touch-action: none; - - &:focus { - outline: none; - @include mixins.keyboard-mode { - box-shadow: inset 0 0 0 2px variables.$color-ultramarine; - } - } } -.NavSidebar__DragHandle--dragging { - @include mixins.light-theme { - background-color: variables.$color-black-alpha-12; - } - @include mixins.dark-theme { - background-color: variables.$color-white-alpha-12; - } -} - -.NavSidebar__document--draggingHandle { - cursor: col-resize; +#LeftPane { + width: 100%; } .NavSidebar__HeaderActions { diff --git a/stylesheets/manifest.scss b/stylesheets/manifest.scss index 953f4987e0..76983e70b7 100644 --- a/stylesheets/manifest.scss +++ b/stylesheets/manifest.scss @@ -203,3 +203,5 @@ @use 'components/UsernameMegaphone.scss'; @use 'components/UsernameOnboardingModal.scss'; @use 'components/WhatsNew.scss'; + +@use 'components/Droidian.scss'; diff --git a/ts/background.preload.ts b/ts/background.preload.ts index 69109b074b..e25394ef92 100644 --- a/ts/background.preload.ts +++ b/ts/background.preload.ts @@ -330,6 +330,8 @@ export async function startApp(): Promise { storage: itemStorage, }); + notificationService.enable(); + await initializeMessageCounter(); // Initialize WebAPI as early as possible @@ -1932,7 +1934,6 @@ export async function startApp(): Promise { onDecryptionErrorQueue.pause(); onRetryRequestQueue.pause(); deliveryReceiptQueue.pause(); - notificationService.disable(); } // 2. After the socket finishes processing any queued messages, restart these queues @@ -1943,7 +1944,6 @@ export async function startApp(): Promise { onDecryptionErrorQueue.start(); onRetryRequestQueue.start(); deliveryReceiptQueue.start(); - notificationService.enable(); } function isSocketOnline() { diff --git a/ts/components/ChatsTab.dom.tsx b/ts/components/ChatsTab.dom.tsx index 636acc4826..62ec8d6152 100644 --- a/ts/components/ChatsTab.dom.tsx +++ b/ts/components/ChatsTab.dom.tsx @@ -42,45 +42,31 @@ export function ChatsTab({ }: ChatsTabProps): React.JSX.Element { return ( <> -
- {renderLeftPane({ - otherTabsUnreadStats, - collapsed: navTabsCollapsed, - hasPendingUpdate, - hasFailedStorySends, - onToggleCollapse: onToggleNavTabsCollapse, - })} -
+ + {!selectedConversationId && +
+ {renderLeftPane({ + otherTabsUnreadStats, + hasPendingUpdate, + hasFailedStorySends, + onToggleCollapse: onToggleNavTabsCollapse, + })} +
+ } + + {selectedConversationId &&
- {selectedConversationId ? ( -
- {renderConversationView({ selectedConversationId })} -
- ) : ( -
- {renderMiniPlayer({ shouldFlow: false })} -
-

- {isStaging - ? 'THIS IS A STAGING DESKTOP' - : i18n('icu:welcomeToSignal')} -

-

- -

-
-
- {i18n('icu:signalNonProfit')} -
-
- )} +
+ {renderConversationView({ selectedConversationId })} +
+ } ); } diff --git a/ts/components/CompositionArea.dom.tsx b/ts/components/CompositionArea.dom.tsx index f9dc0d340e..a077ea0589 100644 --- a/ts/components/CompositionArea.dom.tsx +++ b/ts/components/CompositionArea.dom.tsx @@ -456,6 +456,10 @@ export const CompositionArea = memo(function CompositionArea({ } }, []); + const launchRecorder = useCallback(() => { + startRecording(conversationId); + }, []); + const launchMediaPicker = useCallback( () => launchAttachmentPicker('media'), [launchAttachmentPicker] @@ -785,18 +789,6 @@ export const CompositionArea = memo(function CompositionArea({ ); - const micButtonFragment = shouldShowMicrophone ? ( -
- -
- ) : null; - const editMessageFragment = draftEditMessage ? ( <> {large &&
} @@ -839,6 +831,9 @@ export const CompositionArea = memo(function CompositionArea({
+ + {i18n('icu:Keyboard--begin-recording-voice-note')} + {i18n('icu:CompositionArea__AttachMenu__PhotosAndVideos')} @@ -1287,7 +1282,6 @@ export const CompositionArea = memo(function CompositionArea({ )} {!isViewOnceActive && !large && ( <> - {!dirty ? micButtonFragment : null} {editMessageFragment} {composerAddMenuButton} @@ -1302,7 +1296,6 @@ export const CompositionArea = memo(function CompositionArea({ > {leftHandSideButtonsFragment} {composerAddMenuButton} - {!dirty ? micButtonFragment : null} {editMessageFragment} {dirty || !shouldShowMicrophone ? sendButtonFragment : null}
diff --git a/ts/components/MediaEditor.dom.tsx b/ts/components/MediaEditor.dom.tsx index fad8cc12f2..83c32bb4fb 100644 --- a/ts/components/MediaEditor.dom.tsx +++ b/ts/components/MediaEditor.dom.tsx @@ -810,7 +810,7 @@ export function MediaEditor({ }); rect.on('deselected', () => { - setEditMode(undefined); + fabricCanvas.setActiveObject(rect); }); fabricCanvas.add(rect); diff --git a/ts/components/NavSidebar.dom.tsx b/ts/components/NavSidebar.dom.tsx index 42e3b9829e..14cc780d56 100644 --- a/ts/components/NavSidebar.dom.tsx +++ b/ts/components/NavSidebar.dom.tsx @@ -88,159 +88,61 @@ export function NavSidebar({ renderToastManager, }: NavSidebarProps): React.JSX.Element { const isRTL = i18n.getLocaleDirection() === 'rtl'; - const [dragState, setDragState] = useState(DragState.INITIAL); - - const [preferredWidth, setPreferredWidth] = useState(() => { - return getWidthFromPreferredWidth(preferredLeftPaneWidth, { - requiresFullWidth, - }); - }); - - const width = getWidthFromPreferredWidth(preferredWidth, { - requiresFullWidth, - }); - - const widthBreakpoint = getNavSidebarWidthBreakpoint(width); - - const expandNarrowLeftPane = useCallback(() => { - if (preferredWidth < MIN_FULL_WIDTH) { - setPreferredWidth(MIN_FULL_WIDTH); - savePreferredLeftPaneWidth(MIN_FULL_WIDTH); - } - }, [preferredWidth, savePreferredLeftPaneWidth]); - - // `useMove` gives us keyboard and mouse dragging support. - const { moveProps } = useMove({ - onMoveStart() { - setDragState(DragState.DRAGGING); - }, - onMoveEnd() { - setDragState(DragState.DRAGEND); - }, - onMove(event) { - const { shiftKey, pointerType } = event; - const deltaX = isRTL ? -event.deltaX : event.deltaX; - const isKeyboard = pointerType === 'keyboard'; - const increment = isKeyboard && shiftKey ? 10 : 1; - setPreferredWidth(prevWidth => { - // Jump minimize for keyboard users - if (isKeyboard && prevWidth === MIN_FULL_WIDTH && deltaX < 0) { - return MIN_WIDTH; - } - // Jump maximize for keyboard users - if (isKeyboard && prevWidth === MIN_WIDTH && deltaX > 0) { - return MIN_FULL_WIDTH; - } - return prevWidth + deltaX * increment; - }); - }, - }); - - useEffect(() => { - // Save the preferred width when the drag ends. We can't do this in onMoveEnd - // because the width is not updated yet. - if (dragState === DragState.DRAGEND) { - setPreferredWidth(width); - savePreferredLeftPaneWidth(width); - setDragState(DragState.INITIAL); - } - }, [ - dragState, - preferredLeftPaneWidth, - preferredWidth, - savePreferredLeftPaneWidth, - width, - ]); - - useEffect(() => { - // This effect helps keep the pointer `col-resize` even when you drag past the handle. - const className = 'NavSidebar__document--draggingHandle'; - if (dragState === DragState.DRAGGING) { - document.body.classList.add(className); - return () => { - document.body.classList.remove(className); - }; - } - return undefined; - }, [dragState]); return ( - -
- {!hideHeader && ( -
- {onBack == null && navTabsCollapsed && ( - +
+ {!hideHeader && ( +
+ {onBack == null && navTabsCollapsed && ( + + )} +
+ {onBack != null && ( + )} -
- {onBack != null && ( - - )} -

- {title} -

- {actions && ( -
{actions}
- )} -
+ {title} + + {actions && ( +
{actions}
+ )}
- )} +
+ )} -
{children}
+
{children}
-
- - {renderToastManager({ - containerWidthBreakpoint: widthBreakpoint, - expandNarrowLeftPane, - })} -
- + {renderToastManager({ containerWidthBreakpoint: 400 })} +
); } diff --git a/ts/components/Preferences.dom.tsx b/ts/components/Preferences.dom.tsx index 8f68574263..c5afb4ad9d 100644 --- a/ts/components/Preferences.dom.tsx +++ b/ts/components/Preferences.dom.tsx @@ -2338,7 +2338,7 @@ export function Preferences({
{ formats: this.props.formats, modules: this.props.modules, placeholder: this.props.placeholder, - readOnly: this.props.readOnly, + readOnly: true }); } @@ -71,10 +71,24 @@ export class SimpleQuillWrapper extends React.Component { return this.quill; } + handleClick = () => { + const el = this.quillElement.current; + if (el) { + el.removeAttribute('inert'); + } + // Focus the Quill editor programmatically + if (this.quill) { + this.quill.focus(); + } + }; + override render(): React.JSX.Element { return ( -
-
+
+
); } diff --git a/ts/components/conversation/ConversationHeader.dom.tsx b/ts/components/conversation/ConversationHeader.dom.tsx index dbec843b98..190ba4de33 100644 --- a/ts/components/conversation/ConversationHeader.dom.tsx +++ b/ts/components/conversation/ConversationHeader.dom.tsx @@ -12,6 +12,7 @@ import { } from '../../hooks/useKeyboardShortcuts.dom.js'; import { SizeObserver } from '../../hooks/useSizeObserver.dom.js'; import type { ConversationTypeType } from '../../state/ducks/conversations.preload.js'; +import { showConversation } from '../../state/ducks/conversations.preload.js'; import type { HasStories } from '../../types/Stories.std.js'; import type { LocalizerType, ThemeType } from '../../types/Util.std.js'; import type { DurationInSeconds } from '../../util/durations/index.std.js'; @@ -53,6 +54,8 @@ import type { } from '../../state/selectors/timeline.preload.js'; import { tw } from '../../axo/tw.dom.js'; +import { useDispatch } from 'react-redux'; + function HeaderInfoTitle({ name, title, @@ -483,6 +486,11 @@ function HeaderContent({ onViewUserStories: () => void; onViewConversationDetails: () => void; }) { + const dispatch = useDispatch(); + const onBackButton = () => { + dispatch(showConversation({ conversationId: undefined })); + }; + let onClick: undefined | (() => void); const { type } = conversation; switch (type) { @@ -556,6 +564,13 @@ function HeaderContent({ if (onClick) { return ( + <> +
+ ); } diff --git a/ts/components/fun/base/FunSearch.dom.tsx b/ts/components/fun/base/FunSearch.dom.tsx index 6f0cb1b873..f15ce63e21 100644 --- a/ts/components/fun/base/FunSearch.dom.tsx +++ b/ts/components/fun/base/FunSearch.dom.tsx @@ -53,7 +53,7 @@ export function FunSearch(props: FunSearchProps): React.JSX.Element { onBlur={handleBlur} placeholder={props.placeholder} // eslint-disable-next-line jsx-a11y/no-autofocus - autoFocus={shouldAutoFocus} + autoFocus={false} /> {props.searchInput !== '' && (