diff --git a/app/index.html b/app/index.html index 68d65584..aa1f8cff 100644 --- a/app/index.html +++ b/app/index.html @@ -9,6 +9,13 @@ + + + + + + + @@ -30,14 +37,14 @@ - + - + - + diff --git a/app/js/app.js b/app/js/app.js index 319c0af6..d8a4723f 100644 --- a/app/js/app.js +++ b/app/js/app.js @@ -49,7 +49,7 @@ config(['$locationProvider', '$routeProvider', '$compileProvider', function($loc // $locationProvider.html5Mode(true); $routeProvider.when('/', {templateUrl: 'partials/welcome.html', controller: 'AppWelcomeController'}); $routeProvider.when('/login', {templateUrl: 'partials/login.html?1', controller: 'AppLoginController'}); - $routeProvider.when('/im', {templateUrl: 'partials/im.html?2', controller: 'AppIMController', reloadOnSearch: false}); + $routeProvider.when('/im', {templateUrl: 'partials/im.html?3', controller: 'AppIMController', reloadOnSearch: false}); $routeProvider.otherwise({redirectTo: '/'}); }]); diff --git a/app/js/directives.js b/app/js/directives.js index 73cda09b..7788c4bd 100644 --- a/app/js/directives.js +++ b/app/js/directives.js @@ -16,7 +16,7 @@ angular.module('myApp.directives', ['myApp.filters']) restrict: 'AE', scope: true, translude: false, - templateUrl: 'partials/dialog.html?2' + templateUrl: 'partials/dialog.html?3' }; }) @@ -25,7 +25,7 @@ angular.module('myApp.directives', ['myApp.filters']) restrict: 'AE', scope: true, translude: false, - templateUrl: 'partials/message.html?3' + templateUrl: 'partials/message.html?4' }; }) @@ -359,18 +359,31 @@ angular.module('myApp.directives', ['myApp.filters']) }; function link (scope, element, attrs) { - element.src = 'img/blank.gif'; + var counter = 0; scope.$watch('thumb.location', function (newVal) { + var counterSaved = ++counter; if (!scope.thumb || !scope.thumb.location) { - element.attr('src', scope.thumb && scope.thumb.placeholder || ''); + element.attr('src', scope.thumb && scope.thumb.placeholder || 'img/blank.gif'); return; } + var cachedSrc = MtpApiFileManager.getCachedFile(location); + if (cachedSrc) { + element.attr('src', cachedSrc); + return; + } + + element.attr('src', scope.thumb.placeholder || 'img/blank.gif'); + MtpApiFileManager.downloadSmallFile(scope.thumb.location, scope.thumb.size).then(function (url) { - element.attr('src', url); + if (counterSaved == counter) { + element.attr('src', url); + } }, function (e) { dLog('Download image failed', e, scope.thumb.location); - element.attr('src', scope.thumb.placeholder || ''); + if (counterSaved == counter) { + element.attr('src', scope.thumb.placeholder || 'img/blank.gif'); + } }); }) @@ -411,24 +424,18 @@ angular.module('myApp.directives', ['myApp.filters']) }; function link (scope, element, attrs) { - var imgElement = $('img', element), - fullLoaded = false; + var imgElement = $('img', element); - imgElement.attr('src', scope.fullPhoto.placeholder || 'img/blank.gif'); + imgElement + .attr('src', MtpApiFileManager.getCachedFile(scope.thumbLocation) || 'img/blank.gif') + .addClass('thumb_blurred') + .addClass('thumb_blur_animation'); if (!scope.fullPhoto.location) { return; } - MtpApiFileManager.getCachedFile(scope.thumbLocation).then(function (url) { - if (!fullLoaded) { - imgElement - .attr('src', url) - .addClass('thumb_blurred') - .addClass('thumb_blur_animation'); - } - }); var apiPromise; if (scope.fullPhoto.size) { @@ -446,7 +453,6 @@ angular.module('myApp.directives', ['myApp.filters']) scope.progress = {enabled: true, percent: 1}; apiPromise.then(function (url) { - fullLoaded = true; scope.progress.enabled = false; imgElement .attr('src', url) @@ -486,7 +492,13 @@ angular.module('myApp.directives', ['myApp.filters']) \ \
\ - \ + \
\
\ \ diff --git a/app/js/lib/mtproto.js b/app/js/lib/mtproto.js index 80f391fb..18e8f751 100644 --- a/app/js/lib/mtproto.js +++ b/app/js/lib/mtproto.js @@ -2297,14 +2297,16 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { var apiUploadPromise = $q.when(); var cachedSavePromises = {}; var cachedDownloadPromises = {}; + var cachedDownloads = {}; var downloadPulls = {}; - var downloadActive = 0; + var downloadActives = {}; var downloadLimit = 5; function downloadRequest(dcID, cb, activeDelta) { if (downloadPulls[dcID] === undefined) { downloadPulls[dcID] = []; + downloadActives[dcID] = 0 } var downloadPull = downloadPulls[dcID]; var deferred = $q.defer(); @@ -2319,25 +2321,25 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { function downloadCheck(dcID) { var downloadPull = downloadPulls[dcID]; - if (downloadActive >= downloadLimit || !downloadPull || !downloadPull.length) { + if (downloadActives[dcID] >= downloadLimit || !downloadPull || !downloadPull.length) { return false; } var data = downloadPull.shift(), activeDelta = data.activeDelta || 1; - downloadActive += activeDelta; + downloadActives[dcID] += activeDelta; var a = index++; data.cb() .then(function (result) { - downloadActive -= activeDelta; + downloadActives[dcID] -= activeDelta; downloadCheck(dcID); data.deferred.resolve(result); }, function (error) { - downloadActive -= activeDelta; + downloadActives[dcID] -= activeDelta; downloadCheck(dcID); data.deferred.reject(error); @@ -2351,7 +2353,7 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { $window.requestFileSystem = $window.requestFileSystem || $window.webkitRequestFileSystem; - if (!$window.requestFileSystem) { + if (!$window.requestFileSystem/* || true*/) { return $q.reject({type: 'FS_BROWSER_UNSUPPORTED', description: 'requestFileSystem not present'}); } @@ -2404,23 +2406,12 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { }; function getCachedFile (location) { - var fileName = getFileName(location); - - if (cachedSavePromises[fileName]) { - return cachedSavePromises[fileName]; + if (!location) { + return false; } - var deferred = $q.defer(), - errorHandler = function (error) { - deferred.reject(); - }; - - requestFS().then(function () { - cachedFS.root.getFile(fileName, {create: false}, function(fileEntry) { - deferred.resolve(fileEntry.toURL()); - }, errorHandler); - }, errorHandler); + var fileName = getFileName(location); - return deferred.promise; + return cachedDownloads[fileName] || false; } function saveSmallFile (location, bytes) { @@ -2434,17 +2425,18 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { errorHandler = function (error) { deferred.reject(error); if (cacheFileWriter) cacheFileWriter.truncate(); + errorHandler = angular.noop; }; requestFS().then(function () { cachedFS.root.getFile(fileName, {create: false}, function(fileEntry) { - deferred.resolve(fileEntry.toURL()); + deferred.resolve(cachedDownloads[fileName] = fileEntry.toURL()); }, function () { cachedFS.root.getFile(fileName, {create: true}, function(fileEntry) { fileEntry.createWriter(function (fileWriter) { cacheFileWriter = fileWriter; fileWriteBytes(fileWriter, bytes).then(function () { - deferred.resolve(fileEntry.toURL()); + deferred.resolve(cachedDownloads[fileName] = fileEntry.toURL()); }, errorHandler); }, errorHandler); }, errorHandler); @@ -2468,6 +2460,7 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { errorHandler = function (error) { deferred.reject(error); if (cacheFileWriter) cacheFileWriter.truncate(); + errorHandler = angular.noop; }, doDownload = function () { cachedFS.root.getFile(fileName, {create: true}, function(fileEntry) { @@ -2485,7 +2478,7 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { downloadPromise.then(function (result) { fileWriteBytes(fileWriter, result.bytes).then(function () { // dLog('Success', location, fileEntry.toURL()); - deferred.resolve(fileEntry.toURL()); + deferred.resolve(cachedDownloads[fileName] = fileEntry.toURL()); }, errorHandler); }, errorHandler); }, errorHandler); @@ -2496,7 +2489,7 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { cachedFS.root.getFile(fileName, {create: false}, function(fileEntry) { fileEntry.file(function(file) { if (file.size) { - deferred.resolve(fileEntry.toURL()); + deferred.resolve(cachedDownloads[fileName] = fileEntry.toURL()); } else { dLog('Small file empty', file); doDownload(); @@ -2513,7 +2506,7 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { limit: 0 }, {dcID: location.dc_id}); }).then(function (result) { - deferred.resolve('data:image/jpeg;base64,' + bytesToBase64(result.bytes)) + deferred.resolve(cachedDownloads[fileName] = 'data:image/jpeg;base64,' + bytesToBase64(result.bytes)) }, errorHandler); }); @@ -2536,6 +2529,7 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { // dLog('fail'); deferred.reject(error); if (cacheFileWriter) cacheFileWriter.truncate(); + errorHandler = angular.noop; }, saveToFileEntry = function (fileEntry) { fileEntry.createWriter(function (fileWriter) { @@ -2571,7 +2565,7 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { }, errorHandler).then(function () { if (isFinal) { - deferred.resolve(fileEntry.toURL('image/jpeg')); + deferred.resolve(cachedDownloads[fileName] = fileEntry.toURL('image/jpeg')); } else { // dLog('notify', {done: offset + limit, total: size}); deferred.notify({done: offset + limit, total: size}); @@ -2590,9 +2584,6 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { } }, errorHandler); - }, - doDownload = function () { - cachedFS.root.getFile(fileName, {create: true}, saveToFileEntry, errorHandler); }; if (fileEntry) { @@ -2603,14 +2594,68 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { fileEntry.file(function(file) { dLog('check size', file.size, size); if (file.size >= size) { - deferred.resolve(fileEntry.toURL()); + deferred.resolve(cachedDownloads[fileName] = fileEntry.toURL()); } else { dLog('File bad size', file, size); - doDownload(); + cachedFS.root.getFile(fileName, {create: true}, saveToFileEntry, errorHandler) } }, errorHandler); - }, doDownload); - }, errorHandler); + }, function () { + cachedFS.root.getFile(fileName, {create: true}, saveToFileEntry, errorHandler) + }); + }, function () { + + var blobParts = []; + var limit = size > 30400 ? 524288 : 4096; + var writeBlobPromise = $q.when(), + writeBlobDeferred; + for (var offset = 0; offset < size; offset += limit) { + writeBlobDeferred = $q.defer(); + (function (isFinal, offset, writeBlobDeferred, writeBlobPromise) { + return downloadRequest(dcID, function () { + return MtpApiManager.invokeApi('upload.getFile', { + location: location, + offset: offset, + limit: limit + }, {dcID: dcID}); + }, 6).then(function (result) { + writeBlobPromise.then(function () { + try { + blobParts.push(bytesToArrayBuffer(result.bytes)); + writeBlobDeferred.resolve(); + + if (isFinal) { + try { + var blob = new Blob(blobParts, {type: 'image/jpeg'}); + } catch (e) { + window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder; + var bb = new BlobBuilder; + angular.forEach(blobParts, function(blobPart) { + bb.append(blobPart); + }); + var blob = bb.getBlob('image/jpeg'); + } + + + window.URL = window.URL || window.webkitURL; + deferred.resolve(cachedDownloads[fileName] = URL.createObjectURL(blob)); + } else { + deferred.notify({done: offset + limit, total: size}); + }; + } catch (e) { + errorHandler(e); + } + }, errorHandler); + + }); + + })(offset + limit >= size, offset, writeBlobDeferred, writeBlobPromise); + + writeBlobPromise = writeBlobDeferred.promise; + + } + + }); } return cachedDownloadPromises[fileName] = deferred.promise; @@ -2626,6 +2671,7 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { dLog('fail'); deferred.reject(error); if (cacheFileWriter) cacheFileWriter.truncate(); + errorHandler = angular.noop; }; requestFS().then(function () { @@ -2660,6 +2706,7 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { errorHandler = function (error) { dLog('error', error); deferred.reject(error); + errorHandler = angular.noop; }, part = 0, offset, diff --git a/app/js/services.js b/app/js/services.js index b69ec370..c7283f3b 100644 --- a/app/js/services.js +++ b/app/js/services.js @@ -213,7 +213,7 @@ angular.module('myApp.services', []) scope.userID = userID; var modalInstance = $modal.open({ - templateUrl: 'partials/user_modal.html', + templateUrl: 'partials/user_modal.html?1', controller: 'UserModalController', scope: scope, windowClass: 'user_modal_window', @@ -335,7 +335,7 @@ angular.module('myApp.services', []) scope.chatID = chatID; var modalInstance = $modal.open({ - templateUrl: 'partials/chat_modal.html?2', + templateUrl: 'partials/chat_modal.html?3', controller: 'ChatModalController', windowClass: 'chat_modal_window', scope: scope diff --git a/app/partials/chat_modal.html b/app/partials/chat_modal.html index d5460a71..d8652f1d 100644 --- a/app/partials/chat_modal.html +++ b/app/partials/chat_modal.html @@ -8,7 +8,10 @@