diff --git a/public/index.html b/public/index.html index cf286cc..290fd01 100644 --- a/public/index.html +++ b/public/index.html @@ -216,7 +216,7 @@
- File Transfer Completed +
diff --git a/public/scripts/network.js b/public/scripts/network.js index 55bce53..6ccbf17 100644 --- a/public/scripts/network.js +++ b/public/scripts/network.js @@ -12,7 +12,7 @@ class ServerConnection { Events.on('beforeunload', _ => this._disconnect()); Events.on('pagehide', _ => this._disconnect()); document.addEventListener('visibilitychange', _ => this._onVisibilityChange()); - if (navigator.connection) navigator.connection.addEventListener('change', _ => this._disconnect()); + if (navigator.connection) navigator.connection.addEventListener('change', _ => this._reconnect()); Events.on('reconnect', _ => this._reconnect()); Events.on('room-secrets', e => this._sendRoomSecrets(e.detail)); Events.on('room-secret-deleted', e => this.send({ type: 'room-secret-deleted', roomSecret: e.detail})); @@ -152,9 +152,10 @@ class ServerConnection { _onDisconnect() { console.log('WS: server disconnected'); - Events.fire('notify-user', 'Connection lost. Retrying...'); + Events.fire('notify-user', 'Server connection lost. Retrying...'); clearTimeout(this._reconnectTimer); - this._reconnectTimer = setTimeout(_ => this._connect(), 1000); + this._reconnectTimer = setTimeout(_ => this._connect(), 5000); + this._connect(); Events.fire('ws-disconnected'); } @@ -298,8 +299,6 @@ class Peer { } async sendFiles() { - console.debug("sendFiles") - console.debug(this.zipFileRequested); this._filesQueue.push({zipFile: this.zipFileRequested, fileHeader: this._fileHeaderRequested}); this._fileHeaderRequested = null if (this._busy) return; @@ -429,7 +428,7 @@ class Peer { } async _onFileReceived(zipBlob, fileHeader) { - Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: 'wait'}); + Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: 'process'}); this._busy = false; this.sendJSON({type: 'file-transfer-complete'}); @@ -563,9 +562,17 @@ class RTCPeer extends Peer { channel.binaryType = 'arraybuffer'; channel.onmessage = e => this._onMessage(e.data); channel.onclose = _ => this._onChannelClosed(); + Events.on('beforeunload', _ => this._closeChannel()); + Events.on('pagehide', _ => this._closeChannel()); this._channel = channel; } + _closeChannel() { + this._channel.onclose = null; + this._conn.close(); + this._conn = null; + } + _onChannelClosed() { console.log('RTC: channel closed', this._peerId); Events.fire('peer-disconnected', this._peerId); @@ -603,7 +610,7 @@ class RTCPeer extends Peer { } _send(message) { - if (!this._channel) return this.refresh(); + if (!this._channel) this.refresh(); this._channel.send(message); } @@ -617,8 +624,6 @@ class RTCPeer extends Peer { refresh() { // check if channel is open. otherwise create one - console.debug("refresh:"); - console.debug(this._conn); if (this._isConnected() || this._isConnecting()) return; this._connect(this._peerId, this._isCaller); } @@ -652,8 +657,7 @@ class PeersManager { Events.on('respond-to-files-transfer-request', e => this._onRespondToFileTransferRequest(e.detail)) Events.on('send-text', e => this._onSendText(e.detail)); Events.on('peer-joined', e => this._onPeerJoined(e.detail)); - Events.on('peer-left', e => this._onPeerLeft(e.detail)); - Events.on('ws-disconnected', _ => this._clearPeers()); + Events.on('peer-disconnected', e => this._onPeerLeft(e.detail)); Events.on('secret-room-deleted', e => this._onSecretRoomDeleted(e.detail)); } @@ -699,20 +703,15 @@ class PeersManager { } _onFilesSelected(message) { - const files = this._addTypeIfMissing(message.files); - this.peers[message.to].requestFileTransfer(files); - } - - _addTypeIfMissing(files) { - let filesWithType = [], file; - for (let i=0; i this._onPeerLeft(peerId)); - } - } - _onSecretRoomDeleted(roomSecret) { for (const peerId in this.peers) { const peer = this.peers[peerId]; diff --git a/public/scripts/ui.js b/public/scripts/ui.js index 558affa..d18794e 100644 --- a/public/scripts/ui.js +++ b/public/scripts/ui.js @@ -19,14 +19,12 @@ class PeersUI { constructor() { Events.on('peer-joined', e => this._onPeerJoined(e.detail)); - Events.on('peer-left', e => this._onPeerLeft(e.detail)); Events.on('peer-connected', e => this._onPeerConnected(e.detail)); Events.on('peer-disconnected', e => this._onPeerDisconnected(e.detail)); Events.on('peers', e => this._onPeers(e.detail)); Events.on('set-progress', e => this._onSetProgress(e.detail)); Events.on('paste', e => this._onPaste(e)); - Events.on('ws-disconnected', _ => this._clearPeers()); - Events.on('secret-room-deleted', _ => this._clearPeers('secret')); + Events.on('secret-room-deleted', e => this._onSecretRoomDeleted(e.detail)); Events.on('activate-paste-mode', e => this._activatePasteMode(e.detail.files, e.detail.text)); this.peers = {}; @@ -88,16 +86,11 @@ class PeersUI { if ($$('x-peers:empty')) setTimeout(_ => window.animateBackground(true), 1750); // Start animation again } - _onPeerLeft(peerId) { - this._onPeerDisconnected(peerId); - delete this.peers[peerId]; - } - _onSecretRoomDeleted(roomSecret) { for (const peerId in this.peers) { const peer = this.peers[peerId]; if (peer.roomSecret === roomSecret) { - this._onPeerLeft(peerId); + this._onPeerDisconnected(peerId); } } } @@ -108,16 +101,6 @@ class PeersUI { $peer.ui.setProgress(progress.progress, progress.status) } - _clearPeers(roomType = 'all') { - for (const peerId in this.peers) { - if (roomType === 'all' || this.peers[peerId].roomType === roomType) { - const peerNode = $(peerId); - if(peerNode) peerNode.remove(); - delete this.peers[peerId]; - } - } - } - _onDrop(e) { e.preventDefault(); if (!$$('x-peer') || !$$('x-peer').contains(e.target)) { @@ -429,7 +412,7 @@ class Dialog { this.$el = $(id); this.$el.querySelectorAll('[close]').forEach(el => el.addEventListener('click', _ => this.hide())) this.$autoFocus = this.$el.querySelector('[autofocus]'); - if (hideOnDisconnect) Events.on('ws-disconnected', _ => this.hide()); + if (hideOnDisconnect) Events.on('peer-disconnected', e => this._onPeerDisconnected(e.detail)); } show() { @@ -445,6 +428,14 @@ class Dialog { } document.title = 'PairDrop'; document.changeFavicon("images/favicon-96x96.png"); + if (this.correspondingPeerId) setTimeout(_ => this.correspondingPeerId = undefined, 300); + } + + _onPeerDisconnected(peerId) { + if (this.correspondingPeerId && this.correspondingPeerId === peerId) { + this.hide(); + Events.fire('notify-user', 'Selected peer left.') + } } } @@ -600,7 +591,7 @@ class ReceiveFileDialog extends ReceiveDialog { Events.fire('set-progress', { peerId: peerId, progress: 1, - status: 'wait' + status: 'process' }) this.$shareOrDownloadBtn.click(); }).catch(r => console.error(r)); @@ -631,8 +622,6 @@ class ReceiveRequestDialog extends ReceiveDialog { this.$declineRequestBtn.addEventListener('click', _ => this._respondToFileTransferRequest(false)); Events.on('files-transfer-request', e => this._onRequestFileTransfer(e.detail.request, e.detail.peerId)) - Events.on('peer-left', e => this._onPeerDisconnectedOrLeft(e.detail)) - Events.on('peer-disconnected', e => this._onPeerDisconnectedOrLeft(e.detail)) Events.on('keydown', e => this._onKeyDown(e)); } @@ -643,15 +632,8 @@ class ReceiveRequestDialog extends ReceiveDialog { } } - _onPeerDisconnectedOrLeft(peerId) { - if (peerId === this.requestingPeerId) { - this._respondToFileTransferRequest(false) - this.hide(); - } - } - _onRequestFileTransfer(request, peerId) { - this.requestingPeerId = peerId; + this.correspondingPeerId = peerId; this.requestedHeader = request.header; const peer = $(peerId); @@ -693,13 +675,12 @@ class ReceiveRequestDialog extends ReceiveDialog { _respondToFileTransferRequest(accepted) { Events.fire('respond-to-files-transfer-request', { - to: this.requestingPeerId, + to: this.correspondingPeerId, header: this.requestedHeader, accepted: accepted }) - this.requestingPeerId = null; if (accepted) { - Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: 'wait'}); + Events.fire('set-progress', {peerId: this.correspondingPeerId, progress: 0, status: 'wait'}); NoSleepUI.enable(); } } @@ -732,6 +713,7 @@ class PairDeviceDialog extends Dialog { Events.on('keydown', e => this._onKeyDown(e)); Events.on('ws-connected', _ => this._onWsConnected()); + Events.on('ws-disconnected', _ => this.hide()); Events.on('pair-device-initiated', e => this._pairDeviceInitiated(e.detail)); Events.on('pair-device-joined', e => this._pairDeviceJoined(e.detail)); Events.on('pair-device-join-key-invalid', _ => this._pairDeviceJoinKeyInvalid()); @@ -976,8 +958,8 @@ class SendTextDialog extends Dialog { } } - _onRecipient(recipient) { - this._recipient = recipient; + _onRecipient(peerId) { + this.correspondingPeerId = peerId; this.show(); const range = document.createRange(); @@ -991,7 +973,7 @@ class SendTextDialog extends Dialog { _send() { Events.fire('send-text', { - to: this._recipient, + to: this.correspondingPeerId, text: this.$text.innerText }); this.$text.value = ""; @@ -1096,13 +1078,14 @@ class Base64ZipDialog extends Dialog { class Toast extends Dialog { constructor() { super('toast'); - Events.on('notify-user', e => this._onNotifiy(e.detail)); + Events.on('notify-user', e => this._onNotify(e.detail)); } - _onNotifiy(message) { + _onNotify(message) { + if (this.hideTimeout) clearTimeout(this.hideTimeout); this.$el.textContent = message; this.show(); - setTimeout(_ => this.hide(), 3000); + this.hideTimeout = setTimeout(_ => this.hide(), 3000); } } diff --git a/public/service-worker.js b/public/service-worker.js index 3870f54..2f22f8e 100644 --- a/public/service-worker.js +++ b/public/service-worker.js @@ -1,17 +1,23 @@ -var CACHE_NAME = 'pairdrop-cache-v4'; -var urlsToCache = [ - 'index.html', - './', - 'styles.css', - 'scripts/network.js', - 'scripts/ui.js', - 'scripts/util.js', - 'scripts/qrcode.js', - 'scripts/zip.min.js', - 'scripts/NoSleep.min.js', - 'scripts/theme.js', - 'sounds/blop.mp3', - 'images/favicon-96x96.png' +const CACHE_NAME = 'pairdrop-cache-v4'; +const urlsToCache = [ + 'index.html', + './', + 'styles.css', + 'scripts/network.js', + 'scripts/ui.js', + 'scripts/util.js', + 'scripts/qrcode.js', + 'scripts/zip.min.js', + 'scripts/NoSleep.min.js', + 'scripts/theme.js', + 'sounds/blop.mp3', + 'images/favicon-96x96.png', + 'images/favicon-96x96-notification.png', + 'images/android-chrome-192x192.png', + 'images/android-chrome-192x192-maskable.png', + 'images/android-chrome-512x512.png', + 'images/android-chrome-512x512-maskable.png', + 'images/apple-touch-icon.png', ]; self.addEventListener('install', function(event) { diff --git a/public/styles.css b/public/styles.css index 78e44f4..a2289a4 100644 --- a/public/styles.css +++ b/public/styles.css @@ -320,6 +320,10 @@ x-peer[status=wait] .status:before { content: 'Waiting...'; } +x-peer[status=process] .status:before { + content: 'Processing...'; +} + x-peer:not([status]) .status, x-peer[status] .device-name { display: none; @@ -527,6 +531,8 @@ x-dialog .row-reverse { max-width: 80%; overflow: hidden; text-overflow: ellipsis; + word-break: break-all; + max-height: 1rem; } .file-size{