class PairDrop { constructor() { this.$headerNotificationBtn = $('notification'); this.$headerEditPairedDevicesBtn = $('edit-paired-devices'); this.$footerPairedDevicesBadge = $$('.discovery-wrapper .badge-room-secret'); this.$headerInstallBtn = $('install'); this.deferredStyles = [ "styles/styles-deferred.css" ]; this.deferredScripts = [ "scripts/browser-tabs-connector.js", "scripts/util.js", "scripts/network.js", "scripts/ui.js", "scripts/qr-code.min.js", "scripts/zip.min.js", "scripts/no-sleep.min.js", "scripts/heic2any.min.js" ]; this.registerServiceWorker(); Events.on('beforeinstallprompt', e => this.onPwaInstallable(e)); this.persistentStorage = new PersistentStorage(); this.localization = new Localization(); this.themeUI = new ThemeUI(); this.backgroundCanvas = new BackgroundCanvas(); this.headerUI = new HeaderUI(); this.centerUI = new CenterUI(); this.footerUI = new FooterUI(); this.initialize() .then(_ => { console.log("Initialization completed."); }); } async initialize() { // Translate page before fading in await this.localization.setInitialTranslation() console.log("Initial translation successful."); // Show "Loading..." until connected to WsServer await this.footerUI.showLoading(); // Evaluate css shifting UI elements and fade in UI elements await this.evaluatePermissionsAndRoomSecrets(); await this.headerUI.evaluateOverflowing(); await this.headerUI.fadeIn(); await this.footerUI._evaluateFooterBadges(); await this.footerUI.fadeIn(); await this.centerUI.fadeIn(); await this.backgroundCanvas.fadeIn(); // Load deferred assets await this.loadDeferredAssets(); console.log("Loading of deferred assets completed."); await this.hydrate(); console.log("UI hydrated."); // Evaluate url params as soon as ws is connected Events.on('ws-connected', _ => this.evaluateUrlParams(), {once: true}); } registerServiceWorker() { if ('serviceWorker' in navigator) { navigator.serviceWorker .register('service-worker.js') .then(serviceWorker => { console.log('Service Worker registered'); window.serviceWorker = serviceWorker }); } } onPwaInstallable(e) { if (!window.matchMedia('(display-mode: minimal-ui)').matches) { // only display install btn when not installed this.$headerInstallBtn.removeAttribute('hidden'); this.$headerInstallBtn.addEventListener('click', () => { this.$headerInstallBtn.setAttribute('hidden', true); e.prompt(); }); } return e.preventDefault(); } async evaluatePermissionsAndRoomSecrets() { // Check whether notification permissions have already been granted if ('Notification' in window && Notification.permission !== 'granted') { this.$headerNotificationBtn.removeAttribute('hidden'); } let roomSecrets = await PersistentStorage.getAllRoomSecrets(); if (roomSecrets.length > 0) { this.$headerEditPairedDevicesBtn.removeAttribute('hidden'); this.$footerPairedDevicesBadge.removeAttribute('hidden'); } } async loadDeferredAssets() { console.log("Load deferred assets"); for (const url of this.deferredStyles) { await this.loadAndApplyStylesheet(url); } for (const url of this.deferredScripts) { await this.loadAndApplyScript(url); } } loadStyleSheet(url) { return new Promise((resolve, reject) => { let stylesheet = document.createElement('link'); stylesheet.rel = 'stylesheet'; stylesheet.href = url; stylesheet.type = 'text/css'; stylesheet.onload = resolve; stylesheet.onerror = reject; document.head.appendChild(stylesheet); }); } async loadAndApplyStylesheet(url) { try { await this.loadStyleSheet(url); console.log(`Stylesheet loaded successfully: ${url}`); } catch (error) { console.error('Error loading stylesheet:', error); } } loadScript(url) { return new Promise((resolve, reject) => { let script = document.createElement("script"); script.src = url; script.onload = resolve; script.onerror = reject; document.body.appendChild(script); }); } async loadAndApplyScript(url) { try { await this.loadScript(url); console.log(`Script loaded successfully: ${url}`); } catch (error) { console.error('Error loading script:', error); } } async hydrate() { this.peersUI = new PeersUI(); this.languageSelectDialog = new LanguageSelectDialog(); this.receiveFileDialog = new ReceiveFileDialog(); this.receiveRequestDialog = new ReceiveRequestDialog(); this.sendTextDialog = new SendTextDialog(); this.receiveTextDialog = new ReceiveTextDialog(); this.pairDeviceDialog = new PairDeviceDialog(); this.clearDevicesDialog = new EditPairedDevicesDialog(); this.publicRoomDialog = new PublicRoomDialog(); this.base64Dialog = new Base64Dialog(); this.shareTextDialog = new ShareTextDialog(); this.toast = new Toast(); this.notifications = new Notifications(); this.networkStatusUI = new NetworkStatusUI(); this.webShareTargetUI = new WebShareTargetUI(); this.webFileHandlersUI = new WebFileHandlersUI(); this.noSleepUI = new NoSleepUI(); this.broadCast = new BrowserTabsConnector(); this.server = new ServerConnection(); this.peers = new PeersManager(this.server); } async evaluateUrlParams() { // get url params const urlParams = new URLSearchParams(window.location.search); const hash = window.location.hash.substring(1); // evaluate url params if (urlParams.has('pair_key')) { const pairKey = urlParams.get('pair_key'); this.pairDeviceDialog._pairDeviceJoin(pairKey); } else if (urlParams.has('room_id')) { const roomId = urlParams.get('room_id'); this.publicRoomDialog._joinPublicRoom(roomId); } else if (urlParams.has('base64text')) { const base64Text = urlParams.get('base64text'); await this.base64Dialog.evaluateBase64Text(base64Text, hash); } else if (urlParams.has('base64zip')) { const base64Zip = urlParams.get('base64zip'); await this.base64Dialog.evaluateBase64Zip(base64Zip, hash); } else if (urlParams.has("share_target")) { const shareTargetType = urlParams.get("share_target"); const title = urlParams.get('title') || ''; const text = urlParams.get('text') || ''; const url = urlParams.get('url') || ''; await this.webShareTargetUI.evaluateShareTarget(shareTargetType, title, text, url); } else if (urlParams.has("file_handler")) { await this.webFileHandlersUI.evaluateLaunchQueue(); } else if (urlParams.has("init")) { const init = urlParams.get("init"); if (init === "pair") { this.pairDeviceDialog._pairDeviceInitiate(); } else if (init === "public_room") { this.publicRoomDialog._createPublicRoom(); } } // remove url params from url const urlWithoutParams = getUrlWithoutArguments(); window.history.replaceState({}, "Rewrite URL", urlWithoutParams); } } const pairDrop = new PairDrop();