mirror of
https://github.com/schlagmichdoch/PairDrop.git
synced 2025-04-20 15:06:15 -04:00
Implement fallback for text messages larger than the max message size to sent them in chunks via the send files API
This commit is contained in:
parent
00f1a20177
commit
755d5e29f0
3 changed files with 190 additions and 97 deletions
|
@ -93,6 +93,7 @@
|
||||||
"file-other-description-file": "and 1 other file",
|
"file-other-description-file": "and 1 other file",
|
||||||
"file-other-description-image-plural": "and {{count}} other images",
|
"file-other-description-image-plural": "and {{count}} other images",
|
||||||
"file-other-description-file-plural": "and {{count}} other files",
|
"file-other-description-file-plural": "and {{count}} other files",
|
||||||
|
"text-message-description": "A large text message",
|
||||||
"title-image": "Image",
|
"title-image": "Image",
|
||||||
"title-file": "File",
|
"title-file": "File",
|
||||||
"title-image-plural": "Images",
|
"title-image-plural": "Images",
|
||||||
|
@ -171,6 +172,7 @@
|
||||||
"file-received-plural": "{{count}} Files Received",
|
"file-received-plural": "{{count}} Files Received",
|
||||||
"file-transfer-requested": "File Transfer Requested",
|
"file-transfer-requested": "File Transfer Requested",
|
||||||
"image-transfer-requested": "Image Transfer Requested",
|
"image-transfer-requested": "Image Transfer Requested",
|
||||||
|
"message-transfer-requested": "Message Transfer Requested",
|
||||||
"message-received": "Message Received",
|
"message-received": "Message Received",
|
||||||
"message-received-plural": "{{count}} Messages Received"
|
"message-received-plural": "{{count}} Messages Received"
|
||||||
},
|
},
|
||||||
|
|
|
@ -331,6 +331,8 @@ class Peer {
|
||||||
this._isCaller = isCaller;
|
this._isCaller = isCaller;
|
||||||
this._peerId = peerId;
|
this._peerId = peerId;
|
||||||
|
|
||||||
|
this._maxMessageSize = 65536; // 64 KB
|
||||||
|
|
||||||
this._roomIds = {};
|
this._roomIds = {};
|
||||||
this._updateRoomIds(roomType, roomId);
|
this._updateRoomIds(roomType, roomId);
|
||||||
|
|
||||||
|
@ -352,14 +354,15 @@ class Peer {
|
||||||
|
|
||||||
// tidy up sender
|
// tidy up sender
|
||||||
this._filesRequested = null;
|
this._filesRequested = null;
|
||||||
|
this._requestSent = null;
|
||||||
this._chunker = null;
|
this._chunker = null;
|
||||||
|
|
||||||
// tidy up receiver
|
// tidy up receiver
|
||||||
this._pendingRequest = null;
|
this._requestPending = null;
|
||||||
this._acceptedRequest = null;
|
this._requestAccepted = null;
|
||||||
this._totalBytesReceived = 0;
|
this._totalBytesReceived = 0;
|
||||||
this._digester = null;
|
this._digester = null;
|
||||||
this._filesReceived = [];
|
this._filesReceived = null;
|
||||||
|
|
||||||
// disable NoSleep if idle
|
// disable NoSleep if idle
|
||||||
Events.fire('evaluate-no-sleep');
|
Events.fire('evaluate-no-sleep');
|
||||||
|
@ -497,7 +500,7 @@ class Peer {
|
||||||
await this._onState(message.state);
|
await this._onState(message.state);
|
||||||
break;
|
break;
|
||||||
case 'transfer-request':
|
case 'transfer-request':
|
||||||
await this._onTransferRequest(message);
|
await this._onTransferRequest(message.request);
|
||||||
break;
|
break;
|
||||||
case 'transfer-request-response':
|
case 'transfer-request-response':
|
||||||
this._onTransferRequestResponse(message);
|
this._onTransferRequestResponse(message);
|
||||||
|
@ -624,7 +627,7 @@ class Peer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// File Sender Only
|
// File Sender Only
|
||||||
async _sendFileTransferRequest(files) {
|
async _sendFileTransferRequest(files, fileIsMessage = false) {
|
||||||
this._state = Peer.STATE_PREPARE;
|
this._state = Peer.STATE_PREPARE;
|
||||||
Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: 'prepare'});
|
Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: 'prepare'});
|
||||||
|
|
||||||
|
@ -642,6 +645,13 @@ class Peer {
|
||||||
if (files[i].type.split('/')[0] !== 'image') imagesOnly = false;
|
if (files[i].type.split('/')[0] !== 'image') imagesOnly = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// request type 'images', 'files' or 'message
|
||||||
|
const filesType = fileIsMessage
|
||||||
|
? 'message'
|
||||||
|
: imagesOnly
|
||||||
|
? 'images'
|
||||||
|
: 'files';
|
||||||
|
|
||||||
let dataUrl = "";
|
let dataUrl = "";
|
||||||
if (files[0].type.split('/')[0] === 'image') {
|
if (files[0].type.split('/')[0] === 'image') {
|
||||||
try {
|
try {
|
||||||
|
@ -654,13 +664,18 @@ class Peer {
|
||||||
this._state = Peer.STATE_TRANSFER_REQUEST_SENT;
|
this._state = Peer.STATE_TRANSFER_REQUEST_SENT;
|
||||||
Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: 'wait'});
|
Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: 'wait'});
|
||||||
|
|
||||||
this._filesRequested = files;
|
const request = {
|
||||||
|
|
||||||
this._sendMessage({type: 'transfer-request',
|
|
||||||
header: header,
|
header: header,
|
||||||
totalSize: totalSize,
|
totalSize: totalSize,
|
||||||
imagesOnly: imagesOnly,
|
filesType: filesType,
|
||||||
thumbnailDataUrl: dataUrl
|
thumbnailDataUrl: dataUrl
|
||||||
|
};
|
||||||
|
|
||||||
|
this._filesRequested = files;
|
||||||
|
this._requestSent = request;
|
||||||
|
|
||||||
|
this._sendMessage({type: 'transfer-request',
|
||||||
|
request: request
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -675,7 +690,7 @@ class Peer {
|
||||||
if (message.reason === 'ram-exceed-ios') {
|
if (message.reason === 'ram-exceed-ios') {
|
||||||
Events.fire('notify-user', Localization.getTranslation('notifications.ram-exceed-ios'));
|
Events.fire('notify-user', Localization.getTranslation('notifications.ram-exceed-ios'));
|
||||||
}
|
}
|
||||||
Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: null});
|
Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: 'idle'});
|
||||||
this._reset();
|
this._reset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -748,7 +763,7 @@ class Peer {
|
||||||
|
|
||||||
if (!message.success) {
|
if (!message.success) {
|
||||||
Logger.warn('File could not be sent');
|
Logger.warn('File could not be sent');
|
||||||
Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: null});
|
Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: 'idle'});
|
||||||
this._reset();
|
this._reset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -760,6 +775,9 @@ class Peer {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If files sent was message -> abort and wait for text-received message
|
||||||
|
if (this._requestSent.filesType === 'message') return;
|
||||||
|
|
||||||
// No more files in queue. Transfer is complete
|
// No more files in queue. Transfer is complete
|
||||||
this._reset();
|
this._reset();
|
||||||
Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: 'transfer-complete'});
|
Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: 'transfer-complete'});
|
||||||
|
@ -770,7 +788,7 @@ class Peer {
|
||||||
// File Receiver Only
|
// File Receiver Only
|
||||||
async _onTransferRequest(request) {
|
async _onTransferRequest(request) {
|
||||||
// Only accept one request at a time per peer
|
// Only accept one request at a time per peer
|
||||||
if (this._pendingRequest) {
|
if (this._requestPending) {
|
||||||
this._sendTransferRequestResponse(false);
|
this._sendTransferRequestResponse(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -790,7 +808,7 @@ class Peer {
|
||||||
}
|
}
|
||||||
|
|
||||||
this._state = Peer.STATE_TRANSFER_REQUEST_RECEIVED;
|
this._state = Peer.STATE_TRANSFER_REQUEST_RECEIVED;
|
||||||
this._pendingRequest = request;
|
this._requestPending = request;
|
||||||
|
|
||||||
// Automatically accept request if auto-accept is set to true via the Edit Paired Devices Dialog
|
// Automatically accept request if auto-accept is set to true via the Edit Paired Devices Dialog
|
||||||
if (this._autoAccept) {
|
if (this._autoAccept) {
|
||||||
|
@ -827,7 +845,7 @@ class Peer {
|
||||||
if (accepted) {
|
if (accepted) {
|
||||||
this._state = Peer.STATE_RECEIVE_PROCEEDING;
|
this._state = Peer.STATE_RECEIVE_PROCEEDING;
|
||||||
this._busy = true;
|
this._busy = true;
|
||||||
this._acceptedRequest = this._pendingRequest;
|
this._requestAccepted = this._requestPending;
|
||||||
this._lastProgress = 0;
|
this._lastProgress = 0;
|
||||||
this._totalBytesReceived = 0;
|
this._totalBytesReceived = 0;
|
||||||
this._filesReceived = [];
|
this._filesReceived = [];
|
||||||
|
@ -892,7 +910,7 @@ class Peer {
|
||||||
|
|
||||||
// While transferring -> round progress to 4th digit. After transferring, set it to 1.
|
// While transferring -> round progress to 4th digit. After transferring, set it to 1.
|
||||||
let progress = this._digester
|
let progress = this._digester
|
||||||
? Math.floor(1e4 * (this._totalBytesReceived + this._digester._bytesReceived) / this._acceptedRequest.totalSize) / 1e4
|
? Math.floor(1e4 * (this._totalBytesReceived + this._digester._bytesReceived) / this._requestAccepted.totalSize) / 1e4
|
||||||
: 1;
|
: 1;
|
||||||
|
|
||||||
Events.fire('set-progress', {peerId: this._peerId, progress: progress, status: 'receive'});
|
Events.fire('set-progress', {peerId: this._peerId, progress: progress, status: 'receive'});
|
||||||
|
@ -913,26 +931,34 @@ class Peer {
|
||||||
this._singleFileReceiveComplete(file);
|
this._singleFileReceiveComplete(file);
|
||||||
|
|
||||||
// If less files received than header accepted -> wait for next file
|
// If less files received than header accepted -> wait for next file
|
||||||
if (this._filesReceived.length < this._acceptedRequest.header.length) return;
|
if (this._filesReceived.length < this._requestAccepted.header.length) return;
|
||||||
|
|
||||||
// We are done receiving
|
// We are done receiving
|
||||||
Events.fire('set-progress', {peerId: this._peerId, progress: 1, status: 'receive'});
|
Events.fire('set-progress', {peerId: this._peerId, progress: 1, status: 'receive'});
|
||||||
|
|
||||||
|
// If filesType is 'message' evaluate files as text
|
||||||
|
if (this._requestAccepted.filesType === 'message') {
|
||||||
|
this._textReceivedAsFile();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fileType is 'images' or 'files'
|
||||||
this._allFilesReceiveComplete();
|
this._allFilesReceiveComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
_fitsAcceptedHeader(header) {
|
_fitsAcceptedHeader(header) {
|
||||||
if (!this._acceptedRequest) {
|
if (!this._requestAccepted) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const positionFile = this._filesReceived.length;
|
const positionFile = this._filesReceived.length;
|
||||||
|
|
||||||
if (positionFile > this._acceptedRequest.header.length - 1) {
|
if (positionFile > this._requestAccepted.header.length - 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if file header fits
|
// Check if file header fits
|
||||||
const acceptedHeader = this._acceptedRequest.header[positionFile];
|
const acceptedHeader = this._requestAccepted.header[positionFile];
|
||||||
|
|
||||||
const sameSize = header.size === acceptedHeader.size;
|
const sameSize = header.size === acceptedHeader.size;
|
||||||
const sameType = header.mime === acceptedHeader.mime;
|
const sameType = header.mime === acceptedHeader.mime;
|
||||||
|
@ -955,8 +981,11 @@ class Peer {
|
||||||
// Log speed from request to receive
|
// Log speed from request to receive
|
||||||
Logger.log(`File received.\n\nSize: ${size} MB\tDuration: ${duration} s\tSpeed: ${speed} MB/s`);
|
Logger.log(`File received.\n\nSize: ${size} MB\tDuration: ${duration} s\tSpeed: ${speed} MB/s`);
|
||||||
|
|
||||||
// include for compatibility with 'Snapdrop & PairDrop for Android' app
|
// Prevent App from downloading message txt file
|
||||||
Events.fire('file-received', file);
|
if (this._requestAccepted.filesType !== 'message') {
|
||||||
|
// include for compatibility with 'Snapdrop & PairDrop for Android' app
|
||||||
|
Events.fire('file-received', file);
|
||||||
|
}
|
||||||
|
|
||||||
this._filesReceived.push(file);
|
this._filesReceived.push(file);
|
||||||
|
|
||||||
|
@ -967,39 +996,88 @@ class Peer {
|
||||||
Events.fire('files-received', {
|
Events.fire('files-received', {
|
||||||
peerId: this._peerId,
|
peerId: this._peerId,
|
||||||
files: this._filesReceived,
|
files: this._filesReceived,
|
||||||
imagesOnly: this._acceptedRequest.imagesOnly,
|
filesType: this._requestAccepted.filesType,
|
||||||
totalSize: this._acceptedRequest.totalSize
|
totalSize: this._requestAccepted.totalSize
|
||||||
});
|
});
|
||||||
this._reset();
|
this._reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message Sender Only
|
// Message Sender Only
|
||||||
_sendText(text) {
|
|
||||||
|
_base64encode(text) {
|
||||||
|
return btoa(unescape(encodeURIComponent(text)));
|
||||||
|
}
|
||||||
|
|
||||||
|
async _sendText(text) {
|
||||||
this._state = Peer.STATE_TEXT_SENT;
|
this._state = Peer.STATE_TEXT_SENT;
|
||||||
const unescaped = btoa(unescape(encodeURIComponent(text)));
|
|
||||||
this._sendMessage({ type: 'text', text: unescaped });
|
// Send text base64 encoded
|
||||||
|
const base64encoded = this._base64encode(text);
|
||||||
|
const message = {type: 'text', text: base64encoded};
|
||||||
|
|
||||||
|
// If text too big for connection -> send as file instead
|
||||||
|
if (JSON.stringify(message).length > this._maxMessageSize) {
|
||||||
|
await this._sendTextAsFile(text);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._sendMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
async _sendTextAsFile(text) {
|
||||||
|
// send text in chunks by using the file transfer api
|
||||||
|
const file = new File([text], "pairdrop-message.txt", { type: 'text/plain' });
|
||||||
|
await this._sendFileTransferRequest([file], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onTextReceiveComplete() {
|
_onTextReceiveComplete() {
|
||||||
if (this._state !== Peer.STATE_TEXT_SENT) {
|
if (this._state !== Peer.STATE_TEXT_SENT && this._state !== Peer.STATE_TRANSFER_PROCEEDING) {
|
||||||
this._sendState();
|
this._sendState();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._reset();
|
this._reset();
|
||||||
|
Events.fire('set-progress', { peerId: this._peerId, progress: 0, status: 'idle' });
|
||||||
Events.fire('notify-user', Localization.getTranslation("notifications.message-transfer-completed"));
|
Events.fire('notify-user', Localization.getTranslation("notifications.message-transfer-completed"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message Receiver Only
|
// Message Receiver Only
|
||||||
_onText(message) {
|
_base64decodeMessage(base64encoded){
|
||||||
if (!message.text) return;
|
let decoded = "";
|
||||||
try {
|
try {
|
||||||
const escaped = decodeURIComponent(escape(atob(message.text)));
|
decoded = decodeURIComponent(escape(atob(base64encoded)));
|
||||||
Events.fire('text-received', { text: escaped, peerId: this._peerId });
|
|
||||||
this._sendMessage({ type: 'text-receive-complete' });
|
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
Logger.error(e);
|
Logger.error(e);
|
||||||
}
|
}
|
||||||
|
return decoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
_onText(message) {
|
||||||
|
if (this._state !== Peer.STATE_IDLE) {
|
||||||
|
this._abortTransfer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!message.text) return;
|
||||||
|
|
||||||
|
const text = this._base64decodeMessage(message.text);
|
||||||
|
|
||||||
|
Events.fire('text-received', { text: text, peerId: this._peerId });
|
||||||
|
this._sendMessage({ type: 'text-receive-complete' });
|
||||||
|
}
|
||||||
|
|
||||||
|
_textReceivedAsFile() {
|
||||||
|
// Use FileReader to unpack text from file
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.addEventListener("load", _ => {
|
||||||
|
Events.fire('text-received', { text: reader.result, peerId: this._peerId });
|
||||||
|
});
|
||||||
|
|
||||||
|
reader.readAsText(this._filesReceived[0]);
|
||||||
|
|
||||||
|
Events.fire('set-progress', { peerId: this._peerId, progress: 1, status: 'idle' });
|
||||||
|
this._sendMessage({ type: 'text-receive-complete' });
|
||||||
|
this._reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1114,6 +1192,9 @@ class RTCPeer extends Peer {
|
||||||
_onConnectionStateChange() {
|
_onConnectionStateChange() {
|
||||||
Logger.debug('RTC: Connection state changed:', this._conn.connectionState);
|
Logger.debug('RTC: Connection state changed:', this._conn.connectionState);
|
||||||
switch (this._conn.connectionState) {
|
switch (this._conn.connectionState) {
|
||||||
|
case 'connected':
|
||||||
|
this._setMaxMessageSize();
|
||||||
|
break;
|
||||||
case 'disconnected':
|
case 'disconnected':
|
||||||
this._refresh();
|
this._refresh();
|
||||||
break;
|
break;
|
||||||
|
@ -1331,6 +1412,12 @@ class RTCPeer extends Peer {
|
||||||
this._server.send(message);
|
this._server.send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_setMaxMessageSize() {
|
||||||
|
this._maxMessageSize = this._conn && this._conn.sctp
|
||||||
|
? this._conn.sctp.maxMessageSize
|
||||||
|
: 262144; // 256 kB
|
||||||
|
}
|
||||||
|
|
||||||
async _sendFile(file) {
|
async _sendFile(file) {
|
||||||
this._chunker = new FileChunkerRTC(
|
this._chunker = new FileChunkerRTC(
|
||||||
file,
|
file,
|
||||||
|
@ -1389,6 +1476,8 @@ class WSPeer extends Peer {
|
||||||
this.rtcSupported = false;
|
this.rtcSupported = false;
|
||||||
this.signalSuccessful = false;
|
this.signalSuccessful = false;
|
||||||
|
|
||||||
|
this._maxMessageSize = 65536; // 64 KB
|
||||||
|
|
||||||
if (!this._isCaller) return; // we will listen for a caller
|
if (!this._isCaller) return; // we will listen for a caller
|
||||||
|
|
||||||
this._sendSignal();
|
this._sendSignal();
|
||||||
|
@ -1607,8 +1696,8 @@ class PeersManager {
|
||||||
await this.peers[message.to]._sendFileTransferRequest(files);
|
await this.peers[message.to]._sendFileTransferRequest(files);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onSendText(message) {
|
async _onSendText(message) {
|
||||||
this.peers[message.to]._sendText(message.text);
|
await this.peers[message.to]._sendText(message.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onPeerLeft(message) {
|
_onPeerLeft(message) {
|
||||||
|
@ -1813,7 +1902,7 @@ class FileChunkerRTC extends FileChunker {
|
||||||
|
|
||||||
this._chunkSize = peerConnection && peerConnection.sctp
|
this._chunkSize = peerConnection && peerConnection.sctp
|
||||||
? Math.min(peerConnection.sctp.maxMessageSize, 1048576) // 1 MB max
|
? Math.min(peerConnection.sctp.maxMessageSize, 1048576) // 1 MB max
|
||||||
: 262144; // 256 KB
|
: 262144; // 256 kB
|
||||||
|
|
||||||
this._peerConnection = peerConnection;
|
this._peerConnection = peerConnection;
|
||||||
this._dataChannel = dataChannel;
|
this._dataChannel = dataChannel;
|
||||||
|
|
|
@ -423,8 +423,8 @@ class PeerUI {
|
||||||
this._connected = false;
|
this._connected = false;
|
||||||
|
|
||||||
this._currentProgress = 0;
|
this._currentProgress = 0;
|
||||||
this._currentStatus = null
|
this._currentStatus = 'idle';
|
||||||
this._oldStatus = null;
|
this._oldStatus = 'idle';
|
||||||
|
|
||||||
this._progressQueue = [];
|
this._progressQueue = [];
|
||||||
|
|
||||||
|
@ -604,14 +604,14 @@ class PeerUI {
|
||||||
|
|
||||||
// on reconnect
|
// on reconnect
|
||||||
this.setStatus(this._oldStatus);
|
this.setStatus(this._oldStatus);
|
||||||
this._oldStatus = null;
|
this._oldStatus = 'idle';
|
||||||
|
|
||||||
this._connectionHash = connectionHash;
|
this._connectionHash = connectionHash;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this._connected = false;
|
this._connected = false;
|
||||||
|
|
||||||
if (!this._oldStatus && this._currentStatus !== "connect") {
|
if (this._oldStatus === 'idle' && this._currentStatus !== "connect") {
|
||||||
// save old status when reconnecting
|
// save old status when reconnecting
|
||||||
this._oldStatus = this._currentStatus;
|
this._oldStatus = this._currentStatus;
|
||||||
}
|
}
|
||||||
|
@ -787,10 +787,10 @@ class PeerUI {
|
||||||
|
|
||||||
clearTimeout(this.statusTimeout);
|
clearTimeout(this.statusTimeout);
|
||||||
|
|
||||||
if (!status) {
|
if (status === 'idle') {
|
||||||
this.$el.removeAttribute('status');
|
this.$el.removeAttribute('status');
|
||||||
this.$el.querySelector('.status').innerHTML = '';
|
this.$el.querySelector('.status').innerHTML = '';
|
||||||
this._currentStatus = null;
|
this._currentStatus = 'idle';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -812,7 +812,7 @@ class PeerUI {
|
||||||
|
|
||||||
if (["transfer-complete", "receive-complete", "error"].includes(status)) {
|
if (["transfer-complete", "receive-complete", "error"].includes(status)) {
|
||||||
this.statusTimeout = setTimeout(() => {
|
this.statusTimeout = setTimeout(() => {
|
||||||
this.setProgress(0, null);
|
this.setProgress(0, 'idle');
|
||||||
}, 10000);
|
}, 10000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1031,30 +1031,35 @@ class ReceiveDialog extends Dialog {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_parseFileData(displayName, connectionHash, files, imagesOnly, totalSize, badgeClassName) {
|
_parseFileData(displayName, connectionHash, files, filesType, totalSize, badgeClassName) {
|
||||||
let fileOther = "";
|
if (filesType === 'message') {
|
||||||
if (files.length === 2) {
|
this.$fileOther.innerText = Localization.getTranslation("dialogs.text-message-description");
|
||||||
fileOther = imagesOnly
|
|
||||||
? Localization.getTranslation("dialogs.file-other-description-image")
|
|
||||||
: Localization.getTranslation("dialogs.file-other-description-file");
|
|
||||||
}
|
}
|
||||||
else if (files.length > 2) {
|
else {
|
||||||
fileOther = imagesOnly
|
let fileOther = "";
|
||||||
? Localization.getTranslation("dialogs.file-other-description-image-plural", null, {count: files.length - 1})
|
if (files.length === 2) {
|
||||||
: Localization.getTranslation("dialogs.file-other-description-file-plural", null, {count: files.length - 1});
|
fileOther = filesType === 'images'
|
||||||
|
? Localization.getTranslation("dialogs.file-other-description-image")
|
||||||
|
: Localization.getTranslation("dialogs.file-other-description-file");
|
||||||
|
}
|
||||||
|
else if (files.length > 2) {
|
||||||
|
fileOther = filesType === 'images'
|
||||||
|
? Localization.getTranslation("dialogs.file-other-description-image-plural", null, {count: files.length - 1})
|
||||||
|
: Localization.getTranslation("dialogs.file-other-description-file-plural", null, {count: files.length - 1});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileName = files[0].name;
|
||||||
|
const fileNameSplit = fileName.split('.');
|
||||||
|
const fileExtension = '.' + fileNameSplit[fileNameSplit.length - 1];
|
||||||
|
const fileStem = fileName.substring(0, fileName.length - fileExtension.length);
|
||||||
|
|
||||||
|
this.$fileOther.innerText = fileOther;
|
||||||
|
this.$fileStem.innerText = fileStem;
|
||||||
|
this.$fileExtension.innerText = fileExtension;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileName = files[0].name;
|
this.$fileSize.innerText = this._formatFileSize(totalSize);
|
||||||
const fileNameSplit = fileName.split('.');
|
|
||||||
const fileExtension = '.' + fileNameSplit[fileNameSplit.length - 1];
|
|
||||||
const fileStem = fileName.substring(0, fileName.length - fileExtension.length);
|
|
||||||
|
|
||||||
const fileSize = this._formatFileSize(totalSize);
|
|
||||||
|
|
||||||
this.$fileOther.innerText = fileOther;
|
|
||||||
this.$fileStem.innerText = fileStem;
|
|
||||||
this.$fileExtension.innerText = fileExtension;
|
|
||||||
this.$fileSize.innerText = fileSize;
|
|
||||||
this.$displayName.innerText = displayName;
|
this.$displayName.innerText = displayName;
|
||||||
this.$displayName.title = connectionHash;
|
this.$displayName.title = connectionHash;
|
||||||
this.$displayName.classList.remove("badge-room-ip", "badge-room-secret", "badge-room-public-id");
|
this.$displayName.classList.remove("badge-room-ip", "badge-room-secret", "badge-room-public-id");
|
||||||
|
@ -1070,12 +1075,12 @@ class ReceiveFileDialog extends ReceiveDialog {
|
||||||
this.$downloadBtn = this.$el.querySelector('#download-btn');
|
this.$downloadBtn = this.$el.querySelector('#download-btn');
|
||||||
this.$shareBtn = this.$el.querySelector('#share-btn');
|
this.$shareBtn = this.$el.querySelector('#share-btn');
|
||||||
|
|
||||||
Events.on('files-received', e => this._onFilesReceived(e.detail.peerId, e.detail.files, e.detail.imagesOnly, e.detail.totalSize));
|
Events.on('files-received', e => this._onFilesReceived(e.detail.peerId, e.detail.files, e.detail.filesType, e.detail.totalSize));
|
||||||
this._filesDataQueue = [];
|
this._filesDataQueue = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
async _onFilesReceived(peerId, files, imagesOnly, totalSize) {
|
async _onFilesReceived(peerId, files, filesType, totalSize) {
|
||||||
const descriptor = this._getDescriptor(files, imagesOnly);
|
const descriptor = this._getDescriptor(files, filesType);
|
||||||
const displayName = $(peerId).ui._displayName();
|
const displayName = $(peerId).ui._displayName();
|
||||||
const connectionHash = $(peerId).ui._connectionHash;
|
const connectionHash = $(peerId).ui._connectionHash;
|
||||||
const badgeClassName = $(peerId).ui._badgeClassName();
|
const badgeClassName = $(peerId).ui._badgeClassName();
|
||||||
|
@ -1083,7 +1088,7 @@ class ReceiveFileDialog extends ReceiveDialog {
|
||||||
this._filesDataQueue.push({
|
this._filesDataQueue.push({
|
||||||
peerId: peerId,
|
peerId: peerId,
|
||||||
files: files,
|
files: files,
|
||||||
imagesOnly: imagesOnly,
|
filesType: filesType,
|
||||||
totalSize: totalSize,
|
totalSize: totalSize,
|
||||||
descriptor: descriptor,
|
descriptor: descriptor,
|
||||||
displayName: displayName,
|
displayName: displayName,
|
||||||
|
@ -1126,7 +1131,7 @@ class ReceiveFileDialog extends ReceiveDialog {
|
||||||
this._data.displayName,
|
this._data.displayName,
|
||||||
this._data.connectionHash,
|
this._data.connectionHash,
|
||||||
this._data.files,
|
this._data.files,
|
||||||
this._data.imagesOnly,
|
this._data.filesType,
|
||||||
this._data.totalSize,
|
this._data.totalSize,
|
||||||
this._data.badgeClassName
|
this._data.badgeClassName
|
||||||
);
|
);
|
||||||
|
@ -1152,15 +1157,15 @@ class ReceiveFileDialog extends ReceiveDialog {
|
||||||
return window.iOS && this._data.totalSize > 250000000;
|
return window.iOS && this._data.totalSize > 250000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
_getDescriptor(files, imagesOnly) {
|
_getDescriptor(files, filesType) {
|
||||||
let descriptor;
|
let descriptor;
|
||||||
if (files.length === 1) {
|
if (files.length === 1) {
|
||||||
descriptor = imagesOnly
|
descriptor = filesType === 'images'
|
||||||
? Localization.getTranslation("dialogs.title-image")
|
? Localization.getTranslation("dialogs.title-image")
|
||||||
: Localization.getTranslation("dialogs.title-file");
|
: Localization.getTranslation("dialogs.title-file");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
descriptor = imagesOnly
|
descriptor = filesType === 'images'
|
||||||
? Localization.getTranslation("dialogs.title-image-plural")
|
? Localization.getTranslation("dialogs.title-image-plural")
|
||||||
: Localization.getTranslation("dialogs.title-file-plural");
|
: Localization.getTranslation("dialogs.title-file-plural");
|
||||||
}
|
}
|
||||||
|
@ -1499,15 +1504,17 @@ class ReceiveRequestDialog extends ReceiveDialog {
|
||||||
_showRequestDialog(request, peerId) {
|
_showRequestDialog(request, peerId) {
|
||||||
this.correspondingPeerId = peerId;
|
this.correspondingPeerId = peerId;
|
||||||
|
|
||||||
const transferRequestTitleTranslation = request.imagesOnly
|
const transferRequestTitleTranslation = request.filesType === 'message'
|
||||||
? Localization.getTranslation('document-titles.image-transfer-requested')
|
? Localization.getTranslation('document-titles.message-transfer-requested')
|
||||||
: Localization.getTranslation('document-titles.file-transfer-requested');
|
: request.filesType === 'images'
|
||||||
|
? Localization.getTranslation('document-titles.image-transfer-requested')
|
||||||
|
: Localization.getTranslation('document-titles.file-transfer-requested');
|
||||||
|
|
||||||
const displayName = $(peerId).ui._displayName();
|
const displayName = $(peerId).ui._displayName();
|
||||||
const connectionHash = $(peerId).ui._connectionHash;
|
const connectionHash = $(peerId).ui._connectionHash;
|
||||||
const badgeClassName = $(peerId).ui._badgeClassName();
|
const badgeClassName = $(peerId).ui._badgeClassName();
|
||||||
|
|
||||||
this._parseFileData(displayName, connectionHash, request.header, request.imagesOnly, request.totalSize, badgeClassName);
|
this._parseFileData(displayName, connectionHash, request.header, request.filesType, request.totalSize, badgeClassName);
|
||||||
this._addThumbnailToPreviewBox(request.thumbnailDataUrl);
|
this._addThumbnailToPreviewBox(request.thumbnailDataUrl);
|
||||||
|
|
||||||
this.$receiveTitle.innerText = transferRequestTitleTranslation;
|
this.$receiveTitle.innerText = transferRequestTitleTranslation;
|
||||||
|
@ -2739,7 +2746,7 @@ class Notifications {
|
||||||
|
|
||||||
|
|
||||||
Events.on('text-received', e => this._messageNotification(e.detail.text, e.detail.peerId));
|
Events.on('text-received', e => this._messageNotification(e.detail.text, e.detail.peerId));
|
||||||
Events.on('files-received', e => this._downloadNotification(e.detail.files, e.detail.imagesOnly));
|
Events.on('files-received', e => this._downloadNotification(e.detail.files, e.detail.filesType));
|
||||||
Events.on('files-transfer-request', e => this._requestNotification(e.detail.request, e.detail.peerId));
|
Events.on('files-transfer-request', e => this._requestNotification(e.detail.request, e.detail.peerId));
|
||||||
// Todo on 'files-transfer-request-abort' remove notification
|
// Todo on 'files-transfer-request-abort' remove notification
|
||||||
}
|
}
|
||||||
|
@ -2823,31 +2830,26 @@ class Notifications {
|
||||||
}
|
}
|
||||||
|
|
||||||
_requestNotification(request, peerId) {
|
_requestNotification(request, peerId) {
|
||||||
if (document.visibilityState !== 'visible') {
|
// Do not notify user if page is visible
|
||||||
let imagesOnly = request.header.every(header => header.mime.split('/')[0] === 'image');
|
if (document.visibilityState === 'visible') return;
|
||||||
let displayName = $(peerId).querySelector('.name').textContent;
|
|
||||||
|
|
||||||
let descriptor;
|
const clickToShowTranslation = Localization.getTranslation("notifications.click-to-show");
|
||||||
if (request.header.length === 1) {
|
const displayName = $(peerId).querySelector('.name').textContent;
|
||||||
descriptor = imagesOnly
|
|
||||||
? Localization.getTranslation("dialogs.title-image")
|
|
||||||
: Localization.getTranslation("dialogs.title-file");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
descriptor = imagesOnly
|
|
||||||
? Localization.getTranslation("dialogs.title-image-plural")
|
|
||||||
: Localization.getTranslation("dialogs.title-file-plural");
|
|
||||||
}
|
|
||||||
|
|
||||||
let title = Localization
|
const transferRequestTitleTranslation = request.filesType === 'message'
|
||||||
.getTranslation("notifications.request-title", null, {
|
? Localization.getTranslation('document-titles.message-transfer-requested')
|
||||||
name: displayName,
|
: request.filesType === 'images'
|
||||||
count: request.header.length,
|
? Localization.getTranslation('document-titles.image-transfer-requested')
|
||||||
descriptor: descriptor.toLowerCase()
|
: Localization.getTranslation('document-titles.file-transfer-requested');
|
||||||
});
|
|
||||||
|
|
||||||
const notification = this._notify(title, Localization.getTranslation("notifications.click-to-show"));
|
let title = Localization
|
||||||
}
|
.getTranslation("notifications.request-title", null, {
|
||||||
|
name: displayName,
|
||||||
|
count: request.header.length,
|
||||||
|
descriptor: transferRequestTitleTranslation.toLowerCase()
|
||||||
|
});
|
||||||
|
|
||||||
|
this._notify(title, clickToShowTranslation);
|
||||||
}
|
}
|
||||||
|
|
||||||
_download(notification) {
|
_download(notification) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue