diff --git a/app/js/controllers.js b/app/js/controllers.js index 4c30f366..24df3fde 100644 --- a/app/js/controllers.js +++ b/app/js/controllers.js @@ -1495,7 +1495,7 @@ angular.module('myApp.controllers', ['myApp.i18n']) updateChannelActions(); }, function () { - safeReplaceObject($scope.state, {error: true}); + safeReplaceObject($scope.state, {error: true, loaded: true}); }); } diff --git a/app/js/directives.js b/app/js/directives.js index 4630ac58..da7388f0 100755 --- a/app/js/directives.js +++ b/app/js/directives.js @@ -3316,6 +3316,49 @@ angular.module('myApp.directives', ['myApp.filters']) }; }) + .directive('myArcProgress', function () { + var html = ''; + return { + scope: { + progress: '=myArcProgress' + }, + link: function ($scope, element, attrs) { + element + .html(html) + .addClass('progress-arc-wrap'); + + var svgEl = element[0].firstChild; + var circle = $('.progress-arc-circle', element); + var bar = $('.progress-arc-bar', element); + + var width = attrs.width || 40; + var radius = width * 0.86; + var stroke = width * 0.14; + var center = width / 2; + + $(svgEl).attr('width', width); + $(svgEl).attr('height', width); + circle.attr('cx', center); + circle.attr('cy', center); + circle.attr('r', radius); + circle.css({strokeWidth: stroke}); + + bar.attr('cx', center); + bar.attr('cy', center); + bar.attr('r', radius); + bar.css({strokeWidth: stroke}); + + var fullLen = 2 * Math.PI * radius; + $scope.$watch('progress', function (newProgress) { + var progress = newProgress / 100.0; + progress = Math.max(0.0, Math.min(progress, 1.0)); + bar.css({strokeDasharray: (progress * fullLen) + ', ' + ((1 - progress) * fullLen)}); + }); + + } + } + }) + .directive('myScrollToOn', function () { return { diff --git a/app/js/lib/mtproto.js b/app/js/lib/mtproto.js index 89d5e890..9e68a995 100644 --- a/app/js/lib/mtproto.js +++ b/app/js/lib/mtproto.js @@ -208,18 +208,20 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) var requestData = xhrSendBuffer ? resultBuffer : resultArray, requestPromise; + var url = MtpDcConfigurator.chooseServer(dcID); + var baseError = {code: 406, type: 'NETWORK_BAD_RESPONSE', url: url}; try { - requestPromise = $http.post(MtpDcConfigurator.chooseServer(dcID), requestData, { + requestPromise = $http.post(url, requestData, { responseType: 'arraybuffer', transformRequest: null }); } catch (e) { - requestPromise = $q.reject({code: 406, type: 'NETWORK_BAD_RESPONSE', originalError: e}); + requestPromise = $q.reject(angular.extend(baseError, {originalError: e})); } return requestPromise.then( function (result) { if (!result.data || !result.data.byteLength) { - return $q.reject({code: 406, type: 'NETWORK_BAD_RESPONSE'}); + return $q.reject(baseError); } try { @@ -230,14 +232,14 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) var msg_len = deserializer.fetchInt('msg_len'); } catch (e) { - return $q.reject({code: 406, type: 'NETWORK_BAD_RESPONSE', originalError: e}); + return $q.reject(angular.extend(baseError, {originalError: e})); } return deserializer; }, function (error) { if (!error.message && !error.type) { - error = {code: 406, type: 'NETWORK_BAD_REQUEST', originalError: error}; + error = angular.extend(baseError, {originalError: error}); } return $q.reject(error); } @@ -286,7 +288,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) deferred.reject(error); }); }, function (error) { - console.log(dT(), 'req_pq error', error.message); + console.error(dT(), 'req_pq error', error.message); deferred.reject(error); }); @@ -1201,19 +1203,22 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) var requestData = xhrSendBuffer ? request.getBuffer() : request.getArray(); var requestPromise; + var url = MtpDcConfigurator.chooseServer(self.dcID, self.upload); + var baseError = {code: 406, type: 'NETWORK_BAD_RESPONSE', url: url}; + try { options = angular.extend(options || {}, { responseType: 'arraybuffer', transformRequest: null }); - requestPromise = $http.post(MtpDcConfigurator.chooseServer(self.dcID, self.upload), requestData, options); + requestPromise = $http.post(url, requestData, options); } catch (e) { requestPromise = $q.reject(e); } return requestPromise.then( function (result) { if (!result.data || !result.data.byteLength) { - return $q.reject({code: 406, type: 'NETWORK_BAD_RESPONSE'}); + return $q.reject(baseError); } return result; }, @@ -1228,7 +1233,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils']) }); } if (!error.message && !error.type) { - error = {code: 406, type: 'NETWORK_BAD_REQUEST'}; + error = angular.extend(baseError, {type: 'NETWORK_BAD_REQUEST', originalError: error}); } return $q.reject(error); } diff --git a/app/js/lib/mtproto_wrapper.js b/app/js/lib/mtproto_wrapper.js index 5e8847e1..103947af 100644 --- a/app/js/lib/mtproto_wrapper.js +++ b/app/js/lib/mtproto_wrapper.js @@ -216,7 +216,7 @@ angular.module('izhukov.mtproto.wrapper', ['izhukov.utils', 'izhukov.mtproto']) networker.wrapApiCall(method, params, options).then(function (result) { deferred.resolve(result); }, rejectPromise); - }); + }, rejectPromise); } } else if (!options.rawError && error.code == 420) { diff --git a/app/js/lib/ng_utils.js b/app/js/lib/ng_utils.js index e1140fce..48a2f9ee 100644 --- a/app/js/lib/ng_utils.js +++ b/app/js/lib/ng_utils.js @@ -1165,7 +1165,7 @@ angular.module('izhukov.utils', []) var usernameRegExp = "[a-zA-Z\\d_]{5,32}"; var botCommandRegExp = "\\/([a-zA-Z\\d_]{1,32})(?:@(" + usernameRegExp + "))?(\\b|$)" - var fullRegExp = new RegExp('(^| )(@)(' + usernameRegExp + ')|(' + urlRegExp + ')|(\\n)|(' + emojiRegExp + ')|(^|\\s)(#[' + alphaNumericRegExp + ']{2,64})|(^|\\s)' + botCommandRegExp, 'i'); + var fullRegExp = new RegExp('(^| )(@)(' + usernameRegExp + ')|(' + urlRegExp + ')|(\\n)|(' + emojiRegExp + ')|(^|[\\s\\(\\]])(#[' + alphaNumericRegExp + ']{2,64})|(^|\\s)' + botCommandRegExp, 'i'); var emailRegExp = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; var youtubeRegExp = /^(?:https?:\/\/)?(?:www\.)?youtu(?:|\.be|be\.com|\.b)(?:\/v\/|\/watch\\?v=|e\/|(?:\/\??#)?\/watch(?:.+)v=)(.{11})(?:\&[^\s]*)?/; diff --git a/app/js/services.js b/app/js/services.js index f64ecf62..dd036724 100755 --- a/app/js/services.js +++ b/app/js/services.js @@ -14,6 +14,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) .service('AppUsersManager', function ($rootScope, $modal, $modalStack, $filter, $q, qSync, MtpApiFileManager, MtpApiManager, RichTextProcessor, ErrorService, Storage, _) { var users = {}, usernames = {}, + userAccess = {}, cachedPhotoLocations = {}, contactsFillPromise, contactsList, @@ -151,6 +152,10 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) } }; + function saveUserAccess (id, accessHash) { + userAccess[id] = accessHash; + } + function getUserStatusForSort(status) { if (status) { var expires = status.expires || status.was_online; @@ -175,7 +180,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) if (angular.isObject(id)) { return id; } - return users[id] || {id: id, deleted: true, num: 1}; + return users[id] || {id: id, deleted: true, num: 1, access_hash: userAccess[id]}; } function getSelf() { @@ -464,6 +469,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) getContacts: getContacts, saveApiUsers: saveApiUsers, saveApiUser: saveApiUser, + saveUserAccess: saveUserAccess, getUser: getUser, getSelf: getSelf, getUserInput: getUserInput, @@ -834,6 +840,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) peerParams = peerString.substr(1).split('_'); if (firstChar == 'u') { + AppUsersManager.saveUserAccess(peerParams[0], peerParams[1]); return { _: 'inputPeerUser', user_id: peerParams[0], diff --git a/app/less/app.less b/app/less/app.less index 6f6118d3..1fa9862c 100644 --- a/app/less/app.less +++ b/app/less/app.less @@ -416,6 +416,62 @@ a { } } +.progress-arc-wrap { + display: block; + border-radius: 100%; +} +.progress-arc circle { + stroke-dashoffset: 0; + stroke: rgba(0,0,0,0.3); + stroke-width: 3px; +} +.progress-arc .progress-arc-bar { + stroke: #FFF; + transform-origin: center center; + transition: stroke-dasharray 500ms linear; + + -webkit-animation: infinite_rotation 2s linear infinite; + -moz-animation: infinite_rotation 2s linear infinite; + -ms-animation: infinite_rotation 2s linear infinite; + animation: infinite_rotation 2s linear infinite; +} + +/* Infinite rotation */ +@-webkit-keyframes infinite_rotation { + 0% { + transform: rotate(0); + } + 100% { + transform: rotate(360deg); + } +} +@-moz-keyframes infinite_rotation { + 0% { + transform: rotate(0); + } + 100% { + transform: rotate(360deg); + } +} +@-ms-keyframes infinite_rotation { + 0% { + transform: rotate(0); + } + 100% { + transform: rotate(360deg); + } +} +@keyframes infinite_rotation { + 0% { + transform: rotate(0); + } + 100% { + transform: rotate(360deg); + } +} + + + .dropdown-menu { border-radius: 2px; padding: 0; diff --git a/app/partials/desktop/error_modal.html b/app/partials/desktop/error_modal.html index 2c58dc14..3b7d7350 100644 --- a/app/partials/desktop/error_modal.html +++ b/app/partials/desktop/error_modal.html @@ -63,6 +63,7 @@