diff --git a/README.md b/README.md
index a81143be..d50ad64d 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-## [Webogram](http://zhukov.github.io/webogram) - Telegram UNOFFICIAL web app
+## [Webogram](http://zhukov.github.io/webogram) – UNOFFICIAL Telegram Web App
Telegram offers great [apps for mobile communication](https://www.telegram.org). It is based on the [MTProto protocol](https://core.telegram.org/protocol) and has an [Open API](http://core.telegram.org/api). I personally like Telegram for its speed and cloud-support (that makes a web app possible, unlike in the case of WA and others).
diff --git a/app/css/app.css b/app/css/app.css
index c16bef1b..5675d5ef 100644
--- a/app/css/app.css
+++ b/app/css/app.css
@@ -709,7 +709,8 @@ div.im_message_video_thumb {
-.im_message_document {
+.im_message_document,
+.im_message_upload_file {
margin-top: 3px;
border-radius: 3px;
display: inline-block;
@@ -728,7 +729,7 @@ div.im_message_video_thumb {
.im_message_document .icon-group {
background-image: url(../img/icons/DialogListGroupChatIcon_Highlighted@2x.png);
}
-.im_message_document .im_message_document_name {
+.im_message_document_name {
color: #999;
vertical-align: text-top;
display: inline-block;
@@ -756,6 +757,33 @@ div.im_message_video_thumb {
padding-right: 3px;
}
+.im_message_upload_progress_wrap,
+.im_message_download_progress_wrap {
+ margin-top: 5px;
+}
+
+.tg_up_progress,
+.tg_down_progress {
+ height: 5px;
+ margin: 0;
+ padding: 0;
+ background: rgba(0,0,0, 0.1);
+ border: 0;
+ border-radius: 4px;
+}
+.tg_up_progress .progress-bar,
+.tg_down_progress .progress-bar {
+ height: 5px;
+ line-height: 5px;
+ background: #43A4DB;
+ border-radius: 3px;
+ overflow: hidden;
+}
+.tg_down_progress .progress-bar {
+ background: #6DBF69;
+}
+
+
.im_service_message_wrap {
text-align: center;
@@ -782,7 +810,7 @@ div.im_message_video_thumb {
.im_content_message_wrap {
margin: 10px 0 5px;
}
-.icon-message-status-unread {
+.icon-message-status {
background: #43A4DB;
border: 1px solid #FFF;
display: block;
@@ -793,7 +821,21 @@ div.im_message_video_thumb {
position: absolute;
margin-left: -27px;
margin-top: 14px;
+ opacity: 0;
+
+ -webkit-transition: opacity ease-in-out 0.15s;
+ transition: opacity ease-in-out 0.15s;
}
+.icon-message-status-unread {
+ opacity: 1.0;
+}
+.icon-message-status-pending {
+ opacity: 0.5;
+}
+/*.icon-message-status-done {
+ opacity: 0;
+}*/
+
.icon-message-status-tick {
/*display: inline-block;*/
display: none;
diff --git a/app/js/controllers.js b/app/js/controllers.js
index 15c8bcdd..b973eb71 100644
--- a/app/js/controllers.js
+++ b/app/js/controllers.js
@@ -301,6 +301,8 @@ angular.module('myApp.controllers', [])
var typingTimeouts = {};
+ $scope.$on('history_update', angular.noop);
+
$scope.$on('history_append', function (e, addedMessage) {
if (addedMessage.peerID == $scope.curDialog.peerID) {
dLog('append', addedMessage);
@@ -383,7 +385,7 @@ angular.module('myApp.controllers', [])
var text = $scope.draftMessage.text;
- if ($scope.draftMessage.sending || !text.length) {
+ if (!text.length) {
return false;
}
@@ -395,50 +397,16 @@ angular.module('myApp.controllers', [])
return all;
});
- $scope.draftMessage.sending = true;
-
- MtpApiManager.invokeApi('messages.sendMessage', {
- peer: $scope.curDialog.inputPeer,
- message: text,
- random_id: $scope.draftMessage.randomID
- }).then(function (result) {
-
- if (ApiUpdatesManager.saveSeq(result.seq)) {
-
- MtpApiManager.getUserID().then(function (fromID) {
- ApiUpdatesManager.saveUpdate({
- _: 'updateNewMessage',
- message: {
- _: 'message',
- id: result.id,
- from_id: fromID,
- to_id: AppPeersManager.getOutputPeer($scope.curDialog.peerID),
- out: true,
- unread: true,
- date: result.date,
- message: text,
- media: {_: 'messageMediaEmpty'}
- },
- pts: result.pts
- });
- });
-
- }
+ AppMessagesManager.sendText($scope.curDialog.peerID, text);
+ resetDraft();
+ $scope.$broadcast('ui_message_send');
- $scope.$broadcast('ui_message_send');
-
- resetDraft();
- }, function () {
- delete $scope.draftMessage.sending;
- });
-
- return cancelEvent(e);
+ return false;
}
function resetDraft () {
$scope.draftMessage = {
- randomID: [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)],
text: ''
};
}
@@ -449,35 +417,8 @@ angular.module('myApp.controllers', [])
}
for (var i = 0; i < newVal.length; i++) {
- (function (file, randomID) {
- MtpApiFileManager.uploadFile(file).then(function (inputFile) {
- var inputMedia;
- if (file.type == 'image/jpeg') {
- inputMedia = {_: 'inputMediaUploadedPhoto', file: inputFile};
- } else {
- inputMedia = {_: 'inputMediaUploadedDocument', file: inputFile, file_name: file.name, mime_type: file.type};
- }
- MtpApiManager.invokeApi('messages.sendMedia', {
- peer: $scope.curDialog.inputPeer,
- media: inputMedia,
- random_id: randomID
- }).then(function (result) {
-
- if (ApiUpdatesManager.saveSeq(result.seq)) {
- ApiUpdatesManager.saveUpdate({
- _: 'updateNewMessage',
- message: result.message,
- pts: result.pts
- });
- }
-
- $scope.$broadcast('ui_message_send');
- });
- }, function (error) {
- dLog('upload error', error);
- })
-
- })(newVal[i], [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)]);
+ AppMessagesManager.sendFile($scope.curDialog.peerID, newVal[i]);
+ $scope.$broadcast('ui_message_send');
}
}
diff --git a/app/js/directives.js b/app/js/directives.js
index 482a445e..7aad2f64 100644
--- a/app/js/directives.js
+++ b/app/js/directives.js
@@ -450,7 +450,8 @@ angular.module('myApp.directives', ['myApp.filters'])
\
\
\
-
\
@@ -471,9 +472,19 @@ angular.module('myApp.directives', ['myApp.filters'])
access_hash: scope.video.access_hash
};
+ var hasQt = false, i;
+ // if (navigator.plugins) {
+ // for (i = 0; i < navigator.plugins.length; i++) {
+ // if (navigator.plugins[i].name.indexOf('QuickTime') >= 0) {
+ // hasQt = true;
+ // }
+ // }
+ // }
+
MtpApiFileManager.downloadFile(scope.video.dc_id, inputLocation, scope.video.size).then(function (url) {
scope.progress.enabled = false;
// scope.progress = {enabled: true, percent: 50};
+ scope.player.quicktime = hasQt;
scope.player.src = $sce.trustAsResourceUrl(url);
}, function (e) {
dLog('Download image failed', e, scope.fullPhoto.location);
@@ -510,3 +521,33 @@ angular.module('myApp.directives', ['myApp.filters'])
}
})
+
+
+ .directive('myTypingDots', function($interval) {
+
+ return {
+ link: link,
+ };
+
+ var interval;
+
+ function link (scope, element, attrs) {
+ var promise = $interval(function () {
+ var time = +new Date(),
+ cnt = 3;
+
+ if (time % 1000 <= 200) {
+ cnt = 0;
+ } else if (time % 1000 <= 400) {
+ cnt = 1;
+ } else if (time % 1000 <= 600) {
+ cnt = 2;
+ }
+ element.html((new Array(cnt + 1)).join('.'));
+ }, 200);
+
+ scope.$on('$destroy', function cleanup() {
+ $interval.cancel(promise);
+ });
+ }
+ })
diff --git a/app/js/lib/mtproto.js b/app/js/lib/mtproto.js
index 0fa9230d..43e1b44d 100644
--- a/app/js/lib/mtproto.js
+++ b/app/js/lib/mtproto.js
@@ -2130,7 +2130,7 @@ factory('MtpApiManager', function (AppConfigManager, MtpAuthorizer, MtpNetworker
deferred.resolve(result);
// setTimeout(function () {
// deferred.resolve(result);
- // },1000);
+ // }, 1000);
},
function (error) {
dLog('error', error.code, error.type, baseDcID, dcID);
@@ -2481,7 +2481,7 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) {
cachedFS.root.getFile(fileName, {create: false}, function(fileEntry) {
fileEntry.file(function(file) {
dLog('check size', file.size, size);
- if (file.size >= size && false) {
+ if (file.size >= size) {
deferred.resolve(fileEntry.toURL());
} else {
dLog('File bad size', file, size);
diff --git a/app/js/services.js b/app/js/services.js
index f2569107..7c27184f 100644
--- a/app/js/services.js
+++ b/app/js/services.js
@@ -405,12 +405,15 @@ angular.module('myApp.services', [])
}
})
-.service('AppMessagesManager', function ($q, $rootScope, $filter, $sanitize, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, MtpApiManager, RichTextProcessor) {
+.service('AppMessagesManager', function ($q, $rootScope, $filter, $sanitize, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, MtpApiManager, MtpApiFileManager, RichTextProcessor) {
var messagesStorage = {};
var messagesForHistory = {};
var historiesStorage = {};
var dialogsStorage = {count: null, dialogs: []};
+ var pendingByRandomID = {};
+ var pendingByMessageID = {};
+ var tempID = -1;
function getDialogs (offset, limit) {
if (dialogsStorage.count !== null && dialogsStorage.dialogs.length >= offset + limit) {
@@ -458,10 +461,14 @@ angular.module('myApp.services', [])
var peerID = AppPeersManager.getPeerID(inputPeer),
historyStorage = historiesStorage[peerID],
- offset = 0;
+ offset = 0,
+ resultPending = [];
if (historyStorage === undefined) {
- historyStorage = historiesStorage[peerID] = {count: null, history: []};
+ historyStorage = historiesStorage[peerID] = {count: null, history: [], pending: []};
+ }
+ else if (!maxID && historyStorage.pending.length) {
+ resultPending = historyStorage.pending.slice();
}
@@ -477,7 +484,7 @@ angular.module('myApp.services', [])
if (historyStorage.count !== null && historyStorage.history.length >= offset + limit) {
return $q.when({
count: historyStorage.count,
- history: historyStorage.history.slice(offset, offset + limit)
+ history: resultPending.concat(historyStorage.history.slice(offset, offset + limit))
});
}
@@ -515,7 +522,7 @@ angular.module('myApp.services', [])
deferred.resolve({
count: historyStorage.count,
- history: historyStorage.history.slice(offset, offset + limit)
+ history: resultPending.concat(historyStorage.history.slice(offset, offset + limit))
});
}, function (error) {
deferred.reject(error);
@@ -619,6 +626,205 @@ angular.module('myApp.services', [])
});
}
+ function sendText(peerID, text) {
+ var messageID = tempID--,
+ randomID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)],
+ randomIDS = bigint(randomID[0]).shiftLeft(32).add(bigint(randomID[1])).toString(),
+ historyStorage = historiesStorage[peerID],
+ inputPeer = AppPeersManager.getInputPeerByID(peerID),
+ message;
+
+ if (historyStorage === undefined) {
+ historyStorage = historiesStorage[peerID] = {count: null, history: [], pending: []};
+ }
+
+ MtpApiManager.getUserID().then(function (fromID) {
+ message = {
+ _: 'message',
+ id: messageID,
+ from_id: fromID,
+ to_id: AppPeersManager.getOutputPeer(peerID),
+ out: true,
+ unread: true,
+ date: (+new Date()) / 1000,
+ message: text,
+ media: {_: 'messageMediaEmpty'},
+ random_id: randomIDS,
+ pending: true
+ };
+
+ message.send = function () {
+ MtpApiManager.invokeApi('messages.sendMessage', {
+ peer: inputPeer,
+ message: text,
+ random_id: randomID
+ }).then(function (result) {
+ if (ApiUpdatesManager.saveSeq(result.seq)) {
+ ApiUpdatesManager.saveUpdate({
+ _: 'updateMessageID',
+ random_id: randomIDS,
+ id: result.id
+ });
+
+ message.date = result.date;
+ message.id = result.id;
+ ApiUpdatesManager.saveUpdate({
+ _: 'updateNewMessage',
+ message: message,
+ pts: result.pts
+ });
+ }
+ });
+ };
+
+ saveMessages([message]);
+ historyStorage.pending.unshift(messageID);
+ $rootScope.$broadcast('history_append', {peerID: peerID, messageID: messageID});
+
+ // setTimeout(function () {
+ message.send();
+ // }, 5000);
+ });
+
+ pendingByRandomID[randomIDS] = [peerID, messageID];
+ };
+
+ function sendFile(peerID, file, options) {
+ var messageID = tempID--,
+ randomID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)],
+ randomIDS = bigint(randomID[0]).shiftLeft(32).add(bigint(randomID[1])).toString(),
+ historyStorage = historiesStorage[peerID],
+ inputPeer = AppPeersManager.getInputPeerByID(peerID),
+ isPhoto = file.type == 'image/jpeg' && file.size <= 5242880; // 5Mb
+
+ if (historyStorage === undefined) {
+ historyStorage = historiesStorage[peerID] = {count: null, history: [], pending: []};
+ }
+
+ MtpApiManager.getUserID().then(function (fromID) {
+ var media = {
+ _: 'messageMediaPending',
+ type: isPhoto ? 'photo' : 'doc',
+ file_name: file.name,
+ size: file.size,
+ progress: {percent: 1}
+ };
+
+ var message = {
+ _: 'message',
+ id: messageID,
+ from_id: fromID,
+ to_id: AppPeersManager.getOutputPeer(peerID),
+ out: true,
+ unread: true,
+ date: (+new Date()) / 1000,
+ message: '',
+ media: media,
+ random_id: randomIDS,
+ pending: true
+ };
+
+ message.send = function () {
+ MtpApiFileManager.uploadFile(file).then(function (inputFile) {
+ var inputMedia;
+ if (isPhoto) {
+ inputMedia = {_: 'inputMediaUploadedPhoto', file: inputFile};
+ } else {
+ inputMedia = {_: 'inputMediaUploadedDocument', file: inputFile, file_name: file.name, mime_type: file.type};
+ }
+ MtpApiManager.invokeApi('messages.sendMedia', {
+ peer: inputPeer,
+ media: inputMedia,
+ random_id: randomID
+ }).then(function (result) {
+ if (ApiUpdatesManager.saveSeq(result.seq)) {
+ ApiUpdatesManager.saveUpdate({
+ _: 'updateMessageID',
+ random_id: randomIDS,
+ id: result.message.id
+ });
+
+ message.date = result.message.date;
+ message.id = result.message.id;
+ message.media = result.message.media;
+
+ ApiUpdatesManager.saveUpdate({
+ _: 'updateNewMessage',
+ message: message,
+ pts: result.pts
+ });
+ }
+
+ });
+ }, null, function (progress) {
+ // dLog('upload progress', progress);
+ var historyMessage = messagesForHistory[messageID],
+ percent = Math.max(1, Math.floor(100 * progress.done / progress.total));
+
+ media.progress.percent = percent;
+ if (historyMessage) {
+ historyMessage.media.progress.percent = percent;
+ $rootScope.$broadcast('history_update', {peerID: peerID});
+ }
+ });
+ };
+
+ saveMessages([message]);
+ historyStorage.pending.unshift(messageID);
+ $rootScope.$broadcast('history_append', {peerID: peerID, messageID: messageID});
+
+ // setTimeout(function () {
+ message.send();
+ // }, 5000);
+ });
+
+ pendingByRandomID[randomIDS] = [peerID, messageID];
+ }
+
+
+ function finalizePendingMessage(randomID, finalMessage) {
+ var pendingData = pendingByRandomID[randomID];
+ // dLog('pdata', randomID, pendingData);
+
+ if (pendingData) {
+ var peerID = pendingData[0],
+ tempID = pendingData[1],
+ historyStorage = historiesStorage[peerID],
+ index = false,
+ message = false,
+ historyMessage = false,
+ i;
+
+ // dLog('pending', randomID, historyStorage.pending);
+ for (i = 0; i < historyStorage.pending.length; i++) {
+ if (historyStorage.pending[i] == tempID) {
+ historyStorage.pending.splice(i, 1);
+ break;
+ }
+ }
+
+ if (message = messagesStorage[tempID]) {
+ delete message.pending;
+ delete message.random_id;
+ delete message.send;
+ }
+
+ if (historyMessage = messagesForHistory[tempID]) {
+ messagesForHistory[finalMessage.id] = angular.extend(historyMessage, wrapForHistory(finalMessage.id));
+ delete historyMessage.pending;
+ delete historyMessage.random_id;
+ delete historyMessage.send;
+ }
+
+ delete messagesForHistory[tempID];
+ delete messagesStorage[tempID];
+
+ return message;
+ }
+
+ return false;
+ }
+
function getMessagePeer (message) {
var toID = message.to_id && AppPeersManager.getPeerID(message.to_id) || 0;
@@ -660,8 +866,8 @@ angular.module('myApp.services', [])
return message;
}
- function wrapForHistory (msgID) {
- if (messagesForHistory[msgID] !== undefined) {
+ function wrapForHistory (msgID, force) {
+ if (!force && messagesForHistory[msgID] !== undefined) {
return messagesForHistory[msgID];
}
@@ -679,6 +885,10 @@ angular.module('myApp.services', [])
case 'messageMediaVideo':
message.media.video = AppVideoManager.wrapForHistory(message.media.video.id);
break;
+
+ case 'messageMediaDocument':
+ message.media.document = AppDocsManager.wrapForHistory(message.media.document.id);
+ break;
}
if (message.media.user_id) {
@@ -714,10 +924,13 @@ angular.module('myApp.services', [])
return [];
}
-
$rootScope.$on('apiUpdate', function (e, update) {
dLog('on apiUpdate', update);
switch (update._) {
+ case 'updateMessageID':
+ pendingByMessageID[update.id] = update.random_id;
+ break;
+
case 'updateNewMessage':
var message = update.message,
peerID = getMessagePeer(message),
@@ -729,7 +942,7 @@ angular.module('myApp.services', [])
return false;
}
} else {
- historyStorage = historiesStorage[peerID] = {count: null, history: []};
+ historyStorage = historiesStorage[peerID] = {count: null, history: [], pending: []};
}
saveMessages([message]);
@@ -737,8 +950,23 @@ angular.module('myApp.services', [])
if (historyStorage.count !== null) {
historyStorage.count++;
}
+
historyStorage.history.unshift(message.id);
- $rootScope.$broadcast('history_append', {peerID: peerID, messageID: message.id});
+ var randomID = pendingByMessageID[message.id],
+ pendingMessage;
+
+
+ if (randomID) {
+ if (pendingMessage = finalizePendingMessage(randomID, message)) {
+ $rootScope.$broadcast('history_update', {peerID: peerID});
+ }
+ delete pendingByMessageID[message.id];
+ }
+
+ // dLog(11, randomID, pendingMessage);
+ if (!pendingMessage) {
+ $rootScope.$broadcast('history_append', {peerID: peerID, messageID: message.id});
+ }
var foundDialog = getDialogByPeerID(peerID),
dialog;
@@ -767,6 +995,7 @@ angular.module('myApp.services', [])
if (message) {
message.unread = false;
if (messagesForHistory[messageID]) {
+ // dLog(222, messagesForHistory[messageID]);
messagesForHistory[messageID].unread = false;
}
peerID = getMessagePeer(message);
@@ -782,6 +1011,7 @@ angular.module('myApp.services', [])
angular.forEach(dialogsUpdated, function(count, peerID) {
$rootScope.$broadcast('dialog_unread', {peerID: peerID, count: count});
});
+ // $rootScope.$broadcast('history_update');
break;
}
});
@@ -791,6 +1021,8 @@ angular.module('myApp.services', [])
getHistory: getHistory,
readHistory: readHistory,
saveMessages: saveMessages,
+ sendText: sendText,
+ sendFile: sendFile,
getMessagePeer: getMessagePeer,
wrapForDialog: wrapForDialog,
wrapForHistory: wrapForHistory
@@ -1011,6 +1243,7 @@ angular.module('myApp.services', [])
.service('AppDocsManager', function ($rootScope, $modal, $window, $timeout, MtpApiFileManager, AppUsersManager) {
var docs = {};
+ var docsForHistory = {};
function saveDoc (apiDoc) {
docs[apiDoc.id] = apiDoc;
@@ -1026,6 +1259,10 @@ angular.module('myApp.services', [])
};
function wrapForHistory (docID) {
+ if (docsForHistory[docID] !== undefined) {
+ return docsForHistory[docID];
+ }
+
var doc = angular.copy(docs[docID]),
width = 100,
height = 100,
@@ -1045,23 +1282,31 @@ angular.module('myApp.services', [])
thumb.location = thumbPhotoSize.location;
thumb.size = thumbPhotoSize.size;
+ } else {
+ thumb = false;
}
doc.thumb = thumb;
- return doc;
+ return docsForHistory[docID] = doc;
}
function openDoc (docID, accessHash) {
var doc = docs[docID],
+ historyDoc = docsForHistory[docID] || doc || {},
inputFileLocation = {
_: 'inputDocumentFileLocation',
id: docID,
access_hash: accessHash || doc.access_hash
- },
- scope = {};
+ };
+
+ historyDoc.progress = {enabled: true, percent: 1};
- scope.progress = {enabled: true, percent: 1};
+ function updateDownloadProgress (progress) {
+ dLog('dl progress', progress);
+ historyDoc.progress.percent = Math.max(1, Math.floor(100 * progress.done / progress.total));
+ $rootScope.$broadcast('history_update');
+ }
if (window.chrome && chrome.fileSystem && chrome.fileSystem.chooseEntry) {
@@ -1076,13 +1321,16 @@ angular.module('myApp.services', [])
}]
}, function (writableFileEntry) {
MtpApiFileManager.downloadFile(doc.dc_id, inputFileLocation, doc.size, writableFileEntry).then(function (url) {
+ delete historyDoc.progress;
dLog('file save done');
- });
-
+ }, function (e) {
+ dLog('document download failed', e);
+ historyDoc.progress.enabled = false;
+ }, updateDownloadProgress);
});
} else {
MtpApiFileManager.downloadFile(doc.dc_id, inputFileLocation, doc.size).then(function (url) {
- scope.progress.enabled = false;
+ delete historyDoc.progress;
var a = $('Download').attr('href', url).attr('target', '_blank').attr('download', doc.file_name).appendTo('body');
a[0].dataset.downloadurl = ['png', doc.file_name, url].join(':');
@@ -1092,9 +1340,8 @@ angular.module('myApp.services', [])
}, 100);
}, function (e) {
dLog('document download failed', e);
- }, function (progress) {
- scope.progress.percent = Math.max(1, Math.floor(100 * progress.done / progress.total));
- });
+ historyDoc.progress.enabled = false;
+ }, updateDownloadProgress);
}
}
@@ -1240,6 +1487,11 @@ angular.module('myApp.services', [])
AppUsersManager.saveApiUsers(differenceResult.users);
AppChatsManager.saveApiChats(differenceResult.chats);
+ // Should be first because of updateMessageID
+ angular.forEach(differenceResult.other_updates, function(update){
+ saveUpdate(update, true);
+ });
+
angular.forEach(differenceResult.new_messages, function (apiMessage) {
saveUpdate({
_: 'updateNewMessage',
@@ -1248,10 +1500,6 @@ angular.module('myApp.services', [])
}, true);
});
- angular.forEach(differenceResult.other_updates, function(update){
- saveUpdate(update, true);
- });
-
var nextState = differenceResult.intermediate_state || differenceResult.state;
curState.seq = nextState.seq;
curState.pts = nextState.pts;
diff --git a/app/partials/head.html b/app/partials/head.html
index 66c5f874..d0299ffb 100644
--- a/app/partials/head.html
+++ b/app/partials/head.html
@@ -2,7 +2,7 @@
+
+
+
+
{{historyMessage.media.file_name}} {{historyMessage.media.size | formatSize}}
+
+
+
+
+ {{historyMessage.media.progress.percent}}% Complete (success)
+
+
+
+
+
+