Browse Source

Init separate mobile version

Attach desktop/mobile styles conditionally
Separate templates for mobile
Make ConfigStorage angular-independent
master
Igor Zhukov 10 years ago
parent
commit
cce8193ebc
  1. 0
      app/css/desktop.css
  2. 7
      app/css/mobile.css
  3. 3
      app/index.html
  4. 18
      app/js/app.js
  5. 38
      app/js/controllers.js
  6. 44
      app/js/directives.js
  7. 2
      app/js/filters.js
  8. 28
      app/js/init.js
  9. 129
      app/js/lib/config.js
  10. 129
      app/js/lib/ng_utils.js
  11. 4
      app/js/lib/utils.js
  12. 57
      app/js/services.js
  13. 0
      app/partials/desktop/changelog_modal.html
  14. 0
      app/partials/desktop/chat_create_modal.html
  15. 0
      app/partials/desktop/chat_edit_modal.html
  16. 0
      app/partials/desktop/chat_modal.html
  17. 0
      app/partials/desktop/confirm_modal.html
  18. 0
      app/partials/desktop/contacts_modal.html
  19. 0
      app/partials/desktop/country_select_modal.html
  20. 0
      app/partials/desktop/dialog.html
  21. 0
      app/partials/desktop/edit_contact_modal.html
  22. 0
      app/partials/desktop/error_modal.html
  23. 0
      app/partials/desktop/full_gif.html
  24. 0
      app/partials/desktop/full_photo.html
  25. 0
      app/partials/desktop/full_video.html
  26. 0
      app/partials/desktop/head.html
  27. 0
      app/partials/desktop/im.html
  28. 0
      app/partials/desktop/import_contact_modal.html
  29. 0
      app/partials/desktop/login.html
  30. 0
      app/partials/desktop/message.html
  31. 0
      app/partials/desktop/message_attach_audio.html
  32. 0
      app/partials/desktop/message_attach_contact.html
  33. 0
      app/partials/desktop/message_attach_document.html
  34. 0
      app/partials/desktop/message_attach_map.html
  35. 0
      app/partials/desktop/message_attach_pending.html
  36. 0
      app/partials/desktop/message_attach_photo.html
  37. 0
      app/partials/desktop/message_attach_video.html
  38. 0
      app/partials/desktop/message_service.html
  39. 0
      app/partials/desktop/peer_select.html
  40. 0
      app/partials/desktop/photo_modal.html
  41. 0
      app/partials/desktop/profile_edit_modal.html
  42. 0
      app/partials/desktop/settings_modal.html
  43. 0
      app/partials/desktop/user_modal.html
  44. 0
      app/partials/desktop/video_modal.html
  45. 0
      app/partials/desktop/welcome.html
  46. 199
      app/partials/mobile/changelog_modal.html
  47. 24
      app/partials/mobile/chat_create_modal.html
  48. 24
      app/partials/mobile/chat_edit_modal.html
  49. 65
      app/partials/mobile/confirm_modal.html
  50. 89
      app/partials/mobile/dialog.html
  51. 30
      app/partials/mobile/edit_contact_modal.html
  52. 87
      app/partials/mobile/error_modal.html
  53. 25
      app/partials/mobile/full_gif.html
  54. 19
      app/partials/mobile/full_photo.html
  55. 26
      app/partials/mobile/full_video.html
  56. 132
      app/partials/mobile/head.html
  57. 278
      app/partials/mobile/im.html
  58. 31
      app/partials/mobile/import_contact_modal.html
  59. 84
      app/partials/mobile/login.html
  60. 79
      app/partials/mobile/message.html
  61. 33
      app/partials/mobile/message_attach_audio.html
  62. 8
      app/partials/mobile/message_attach_contact.html
  63. 39
      app/partials/mobile/message_attach_document.html
  64. 3
      app/partials/mobile/message_attach_map.html
  65. 17
      app/partials/mobile/message_attach_pending.html
  66. 7
      app/partials/mobile/message_attach_photo.html
  67. 31
      app/partials/mobile/message_attach_video.html
  68. 32
      app/partials/mobile/message_service.html
  69. 22
      app/partials/mobile/photo_modal.html
  70. 27
      app/partials/mobile/profile_edit_modal.html
  71. 21
      app/partials/mobile/video_modal.html
  72. 56
      app/partials/mobile/welcome.html
  73. 2
      app/webogram.appcache

0
app/css/desktop.css

7
app/css/app_mobile.css → app/css/mobile.css

@ -1,5 +1,3 @@
@media (max-width: 479px) {
html { html {
background: #FFF; background: #FFF;
} }
@ -1286,7 +1284,4 @@ a.mobile_modal_action .tg_checkbox_label {
} }
.countries_scrollable_wrap a.countries_modal_country { .countries_scrollable_wrap a.countries_modal_country {
padding: 8px 8px; padding: 8px 8px;
} }
}

3
app/index.html

@ -1,5 +1,5 @@
<!doctype html> <!doctype html>
<html lang="en" ng-app="myApp" manifest="webogram.appcache" ng-csp=""> <html lang="en" manifest="webogram.appcache" ng-csp="">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
@ -10,7 +10,6 @@
<link rel="stylesheet" href="vendor/bootstrap/css/bootstrap.css"/> <link rel="stylesheet" href="vendor/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="vendor/jquery.nanoscroller/nanoscroller.css"/> <link rel="stylesheet" href="vendor/jquery.nanoscroller/nanoscroller.css"/>
<link rel="stylesheet" href="css/app.css"/> <link rel="stylesheet" href="css/app.css"/>
<link rel="stylesheet" href="css/app_mobile.css"/>
<!-- endbuild --> <!-- endbuild -->
<link rel="icon" href="favicon.ico" type="image/x-icon" /> <link rel="icon" href="favicon.ico" type="image/x-icon" />

18
app/js/app.js

@ -53,21 +53,9 @@ config(['$locationProvider', '$routeProvider', '$compileProvider', 'StorageProvi
StorageProvider.setPrefix('t_'); StorageProvider.setPrefix('t_');
} }
$routeProvider.when('/', {templateUrl: 'partials/welcome.html', controller: 'AppWelcomeController'}); $routeProvider.when('/', {templateUrl: templateUrl('welcome'), controller: 'AppWelcomeController'});
$routeProvider.when('/login', {templateUrl: 'partials/login.html', controller: 'AppLoginController'}); $routeProvider.when('/login', {templateUrl: templateUrl('login'), controller: 'AppLoginController'});
$routeProvider.when('/im', {templateUrl: 'partials/im.html', controller: 'AppIMController', reloadOnSearch: false}); $routeProvider.when('/im', {templateUrl: templateUrl('im'), controller: 'AppIMController', reloadOnSearch: false});
$routeProvider.otherwise({redirectTo: '/'}); $routeProvider.otherwise({redirectTo: '/'});
}]); }]);
(function () {
var classes = [
Config.Navigator.osX ? 'osx' : 'non_osx',
Config.Navigator.retina ? 'is_2x' : 'is_1x'
];
if (Config.Modes.ios_standalone) {
classes.push('ios_standalone');
}
$(document.body).addClass(classes.join(' '));
})();

38
app/js/controllers.js

@ -42,16 +42,13 @@ angular.module('myApp.controllers', [])
$scope.callPending = {}; $scope.callPending = {};
$scope.chooseCountry = function () { $scope.chooseCountry = function () {
var tUrl = 'partials/country_select_modal.html', var className = 'countries_modal_window page_modal';
className = 'countries_modal_window page_modal'; if (Config.Mobile) {
if (Config.Navigator.mobile) {
tUrl = 'partials/mobile/country_select_modal.html';
className += ' mobile_modal'; className += ' mobile_modal';
} }
var modal = $modal.open({ var modal = $modal.open({
templateUrl: tUrl, templateUrl: templateUrl('country_select_modal'),
controller: 'CountrySelectModalController', controller: 'CountrySelectModalController',
windowClass: className windowClass: className
}); });
@ -62,7 +59,7 @@ angular.module('myApp.controllers', [])
function initPhoneCountry () { function initPhoneCountry () {
var langCode = (navigator.language || '').toLowerCase(), var langCode = (navigator.language || '').toLowerCase(),
countryIso2 = Config.LangCountries[langCode], countryIso2 = Config.LangCountries[langCode],
shouldPregenerate = !Config.Navigator.mobile; shouldPregenerate = !Config.Mobile;
if (['en', 'en-us', 'en-uk'].indexOf(langCode) == -1) { if (['en', 'en-us', 'en-uk'].indexOf(langCode) == -1) {
if (countryIso2 !== undefined) { if (countryIso2 !== undefined) {
@ -316,16 +313,13 @@ angular.module('myApp.controllers', [])
$scope.historyState = {selectActions: false, typing: []}; $scope.historyState = {selectActions: false, typing: []};
$scope.openSettings = function () { $scope.openSettings = function () {
var tUrl = 'partials/settings_modal.html', var className = 'settings_modal_window page_modal';
className = 'settings_modal_window page_modal'; if (Config.Mobile) {
if (Config.Navigator.mobile) {
tUrl = 'partials/mobile/settings_modal.html';
className += ' mobile_modal'; className += ' mobile_modal';
} }
$modal.open({ $modal.open({
templateUrl: tUrl, templateUrl: templateUrl('settings_modal'),
controller: 'SettingsModalController', controller: 'SettingsModalController',
windowClass: className windowClass: className
}); });
@ -347,7 +341,7 @@ angular.module('myApp.controllers', [])
scope.userIDs = userIDs; scope.userIDs = userIDs;
$modal.open({ $modal.open({
templateUrl: 'partials/chat_create_modal.html', templateUrl: templateUrl('chat_create_modal'),
controller: 'ChatCreateModalController', controller: 'ChatCreateModalController',
scope: scope, scope: scope,
windowClass: 'group_edit_modal_window' windowClass: 'group_edit_modal_window'
@ -535,7 +529,7 @@ angular.module('myApp.controllers', [])
} }
}); });
if (Config.Navigator.mobile) { if (Config.Mobile) {
$scope.$watch('curDialog.peer', function () { $scope.$watch('curDialog.peer', function () {
$scope.$broadcast('ui_dialogs_update') $scope.$broadcast('ui_dialogs_update')
}); });
@ -879,7 +873,7 @@ angular.module('myApp.controllers', [])
var curJump = jump, var curJump = jump,
curMoreJump = moreJump, curMoreJump = moreJump,
inputMediaFilter = $scope.historyFilter.mediaType && {_: inputMediaFilters[$scope.historyFilter.mediaType]}, inputMediaFilter = $scope.historyFilter.mediaType && {_: inputMediaFilters[$scope.historyFilter.mediaType]},
limit = Config.Navigator.mobile ? 20 : 0, limit = Config.Mobile ? 20 : 0,
getMessagesPromise = inputMediaFilter getMessagesPromise = inputMediaFilter
? AppMessagesManager.getSearch($scope.curDialog.inputPeer, '', inputMediaFilter, maxID, limit) ? AppMessagesManager.getSearch($scope.curDialog.inputPeer, '', inputMediaFilter, maxID, limit)
: AppMessagesManager.getHistory($scope.curDialog.inputPeer, maxID, limit); : AppMessagesManager.getHistory($scope.curDialog.inputPeer, maxID, limit);
@ -920,7 +914,7 @@ angular.module('myApp.controllers', [])
else if (forceRecent) { else if (forceRecent) {
limit = 10; limit = 10;
} }
else if (Config.Navigator.mobile) { else if (Config.Mobile) {
limit = 20; limit = 20;
} }
@ -1330,7 +1324,7 @@ angular.module('myApp.controllers', [])
AppPhotosManager.downloadPhoto($scope.photoID); AppPhotosManager.downloadPhoto($scope.photoID);
}; };
if (!$scope.messageID || Config.Navigator.mobile) { if (!$scope.messageID || Config.Mobile) {
$scope.nav.next = function () { $scope.nav.next = function () {
$modalInstance.close(); $modalInstance.close();
} }
@ -1352,7 +1346,7 @@ angular.module('myApp.controllers', [])
}; };
if (Config.Navigator.mobile) { if (Config.Mobile) {
$scope.canForward = true; $scope.canForward = true;
$scope.canDelete = true; $scope.canDelete = true;
return; return;
@ -1676,7 +1670,7 @@ angular.module('myApp.controllers', [])
}; };
$modal.open({ $modal.open({
templateUrl: edit ? 'partials/edit_contact_modal.html' : 'partials/import_contact_modal.html', templateUrl: templateUrl(edit ? 'edit_contact_modal' : 'import_contact_modal'),
controller: 'ImportContactModalController', controller: 'ImportContactModalController',
windowClass: 'import_contact_modal_window page_modal', windowClass: 'import_contact_modal_window page_modal',
scope: scope scope: scope
@ -1873,7 +1867,7 @@ angular.module('myApp.controllers', [])
scope.chatID = $scope.chatID; scope.chatID = $scope.chatID;
$modal.open({ $modal.open({
templateUrl: 'partials/chat_edit_modal.html', templateUrl: templateUrl('chat_edit_modal'),
controller: 'ChatEditModalController', controller: 'ChatEditModalController',
scope: scope, scope: scope,
windowClass: 'group_edit_modal_window' windowClass: 'group_edit_modal_window'
@ -1966,7 +1960,7 @@ angular.module('myApp.controllers', [])
$scope.editProfile = function () { $scope.editProfile = function () {
$modal.open({ $modal.open({
templateUrl: 'partials/profile_edit_modal.html', templateUrl: templateUrl('profile_edit_modal'),
controller: 'ProfileEditModalController', controller: 'ProfileEditModalController',
windowClass: 'profile_edit_modal_window page_modal' windowClass: 'profile_edit_modal_window page_modal'
}); });

44
app/js/directives.js

@ -15,61 +15,61 @@ angular.module('myApp.directives', ['myApp.filters'])
.directive('myHead', function() { .directive('myHead', function() {
return { return {
restrict: 'AE', restrict: 'AE',
templateUrl: 'partials/head.html' templateUrl: templateUrl('head')
}; };
}) })
.directive('myDialog', function() { .directive('myDialog', function() {
return { return {
restrict: 'AE', restrict: 'AE',
templateUrl: 'partials/dialog.html' templateUrl: templateUrl('dialog')
}; };
}) })
.directive('myMessage', function() { .directive('myMessage', function() {
return { return {
templateUrl: 'partials/message.html' templateUrl: templateUrl('message')
}; };
}) })
.directive('myServiceMessage', function() { .directive('myServiceMessage', function() {
return { return {
templateUrl: 'partials/message_service.html' templateUrl: templateUrl('message_service')
}; };
}) })
.directive('myMessagePhoto', function() { .directive('myMessagePhoto', function() {
return { return {
templateUrl: 'partials/message_attach_photo.html' templateUrl: templateUrl('message_attach_photo')
}; };
}) })
.directive('myMessageVideo', function() { .directive('myMessageVideo', function() {
return { return {
templateUrl: 'partials/message_attach_video.html' templateUrl: templateUrl('message_attach_video')
}; };
}) })
.directive('myMessageDocument', function() { .directive('myMessageDocument', function() {
return { return {
templateUrl: 'partials/message_attach_document.html' templateUrl: templateUrl('message_attach_document')
}; };
}) })
.directive('myMessageAudio', function() { .directive('myMessageAudio', function() {
return { return {
templateUrl: 'partials/message_attach_audio.html' templateUrl: templateUrl('message_attach_audio')
}; };
}) })
.directive('myMessageMap', function() { .directive('myMessageMap', function() {
return { return {
templateUrl: 'partials/message_attach_map.html' templateUrl: templateUrl('message_attach_map')
}; };
}) })
.directive('myMessageContact', function() { .directive('myMessageContact', function() {
return { return {
templateUrl: 'partials/message_attach_contact.html' templateUrl: templateUrl('message_attach_contact')
}; };
}) })
.directive('myMessagePending', function() { .directive('myMessagePending', function() {
return { return {
templateUrl: 'partials/message_attach_pending.html' templateUrl: templateUrl('message_attach_pending')
}; };
}) })
@ -241,7 +241,7 @@ angular.module('myApp.directives', ['myApp.filters'])
dialogsColWrap = $('.im_dialogs_col_wrap')[0], dialogsColWrap = $('.im_dialogs_col_wrap')[0],
scrollableWrap = $('.im_dialogs_scrollable_wrap', element)[0], scrollableWrap = $('.im_dialogs_scrollable_wrap', element)[0],
headWrap = $('.tg_page_head')[0], headWrap = $('.tg_page_head')[0],
panelWrapSelector = Config.Navigator.mobile && attrs.modal panelWrapSelector = Config.Mobile && attrs.modal
? '.mobile_modal_body .im_dialogs_panel' ? '.mobile_modal_body .im_dialogs_panel'
: '.im_dialogs_panel', : '.im_dialogs_panel',
panelWrap = $(panelWrapSelector)[0], panelWrap = $(panelWrapSelector)[0],
@ -311,7 +311,7 @@ angular.module('myApp.directives', ['myApp.filters'])
$(element).css({ $(element).css({
height: $($window).height() - height: $($window).height() -
(panelWrap ? panelWrap.offsetHeight : 58) - (panelWrap ? panelWrap.offsetHeight : 58) -
(Config.Navigator.mobile ? 46 : 200) (Config.Mobile ? 46 : 200)
}); });
updateScroller(); updateScroller();
return; return;
@ -367,7 +367,7 @@ angular.module('myApp.directives', ['myApp.filters'])
height: $($window).height() - height: $($window).height() -
(panelWrap && panelWrap.offsetHeight || 0) - (panelWrap && panelWrap.offsetHeight || 0) -
(searchWrap && searchWrap.offsetHeight || 0) - (searchWrap && searchWrap.offsetHeight || 0) -
(Config.Navigator.mobile ? 64 : 200) (Config.Mobile ? 64 : 200)
}); });
$(contactsWrap).nanoScroller(); $(contactsWrap).nanoScroller();
} }
@ -401,7 +401,7 @@ angular.module('myApp.directives', ['myApp.filters'])
height: $($window).height() height: $($window).height()
- (panelWrap && panelWrap.offsetHeight || 0) - (panelWrap && panelWrap.offsetHeight || 0)
- (searchWrap && searchWrap.offsetHeight || 0) - (searchWrap && searchWrap.offsetHeight || 0)
- (Config.Navigator.mobile ? 46 + 18 : 200) - (Config.Mobile ? 46 + 18 : 200)
}); });
$(countriesWrap).nanoScroller(); $(countriesWrap).nanoScroller();
} }
@ -679,7 +679,7 @@ angular.module('myApp.directives', ['myApp.filters'])
var marginTop = scrollableWrap.offsetHeight var marginTop = scrollableWrap.offsetHeight
- historyMessagesEl.offsetHeight - historyMessagesEl.offsetHeight
- 20 - 20
- (Config.Navigator.mobile ? 0 : 49); - (Config.Mobile ? 0 : 49);
if (historyMessagesEl.offsetHeight > 0 && marginTop > 0) { if (historyMessagesEl.offsetHeight > 0 && marginTop > 0) {
$(historyMessagesEl).css({marginTop: marginTop}); $(historyMessagesEl).css({marginTop: marginTop});
@ -743,7 +743,7 @@ angular.module('myApp.directives', ['myApp.filters'])
var self = this; var self = this;
$scope.$apply(function () { $scope.$apply(function () {
$scope.draftMessage.files = Array.prototype.slice.call(self.files); $scope.draftMessage.files = Array.prototype.slice.call(self.files);
$scope.draftMessage.isMedia = $(self).hasClass('im_media_attach_input') || Config.Navigator.mobile; $scope.draftMessage.isMedia = $(self).hasClass('im_media_attach_input') || Config.Mobile;
setTimeout(function () { setTimeout(function () {
try { try {
self.value = ''; self.value = '';
@ -1054,7 +1054,7 @@ angular.module('myApp.directives', ['myApp.filters'])
return { return {
link: link, link: link,
transclude: true, transclude: true,
templateUrl: 'partials/full_photo.html', templateUrl: templateUrl('full_photo'),
scope: { scope: {
fullPhoto: '=', fullPhoto: '=',
thumbLocation: '=' thumbLocation: '='
@ -1133,7 +1133,7 @@ angular.module('myApp.directives', ['myApp.filters'])
return { return {
link: link, link: link,
transclude: true, transclude: true,
templateUrl: 'partials/full_video.html', templateUrl: templateUrl('full_video'),
scope: { scope: {
video: '=' video: '='
} }
@ -1196,7 +1196,7 @@ angular.module('myApp.directives', ['myApp.filters'])
return { return {
link: link, link: link,
templateUrl: 'partials/full_gif.html', templateUrl: templateUrl('full_gif'),
scope: { scope: {
document: '=' document: '='
} }
@ -1393,7 +1393,7 @@ angular.module('myApp.directives', ['myApp.filters'])
function link($scope, element, attrs) { function link($scope, element, attrs) {
attrs.$observe('myModalWidth', function (newW) { attrs.$observe('myModalWidth', function (newW) {
$(element[0].parentNode.parentNode).css({width: parseInt(newW) + (Config.Navigator.mobile ? 0 : 36)}); $(element[0].parentNode.parentNode).css({width: parseInt(newW) + (Config.Mobile ? 0 : 36)});
}); });
}; };
@ -1496,7 +1496,7 @@ angular.module('myApp.directives', ['myApp.filters'])
function link($scope, element, attrs) { function link($scope, element, attrs) {
var updateMargin = function () { var updateMargin = function () {
if (Config.Navigator.mobile && if (Config.Mobile &&
$(element[0].parentNode.parentNode.parentNode).hasClass('page_modal')) { $(element[0].parentNode.parentNode.parentNode).hasClass('page_modal')) {
return; return;
} }

2
app/js/filters.js

@ -78,7 +78,7 @@ angular.module('myApp.filters', [])
.filter('time', ['$filter', function($filter) { .filter('time', ['$filter', function($filter) {
var cachedDates = {}, var cachedDates = {},
dateFilter = $filter('date'), dateFilter = $filter('date'),
format = Config.Navigator.mobile ? 'HH:mm' : 'HH:mm:ss'; format = Config.Mobile ? 'HH:mm' : 'HH:mm:ss';
return function (timestamp) { return function (timestamp) {
if (cachedDates[timestamp]) { if (cachedDates[timestamp]) {

28
app/js/init.js

@ -1,4 +1,4 @@
;(function () { ;(function initAutoUpgrade () {
// Prevent click-jacking // Prevent click-jacking
try { try {
@ -61,3 +61,29 @@
scheduleUpdate(3000); scheduleUpdate(3000);
window.addEventListener('load', attach); window.addEventListener('load', attach);
})(); })();
(function initApplication () {
var classes = [
Config.Navigator.osX ? 'osx' : 'non_osx',
Config.Navigator.retina ? 'is_2x' : 'is_1x'
];
if (Config.Modes.ios_standalone) {
classes.push('ios_standalone');
}
$(document.body).addClass(classes.join(' '));
ConfigStorage.get('current_layout', function (layout) {
switch (layout) {
case 'mobile': Config.Mobile = true; break;
case 'desktop': Config.Mobile = false; break;
default: Config.Mobile = Config.Mobile; break;
}
$('head').append(
'<link rel="stylesheet" href="css/' + (Config.Mobile ? 'mobile.css' : 'desktop.css') + '" />'
);
$(document).ready(function() {
angular.bootstrap(document, ['myApp']);
});
});
})();

129
app/js/lib/config.js

File diff suppressed because one or more lines are too long

129
app/js/lib/ng_utils.js

@ -9,127 +9,26 @@ angular.module('izhukov.utils', [])
.provider('Storage', function () { .provider('Storage', function () {
var keyPrefix = '';
var cache = {};
var useCs = !!(window.chrome && chrome.storage && chrome.storage.local);
var useLs = !useCs && !!window.localStorage;
this.setPrefix = function (newPrefix) { this.setPrefix = function (newPrefix) {
keyPrefix = newPrefix ConfigStorage.prefix(newPrefix);
}; };
this.$get = ['$q', function ($q) { this.$get = ['$q', function ($q) {
function getValue() { var methods = {};
var keys = Array.prototype.slice.call(arguments), angular.forEach(['get', 'set', 'remove'], function (methodName) {
result = [], methods[methodName] = function () {
single = keys.length == 1, var deferred = $q.defer(),
allFound = true; args = Array.prototype.slice.call(arguments);
for (var i = 0; i < keys.length; i++) {
keys[i] = keyPrefix + keys[i];
}
angular.forEach(keys, function (key) {
if (cache[key] !== undefined) {
result.push(cache[key]);
}
else if (useLs) {
var value = localStorage.getItem(key);
value = (value === undefined || value === null) ? false : JSON.parse(value);
result.push(cache[key] = value);
}
else if (!useCs) {
result.push(cache[key] = false);
}
else {
allFound = false;
}
});
if (allFound) {
return $q.when(single ? result[0] : result);
}
var deferred = $q.defer();
chrome.storage.local.get(keys, function (resultObj) {
result = [];
angular.forEach(keys, function (key) {
var value = resultObj[key];
value = value === undefined || value === null ? false : JSON.parse(value);
result.push(cache[key] = value);
});
deferred.resolve(single ? result[0] : result);
});
return deferred.promise;
};
function setValue(obj) {
var keyValues = {};
angular.forEach(obj, function (value, key) {
keyValues[keyPrefix + key] = JSON.stringify(value);
cache[keyPrefix + key] = value;
});
if (useLs) {
angular.forEach(keyValues, function (value, key) {
localStorage.setItem(key, value);
});
return $q.when();
}
if (!useCs) {
return $q.when();
}
var deferred = $q.defer();
chrome.storage.local.set(keyValues, function () {
deferred.resolve();
});
return deferred.promise;
};
function removeValue () {
var keys = Array.prototype.slice.call(arguments);
for (var i = 0; i < keys.length; i++) {
keys[i] = keyPrefix + keys[i];
}
angular.forEach(keys, function(key){
delete cache[key];
});
if (useLs) { args.push(function (result) {
angular.forEach(keys, function(key){ deferred.resolve(result);
localStorage.removeItem(key);
}); });
ConfigStorage[methodName].apply(ConfigStorage, args);
return $q.when(); return deferred.promise;
} };
});
if (!useCs) { return methods;
return $q.when();
}
var deferred = $q.defer();
chrome.storage.local.remove(keys, function () {
deferred.resolve();
});
return deferred.promise;
};
return {
get: getValue,
set: setValue,
remove: removeValue
};
}]; }];
}) })
@ -284,7 +183,7 @@ angular.module('izhukov.utils', [])
} }
function downloadFile (url, mimeType, fileName) { function downloadFile (url, mimeType, fileName) {
// if (Config.Navigator.mobile) { // if (Config.Mobile) {
// window.open(url, '_blank'); // window.open(url, '_blank');
// return; // return;
// } // }

4
app/js/lib/utils.js

@ -135,3 +135,7 @@ if (!Function.prototype.bind) {
}; };
} }
function templateUrl (tplName) {
return 'partials/' + (Config.Navigator.mobile ? 'mobile' : 'desktop') + '/' + tplName + '.html';
}

57
app/js/services.js

@ -180,16 +180,13 @@ angular.module('myApp.services', [])
var scope = $rootScope.$new(); var scope = $rootScope.$new();
scope.userID = userID; scope.userID = userID;
var tUrl = 'partials/user_modal.html', var className = 'user_modal_window page_modal';
className = 'user_modal_window page_modal'; if (Config.Mobile) {
if (Config.Navigator.mobile) {
tUrl = 'partials/mobile/user_modal.html';
className += ' mobile_modal'; className += ' mobile_modal';
} }
var modalInstance = $modal.open({ var modalInstance = $modal.open({
templateUrl: tUrl, templateUrl: templateUrl('user_modal'),
controller: 'UserModalController', controller: 'UserModalController',
scope: scope, scope: scope,
windowClass: className windowClass: className
@ -283,7 +280,7 @@ angular.module('myApp.services', [])
function openImportContact () { function openImportContact () {
return $modal.open({ return $modal.open({
templateUrl: 'partials/import_contact_modal.html', templateUrl: templateUrl('import_contact_modal'),
controller: 'ImportContactModalController', controller: 'ImportContactModalController',
windowClass: 'import_contact_modal_window' windowClass: 'import_contact_modal_window'
}).result.then(function (foundUserID) { }).result.then(function (foundUserID) {
@ -358,7 +355,7 @@ angular.module('myApp.services', [])
}; };
function isAvailable () { function isAvailable () {
if (Config.Navigator.mobile && Config.Navigator.ffos && Config.Modes.packed) { if (Config.Mobile && Config.Navigator.ffos && Config.Modes.packed) {
try { try {
return navigator.mozContacts && navigator.mozContacts.getAll; return navigator.mozContacts && navigator.mozContacts.getAll;
} catch (e) { } catch (e) {
@ -371,7 +368,7 @@ angular.module('myApp.services', [])
function openPhonebookImport () { function openPhonebookImport () {
return $modal.open({ return $modal.open({
templateUrl: 'partials/mobile/phonebook_modal.html', templateUrl: templateUrl('phonebook_modal'),
controller: 'PhonebookModalController', controller: 'PhonebookModalController',
windowClass: 'phonebook_modal_window page_modal mobile_modal' windowClass: 'phonebook_modal_window page_modal mobile_modal'
}); });
@ -516,16 +513,13 @@ angular.module('myApp.services', [])
var scope = $rootScope.$new(); var scope = $rootScope.$new();
scope.chatID = chatID; scope.chatID = chatID;
var tUrl = 'partials/chat_modal.html', var className = 'chat_modal_window page_modal';
className = 'chat_modal_window page_modal'; if (Config.Mobile) {
if (Config.Navigator.mobile) {
tUrl = 'partials/mobile/chat_modal.html';
className += ' mobile_modal'; className += ' mobile_modal';
} }
var modalInstance = $modal.open({ var modalInstance = $modal.open({
templateUrl: tUrl, templateUrl: templateUrl('chat_modal'),
controller: 'ChatModalController', controller: 'ChatModalController',
scope: scope, scope: scope,
windowClass: className windowClass: className
@ -2058,7 +2052,7 @@ angular.module('myApp.services', [])
$rootScope.$broadcast('dialogs_update', dialog); $rootScope.$broadcast('dialogs_update', dialog);
if ((Config.Navigator.mobile && $rootScope.selectedPeerID != peerID || $rootScope.idle.isIDLE) && if ((Config.Mobile && $rootScope.selectedPeerID != peerID || $rootScope.idle.isIDLE) &&
!message.out && !message.out &&
message.unread) { message.unread) {
NotificationsManager.getPeerMuted(peerID).then(function (muted) { NotificationsManager.getPeerMuted(peerID).then(function (muted) {
@ -2321,7 +2315,7 @@ angular.module('myApp.services', [])
function wrapForFull (photoID) { function wrapForFull (photoID) {
var photo = wrapForHistory(photoID), var photo = wrapForHistory(photoID),
fullWidth = $(window).width() - (Config.Navigator.mobile ? 20 : 36), fullWidth = $(window).width() - (Config.Mobile ? 20 : 36),
fullHeight = $($window).height() - 150, fullHeight = $($window).height() - 150,
fullPhotoSize = choosePhotoSize(photo, fullWidth, fullHeight), fullPhotoSize = choosePhotoSize(photo, fullWidth, fullHeight),
full = { full = {
@ -2347,7 +2341,7 @@ angular.module('myApp.services', [])
} }
} }
if (!Config.Navigator.mobile && full.width >= fullPhotoSize.w && full.height >= fullPhotoSize.h) { if (!Config.Mobile && full.width >= fullPhotoSize.w && full.height >= fullPhotoSize.h) {
full.width = fullPhotoSize.w; full.width = fullPhotoSize.w;
full.height = fullPhotoSize.h; full.height = fullPhotoSize.h;
} }
@ -2379,7 +2373,7 @@ angular.module('myApp.services', [])
} }
var modalInstance = $modal.open({ var modalInstance = $modal.open({
templateUrl: 'partials/photo_modal.html', templateUrl: templateUrl('photo_modal'),
controller: scope.userID ? 'UserpicModalController' : 'PhotoModalController', controller: scope.userID ? 'UserpicModalController' : 'PhotoModalController',
scope: scope, scope: scope,
windowClass: 'photo_modal_window' windowClass: 'photo_modal_window'
@ -2534,7 +2528,7 @@ angular.module('myApp.services', [])
scope.messageID = messageID; scope.messageID = messageID;
var modalInstance = $modal.open({ var modalInstance = $modal.open({
templateUrl: 'partials/video_modal.html', templateUrl: templateUrl('video_modal'),
controller: 'VideoModalController', controller: 'VideoModalController',
scope: scope, scope: scope,
windowClass: 'video_modal_window' windowClass: 'video_modal_window'
@ -3730,7 +3724,7 @@ angular.module('myApp.services', [])
shownBoxes++; shownBoxes++;
var modal = $modal.open({ var modal = $modal.open({
templateUrl: 'partials/error_modal.html', templateUrl: templateUrl('error_modal'),
scope: scope, scope: scope,
windowClass: options.windowClass || 'error_modal_window' windowClass: options.windowClass || 'error_modal_window'
}); });
@ -3755,7 +3749,7 @@ angular.module('myApp.services', [])
angular.extend(scope, params); angular.extend(scope, params);
var modal = $modal.open({ var modal = $modal.open({
templateUrl: 'partials/confirm_modal.html', templateUrl: templateUrl('confirm_modal'),
scope: scope, scope: scope,
windowClass: options.windowClass || 'confirm_modal_window' windowClass: options.windowClass || 'confirm_modal_window'
}); });
@ -3791,16 +3785,14 @@ angular.module('myApp.services', [])
angular.extend(scope, options); angular.extend(scope, options);
} }
var tUrl = 'partials/peer_select.html', var className = 'peer_select_window page_modal';
className = 'peer_select_window page_modal';
if (Config.Navigator.mobile) { if (Config.Mobile) {
tUrl = 'partials/mobile/peer_select.html';
className += ' mobile_modal'; className += ' mobile_modal';
} }
return $modal.open({ return $modal.open({
templateUrl: tUrl, templateUrl: templateUrl('peer_select'),
controller: 'PeerSelectController', controller: 'PeerSelectController',
scope: scope, scope: scope,
windowClass: className windowClass: className
@ -3826,16 +3818,13 @@ angular.module('myApp.services', [])
scope.action = 'select'; scope.action = 'select';
} }
var tUrl = 'partials/contacts_modal.html', var className = 'contacts_modal_window page_modal';
className = 'contacts_modal_window page_modal'; if (Config.Mobile) {
if (Config.Navigator.mobile) {
tUrl = 'partials/mobile/contacts_modal.html';
className += ' mobile_modal'; className += ' mobile_modal';
} }
return $modal.open({ return $modal.open({
templateUrl: tUrl, templateUrl: templateUrl('contacts_modal'),
controller: 'ContactsModalController', controller: 'ContactsModalController',
scope: scope, scope: scope,
windowClass: className windowClass: className
@ -3906,7 +3895,7 @@ angular.module('myApp.services', [])
}; };
$modal.open({ $modal.open({
templateUrl: 'partials/changelog_modal.html', templateUrl: templateUrl('changelog_modal'),
scope: $scope, scope: $scope,
windowClass: 'changelog_modal_window page_modal' windowClass: 'changelog_modal_window page_modal'
}); });

0
app/partials/changelog_modal.html → app/partials/desktop/changelog_modal.html

0
app/partials/chat_create_modal.html → app/partials/desktop/chat_create_modal.html

0
app/partials/chat_edit_modal.html → app/partials/desktop/chat_edit_modal.html

0
app/partials/chat_modal.html → app/partials/desktop/chat_modal.html

0
app/partials/confirm_modal.html → app/partials/desktop/confirm_modal.html

0
app/partials/contacts_modal.html → app/partials/desktop/contacts_modal.html

0
app/partials/country_select_modal.html → app/partials/desktop/country_select_modal.html

0
app/partials/dialog.html → app/partials/desktop/dialog.html

0
app/partials/edit_contact_modal.html → app/partials/desktop/edit_contact_modal.html

0
app/partials/error_modal.html → app/partials/desktop/error_modal.html

0
app/partials/full_gif.html → app/partials/desktop/full_gif.html

0
app/partials/full_photo.html → app/partials/desktop/full_photo.html

0
app/partials/full_video.html → app/partials/desktop/full_video.html

0
app/partials/head.html → app/partials/desktop/head.html

0
app/partials/im.html → app/partials/desktop/im.html

0
app/partials/import_contact_modal.html → app/partials/desktop/import_contact_modal.html

0
app/partials/login.html → app/partials/desktop/login.html

0
app/partials/message.html → app/partials/desktop/message.html

0
app/partials/message_attach_audio.html → app/partials/desktop/message_attach_audio.html

0
app/partials/message_attach_contact.html → app/partials/desktop/message_attach_contact.html

0
app/partials/message_attach_document.html → app/partials/desktop/message_attach_document.html

0
app/partials/message_attach_map.html → app/partials/desktop/message_attach_map.html

0
app/partials/message_attach_pending.html → app/partials/desktop/message_attach_pending.html

0
app/partials/message_attach_photo.html → app/partials/desktop/message_attach_photo.html

0
app/partials/message_attach_video.html → app/partials/desktop/message_attach_video.html

0
app/partials/message_service.html → app/partials/desktop/message_service.html

0
app/partials/peer_select.html → app/partials/desktop/peer_select.html

0
app/partials/photo_modal.html → app/partials/desktop/photo_modal.html

0
app/partials/profile_edit_modal.html → app/partials/desktop/profile_edit_modal.html

0
app/partials/settings_modal.html → app/partials/desktop/settings_modal.html

0
app/partials/user_modal.html → app/partials/desktop/user_modal.html

0
app/partials/video_modal.html → app/partials/desktop/video_modal.html

0
app/partials/welcome.html → app/partials/desktop/welcome.html

199
app/partials/mobile/changelog_modal.html

@ -0,0 +1,199 @@
<div class="changelog_modal_wrap" my-modal-position>
<a class="modal-close-button" ng-click="$close()"><i></i></a>
<div class="modal-body">
<div class="changelog_card_wrap" ng-switch="lastVersion === false">
<div ng-switch-when="true">
<div class="changelog_card"></div>
<h2 class="changelog_header">Recent updates in <strong>Telegram Web</strong></h2>
</div>
<div ng-switch-default>
<div class="changelog_card"></div>
<h2 class="changelog_header"><strong>Telegram Web</strong> has been updated!</h2>
</div>
</div>
<div class="changelog_versions_wrap">
<div class="modal_section changelog_version_wrap">
<h3 class="modal_section_header changelog_version_title">
<span class="pull-right">current version</span>
Version 0.3.0
</h3>
<div class="modal_section_body changelog_version_changes">
<ul class="list-unstyled changelog_version_changes_list">
<li>Added online statuses automatic update</li>
<li>Fixed scrollbar invalid width bug</li>
<li>[Desktop] Added phone country detection</li>
<li>[FirefoxOS] Improved PUSH-notifications for &lt;= 1.1</li>
<li>[FirefoxOS] Fixed emoji in notifications</li>
<li>[FirefoxOS] Fixed attachment bug for &lt;= 1.1</li>
<li>[FirefoxOS] Added phonebook permissions handling</li>
<li>[FirefoxOS] Added ability to share Gallery photos in Telegram</li>
<li>Supported international hashtags in messages</li>
</ul>
</div>
</div>
<div class="modal_section changelog_version_wrap">
<h3 class="modal_section_header changelog_version_title">
Version 0.2.9
</h3>
<div class="modal_section_body changelog_version_changes">
<ul class="list-unstyled changelog_version_changes_list">
<li>Updated mobile layout</li>
<li>Bugfixes</li>
</ul>
</div>
</div>
<div class="modal_section changelog_version_wrap">
<h3 class="modal_section_header changelog_version_title">
Version 0.2.5
</h3>
<div class="modal_section_body changelog_version_changes">
<ul class="list-unstyled changelog_version_changes_list">
<li>Updated mobile layout</li>
<li>Improved performance</li>
<li>Improved messages grouping</li>
<li>[FirefoxOS] Fixed notifications for &lt;= 1.1</li>
<li>[FirefoxOS] Fixed phonebook import</li>
</ul>
</div>
</div>
<div class="modal_section changelog_version_wrap">
<h3 class="modal_section_header changelog_version_title">
Version 0.2.1
</h3>
<div class="modal_section_body changelog_version_changes">
<ul class="list-unstyled changelog_version_changes_list">
<li>Improved key generation performance on slow devices</li>
<li>Added network sleep for mobile devices</li>
<li>[FirefoxOS] Added support of PUSH notifications</li>
</ul>
</div>
</div>
<div class="modal_section changelog_version_wrap">
<h3 class="modal_section_header changelog_version_title">
Version 0.2
</h3>
<div class="modal_section_body changelog_version_changes">
<ul class="list-unstyled changelog_version_changes_list">
<li>Updated contacts list, added edit mode</li>
<li>First Firefox OS release. See <a href="https://marketplace.firefox.com/app/telegram" target="_blank">Firefox Marketplace</a></li>
</ul>
</div>
</div>
<div class="modal_section changelog_version_wrap" ng-show="canShowVersion('0.1.9')">
<h3 class="modal_section_header changelog_version_title">
Version 0.1.9
</h3>
<div class="modal_section_body changelog_version_changes">
<ul class="list-unstyled changelog_version_changes_list">
<li>Improvements of performance</li>
<li>Bugfixes</li>
</ul>
</div>
</div>
<div class="modal_section changelog_version_wrap" ng-show="canShowVersion('0.1.8')">
<h3 class="modal_section_header changelog_version_title">
Version 0.1.8
</h3>
<div class="modal_section_body changelog_version_changes">
<ul class="list-unstyled changelog_version_changes_list">
<li>Improved mobile layout</li>
<li>Bugfixes</li>
</ul>
</div>
</div>
<div class="modal_section changelog_version_wrap" ng-show="canShowVersion('0.1.7')">
<h3 class="modal_section_header changelog_version_title">
Version 0.1.7
</h3>
<div class="modal_section_body changelog_version_changes">
<ul class="list-unstyled changelog_version_changes_list">
<li>Improved mobile layout</li>
<li>Added file cache for Firefox and Android</li>
<li>New design for forwarded messages</li>
<li>Hash-tags support</li>
<li>Messaging bugfixes</li>
</ul>
</div>
</div>
<div class="modal_section changelog_version_wrap" ng-show="canShowVersion('0.1.6')">
<h3 class="modal_section_header changelog_version_title">
Version 0.1.6
</h3>
<div class="modal_section_body changelog_version_changes">
<ul class="list-unstyled changelog_version_changes_list">
<li>Added search of messages</li>
<li>Improved performance of chats with lots of unread messages</li>
<li>Bugfixes</li>
</ul>
</div>
</div>
<div class="modal_section changelog_version_wrap" ng-show="canShowVersion('0.1.5')">
<h3 class="modal_section_header changelog_version_title">
Version 0.1.5
</h3>
<div class="modal_section_body changelog_version_changes">
<ul class="list-unstyled changelog_version_changes_list">
<li>Added registration</li>
<li>Improved experience for newly registered users</li>
</ul>
</div>
</div>
<div class="modal_section changelog_version_wrap" ng-show="canShowVersion('0.1.4')">
<h3 class="modal_section_header changelog_version_title">
Version 0.1.4
</h3>
<div class="modal_section_body changelog_version_changes">
<ul class="list-unstyled changelog_version_changes_list">
<li>Browse userpic history (click on the photo in user info)</li>
<li>New <a href="https://github.com/zhukov/webogram" target="_blank" title="Source code on GitHub">GitHub</a>, <a href="https://twitter.com/telegram_web" target="_blank" title="Follow us on Twitter!">Twitter</a> buttons in Settings</li>
<li>Updated keyboard shortcuts:</li>
<ul>
<li><strong>Alt+Home</strong> - switch to first (most recent) conversation</li>
<li>Removed <strong>Alt+1, 2, 3..</strong> shortcuts due to conflicts in different browsers</li>
</ul>
</ul>
</div>
</div>
<div class="modal_section changelog_version_wrap" ng-show="canShowVersion('0.1.3')">
<h3 class="modal_section_header changelog_version_title">
Version 0.1.3
</h3>
<div class="modal_section_body changelog_version_changes">
<ul class="list-unstyled changelog_version_changes_list">
<li>Added version history to welcome screen</li>
<li>Added keyboard shortcuts:</li>
<ul>
<li><strong>Tab</strong> - set focus to message field</li>
<li><strong>Esc</strong> or <strong>Shift+Tab</strong> - set focus to search field</li>
<li><strong>Up/Down</strong> (while in search field) - move between conversations</li>
<li><strong>Enter</strong> (while in search field) - open selected or first conversation</li>
<li><strong>Alt+Up/Down</strong> - move to previous/next conversation</li>
</ul>
<li>Improved grouping for messages</li>
<li>Fixed video modal positioning bug</li>
<li>Fixed focusing issues on mobile</li>
</ul>
</div>
</div>
</div>
</div>
</div>

24
app/partials/mobile/chat_create_modal.html

@ -0,0 +1,24 @@
<div class="contacts_modal_wrap" my-modal-position>
<a class="modal-close-button" ng-click="$dismiss()"><i></i></a>
<div class="modal-body">
<form class="modal_simple_form" ng-submit="createGroup()">
<h4>Create Group</h4>
<div class="form-group">
<input class="form-control input-sm" my-focused type="text" placeholder="Group name" ng-model="group.name"/>
</div>
</form>
</div>
<div class="modal-footer">
<a class="btn btn-link" ng-click="$dismiss()">Cancel</a>
<button class="btn btn-primary" ng-class="{disabled: group.creating}" ng-click="createGroup()" ng-bind="group.creating ? 'Creating...' : 'Create Group'" ng-disabled="group.creating"></button>
</div>
</div>

24
app/partials/mobile/chat_edit_modal.html

@ -0,0 +1,24 @@
<div class="contacts_modal_wrap" my-modal-position>
<a class="modal-close-button" ng-click="$dismiss()"><i></i></a>
<div class="modal-body">
<form class="modal_simple_form" ng-submit="updateGroup()">
<h4>Edit Group</h4>
<div class="form-group">
<input class="form-control input-sm" my-focused type="text" placeholder="Group name" ng-model="group.name"/>
</div>
</form>
</div>
<div class="modal-footer">
<a class="btn btn-link" ng-click="$dismiss()">Cancel</a>
<button class="btn btn-primary" ng-class="{disabled: group.updating}" ng-click="updateGroup()" ng-bind="group.updating ? 'Saving...' : 'Save'" ng-disabled="group.updating"></button>
</div>
</div>

65
app/partials/mobile/confirm_modal.html

@ -0,0 +1,65 @@
<div class="confirm_modal_wrap" my-modal-position>
<a class="modal-close-button" ng-click="$dismiss()"><i></i></a>
<div class="modal-body">
<div class="confirm_modal_description" ng-switch="type">
<span ng-switch-when="LOGOUT">Are you sure you want to log out?</span>
<span ng-switch-when="WEBOGRAM_UPDATED_RELOAD">A new version of Webogram has been downloaded. Launch it?</span>
<span ng-switch-when="HISTORY_FLUSH">Are you sure? This can not be undone!</span>
<span ng-switch-when="TERMINATE_SESSIONS">Are you sure you want to log out all devices except for the current one?</span>
<span ng-switch-when="HTTPS_MIXED_FAIL">
Your browser <a href="http://mzl.la/13jCUSU" target="_blank">does not support</a> mixed content which is neccessary for MTProto support on https. <a href="https://github.com/zhukov/webogram/issues/237" target="_blank">Learn more &raquo;</a><br/><br/>
Would you like use http-version instead?
</span>
<span ng-switch-when="FILES_CLIPBOARD_PASTE">
<ng-pluralize count="files.length"
when="{'one': 'Are you sure to send file from clipboard?', 'other': 'Are you sure to send {} files from clipboard?'}">
</ng-pluralize>
</span>
<span ng-switch-when="FILE_CLIPBOARD_PASTE">Are you sure to send file(s) from clipboard?</span>
<span ng-switch-when="MESSAGE_DELETE">Are you sure you want to delete the message?</span>
<span ng-switch-when="CONTACTS_IMPORT_PERFORM">Telegram will now sync your contacts in order to find your friends.</span>
<div ng-switch-when="LOGIN_PHONE_CORRECT">
Is this phone number correct?
<div class="confirm_phone_number"> <span ng-bind="country_code"></span> <span ng-bind="phone_number"></span> </div>
</div>
<span ng-switch-when="FORWARD_PEER">Forward to <strong ng-switch="peer_id > 0">
<span ng-switch-when="true" ng-bind-html="peer_data.rFullName"></span>
<span ng-switch-default ng-bind-html="peer_data.rTitle"></span>
</strong>?</span>
<span ng-switch-when="SHARE_CONTACT_PEER">Send to <strong ng-switch="peer_id > 0">
<span ng-switch-when="true" ng-bind-html="peer_data.rFullName"></span>
<span ng-switch-default ng-bind-html="peer_data.rTitle"></span>
</strong>?</span>
<span ng-switch-when="EXT_SHARE_PEER">Share with <strong ng-switch="peer_id > 0">
<span ng-switch-when="true" ng-bind-html="peer_data.rFullName"></span>
<span ng-switch-default ng-bind-html="peer_data.rTitle"></span>
</strong>?</span>
<span ng-switch-default ng-bind="message || 'Are you sure?'"></span>
</div>
</div>
<div class="modal-footer">
<a class="btn btn-link" ng-click="$dismiss()" ng-switch="type">
<span ng-switch-default>Cancel</span>
</a>
<button type="button" class="btn btn-primary" ng-switch="type" ng-click="$close()" my-focused>
<span ng-switch-when="LOGOUT">Log Out</span>
<span ng-switch-when="HISTORY_FLUSH">Delete Chat</span>
<span ng-switch-when="FILES_CLIPBOARD_PASTE">Send</span>
<span ng-switch-when="FILE_CLIPBOARD_PASTE">Send</span>
<span ng-switch-when="MESSAGE_DELETE">Delete</span>
<span ng-switch-when="FORWARD_PEER">Forward message</span>
<span ng-switch-when="PHOTO_SHARE_PEER">Forward photo</span>
<span ng-switch-when="VIDEO_SHARE_PEER">Forward video</span>
<span ng-switch-when="SHARE_CONTACT_PEER">Send contact</span>
<span ng-switch-when="EXT_SHARE_PEER">Share file</span>
<span ng-switch-default>OK</span>
</button>
</div>
</div>

89
app/partials/mobile/dialog.html

@ -0,0 +1,89 @@
<a class="im_dialog" ng-click="dialogSelect(dialogMessage.peerString, search.messages &amp;&amp; dialogMessage.id)">
<div class="im_dialog_meta pull-right text-right">
<div class="im_dialog_date" ng-bind="dialogMessage.dateText"></div>
<span
class="im_dialog_badge badge"
ng-show="dialogMessage.unreadCount > 0 &amp;&amp; !dialogMessage.out"
ng-bind="dialogMessage.unreadCount"
></span>
<i
class="im_dialog_unread"
ng-show="dialogMessage.out &amp;&amp; dialogMessage.unread"
></i>
</div>
<div class="im_dialog_photo pull-left">
<img
class="im_dialog_photo"
my-load-thumb
watch="true"
thumb="dialogMessage.peerPhoto"
/>
</div>
<div class="im_dialog_message_wrap">
<div class="im_dialog_peer" ng-switch="dialogMessage.peerID > 0">
<span class="im_dialog_user" ng-switch-when="true" ng-bind-html="dialogMessage.peerData.rFullName"></span>
<span class="im_dialog_chat" ng-switch-default>
<span ng-bind-html="dialogMessage.peerData.rTitle"></span>
</span>
</div>
<div ng-switch="dialogMessage.deleted">
<div ng-switch-when="true" class="im_dialog_message">
<span class="im_dialog_message_text">deleted message</span>
</div>
<div ng-switch-default class="im_dialog_message">
<span class="im_dialog_chat_from_wrap">
<span
class="im_dialog_chat_from"
ng-if="!dialogMessage.out &amp;&amp; dialogMessage.chatID"
ng-bind-html="dialogMessage.fromUser.rFirstName"
></span><span
class="im_dialog_chat_from"
ng-if="dialogMessage.out"
>You</span>{{((dialogMessage.out || dialogMessage.peerID &lt; 0) &amp;&amp; (dialogMessage.message.length || dialogMessage.media &amp;&amp; dialogMessage.media._ != 'messageMediaEmpty')) ? ':' : ''}}
</span>
<span class="im_dialog_message_media" ng-if="dialogMessage.media &amp;&amp; dialogMessage.media._ != 'messageMediaEmpty'" ng-switch="dialogMessage.media._">
<span ng-switch-when="messageMediaPhoto">Photo</span>
<span ng-switch-when="messageMediaVideo">Video</span>
<span ng-switch-when="messageMediaDocument">Document</span>
<span ng-switch-when="messageMediaAudio">Audio</span>
<span ng-switch-when="messageMediaGeo">Location</span>
<span ng-switch-when="messageMediaContact">Contact</span>
</span>
<span class="im_dialog_message_service" ng-if="dialogMessage._ == 'messageService'" ng-switch="dialogMessage.action._">
<span ng-switch-when="messageActionChatCreate">created the group</span>
<span ng-switch-when="messageActionChatEditTitle">changed group name</span>
<span ng-switch-when="messageActionChatEditPhoto">changed group photo</span>
<span ng-switch-when="messageActionChatDeletePhoto">removed group photo</span>
<span ng-switch-when="messageActionChatAddUser" ng-switch="dialogMessage.from_id == dialogMessage.action.user_id">
<span ng-switch-when="true">
returned to group
</span>
<span ng-switch-default>
invited <span ng-bind-html="dialogMessage.action.user.rFullName"></span>
</span>
</span>
<span ng-switch-when="messageActionChatDeleteUser" ng-switch="dialogMessage.from_id == dialogMessage.action.user_id">
<span ng-switch-when="true">
left group
</span>
<span ng-switch-default>
kicked <span ng-bind-html="dialogMessage.action.user.rFullName"></span>
</span>
</span>
</span>
<span class="im_dialog_message_text" ng-if="dialogMessage.message.length" ng-bind-html="dialogMessage.richMessage"></span>
</div>
</div>
</div>
</a>

30
app/partials/mobile/edit_contact_modal.html

@ -0,0 +1,30 @@
<div class="import_modal_wrap" my-modal-position>
<a class="modal-close-button" ng-click="$dismiss()"><i></i></a>
<div class="modal-body">
<form class="modal_simple_form" ng-submit="doImport()">
<h4>Edit contact</h4>
<div class="form-group">
<span class="form-control uneditable-input disabled" disabled ng-bind="importContact.phone | phoneNumber"></span>
</div>
<div class="form-group">
<input class="form-control input-sm" my-focused type="text" placeholder="First name" ng-model="importContact.first_name"/>
</div>
<div class="form-group">
<input class="form-control input-sm" type="text" placeholder="Last name" ng-model="importContact.last_name"/>
</div>
</form>
</div>
<div class="modal-footer">
<a class="btn btn-link" ng-click="$dismiss()">Cancel</a>
<button class="btn btn-primary" ng-class="{disabled: progress.enabled}" ng-click="doImport()" ng-bind="progress.enabled ? 'Saving...' : 'Save'" ng-disabled="progress.enabled"></button>
</div>
</div>

87
app/partials/mobile/error_modal.html

@ -0,0 +1,87 @@
<div class="error_modal_wrap" my-modal-position>
<a class="modal-close-button" ng-click="$close()"><i></i></a>
<div class="modal-body">
<h4 ng-if="error" class="modal_simple_header" ng-switch="error.type">
<span ng-switch-when="ACCOUNT_REQUIRED">No account</span>
<span ng-switch-default ng-switch="error.code">
<span ng-switch-when="400">Error</span>
<span ng-switch-when="401">Unauthorized</span>
<span ng-switch-when="403">Access denied</span>
<span ng-switch-when="404">Not found</span>
<span ng-switch-when="406">Network error</span>
<span ng-switch-when="420">Too fast</span>
<span ng-switch-default>Server error</span>
</span>
</h4>
<h4 ng-if="!error" class="modal_simple_header" ng-bind="title || 'Alert'"></h4>
<div ng-if="error" class="error_modal_description" ng-switch="error.type">
<span ng-switch-when="NETWORK_BAD_REQUEST">
Please check your internet connection.
</span>
<span ng-switch-when="NETWORK_BAD_RESPONSE">
Please check your internet connection.
</span>
<span ng-switch-when="FIRSTNAME_INVALID">
The first name you entered is invalid.
</span>
<span ng-switch-when="LASTNAME_INVALID">
The last name you entered is invalid.
</span>
<span ng-switch-when="PHONE_NUMBER_INVALID">
The phone number you entered is invalid.
</span>
<span ng-switch-when="USERS_TOO_MUCH">
You have selected too much users.
</span>
<span ng-switch-when="PHOTO_INVALID_DIMENSIONS">
The photo dimensions are invalid, please select another file.
</span>
<span ng-switch-when="VIDEO_EXT_INVALID">
The video file extension is invalid or unsupported, please select another file.
</span>
<span ng-switch-when="PHOTO_CROP_SIZE_SMALL">
The photo you provided is too small.
</span>
<span ng-switch-when="ACCOUNT_REQUIRED">
Sorry, there is no <strong>Telegram</strong> account for {{phone | phoneNumber}}<br/><br/>
Please <strong>sign up</strong> using our mobile apps for <a href="https://telegram.org/" target="_blank">iOS</a> or <a href="https://telegram.org/" target="_blank">Android</a>.
</span>
<span ng-switch-when="USER_NOT_USING_TELEGRAM">
Sorry, there is no <strong>Telegram</strong> account with the phone number you provided.
</span>
<span ng-switch-when="USERS_NOT_USING_TELEGRAM">
Sorry, there are no <strong>Telegram</strong> accounts with the phone numbers you provided.
</span>
<span ng-switch-when="PHONEBOOK_GET_CONTACTS_FAILED">
Telegram needs access to phonebook to import contacts.
</span>
<div ng-switch-default ng-switch="error.code">
<span ng-switch-when="400">One of the params is missing or invalid.</span>
<span ng-switch-when="401">This action requires authorization access. Please <a href="#/login">log in</a>.</span>
<span ng-switch-when="403">You are not allowed for this action.</span>
<span ng-switch-when="404">The page was not found.</span>
<span ng-switch-when="420">You are performing too many actions. Please try again later.</span>
<span ng-switch-default>Internal server error occured. Please try again later.</span>
</div>
</div>
<div ng-if="error" class="error_modal_details" ng-switch="error.detailsShown">
<textarea ng-switch-when="true" rows="3" onclick="this.select()">Method: {{error.input || 'N/A'}}
Result: {{error.originalError ? error.originalError : (error.stack ? (error.name || '') + ' ' + (error.description || error.message) : error)}}
Stack: {{error.stack}}</textarea>
<div ng-switch-default>
<a href="" ng-click="error.detailsShown = true">Technical details here</a>
</div>
</div>
<div ng-if="!error" class="error_modal_description" ng-bind="description"></div>
</div>
</div>

25
app/partials/mobile/full_gif.html

@ -0,0 +1,25 @@
<a class="img_gif_with_progress_wrap" ng-click="toggle()">
<div class="img_gif_image_wrap" ng-switch="document.url &amp;&amp; isActive">
<img ng-switch-when="true" class="img_gif_image" ng-src="{{document.url}}" />
<img ng-switch-default class="img_gif_thumb" my-load-thumb thumb="document.thumb" />
</div>
<div ng-show="!isActive" ng-switch="document.progress.enabled">
<div ng-switch-when="true" class="img_gif_progress_wrap">
<div class="img_gif_progress progress tg_progress">
<div class="progress-bar progress-bar-success" ng-style="{width: document.progress.percent + '%'}"></div>
</div>
</div>
<div ng-switch-default class="img_gif_info_wrap">
<div class="img_gif_label pull-left">GIF</div>
<div ng-if="!document.url" class="img_gif_size pull-right" ng-bind="::document.size | formatSize"></div>
</div>
</div>
</a>

19
app/partials/mobile/full_photo.html

@ -0,0 +1,19 @@
<div class="img_fullsize_with_progress_wrap">
<div class="img_fullsize_progress_overlay" ng-show="progress.enabled">
<div class="img_fullsize_progress_wrap">
<div class="img_fullsize_progress progress tg_progress" ng-show="progress.percent > 0">
<div class="progress-bar progress-bar-success" ng-style="{width: progress.percent + '%'}">
</div>
</div>
</div>
</div>
<div class="photo_full_wrap">
<a class="photo_modal_image">
<img class="photo_modal_image"/>
</a>
</div>
<div class="photo_modal_error_wrap" ng-if="error">
<div class="photo_modal_error" ng-if="error.html" ng-bind-html="error.html"></div>
<div class="photo_modal_error" ng-if="error.text" ng-bind="error.text"></div>
</div>
</div>

26
app/partials/mobile/full_video.html

@ -0,0 +1,26 @@
<div class="img_fullsize_with_progress_wrap" ng-style="{width: video.full.width + 'px', height: video.full.height + 'px'}">
<div class="img_fullsize_progress_overlay" ng-show="progress.enabled">
<div class="img_fullsize_progress_wrap" ng-style="{width: video.full.width + 'px', height: video.full.height + 'px'}">
<div class="img_fullsize_progress progress tg_progress">
<div class="progress-bar progress-bar-success" style="width: {{progress.percent}}%"></div>
</div>
</div>
</div>
<div class="img_fullsize_wrap" ng-if="!player.src">
<img
class="img_fullsize"
my-load-thumb
thumb="video.fullThumb"
/>
</div>
<div class="video_full_player" ng-if="player.src">
<embed ng-src="{{player.src}}" width="{{video.full.width}}" height="{{video.full.height}}" autoplay="true" CONTROLLER="TRUE" SHOWCONTROLS="TRUE" controller="true" loop="false" pluginspace="http://www.apple.com/quicktime/" ng-if="player.quicktime"/>
<video width="{{video.full.width}}" height="{{video.full.height}}" controls autoplay ng-if="!player.quicktime">
<source ng-src="{{player.src}}" type="video/mp4">
</video>
</div>
<div class="video_full_error_wrap" ng-if="error">
<div class="video_full_error" ng-if="error.html" ng-bind-html="error.html"></div>
<div class="video_full_error" ng-if="error.text" ng-bind="error.text"></div>
</div>
</div>

132
app/partials/mobile/head.html

@ -0,0 +1,132 @@
<div class="tg_page_head">
<div class="navbar navbar-static-top navbar-inverse" role="navigation" ng-class="{navbar_peer_not_selected: !curDialog.peer, navbar_offline: offline, navbar_history_select: historyState.selectActions}">
<div class="container">
<a class="navbar-peer-wrap" ng-click="showPeerInfo()">
<img
my-load-thumb
watch="true"
thumb="historyPeer.photo"
/>
</a>
<div class="navbar-toggle-wrap dropdown">
<a class="dropdown-toggle navbar-toggle">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<ul ng-if="!curDialog.peer &amp;&amp; isLoggedIn" class="dropdown-menu">
<li><a ng-click="openGroup()">New Group</a></li>
<li><a ng-click="importContact()">New Contact</a></li>
<li><a ng-click="openContacts()">Contacts</a></li>
<li><a ng-click="openSettings()">Settings</a></li>
<li><a ng-click="logOut()">Log Out</a></li>
</ul>
<ul ng-if="curDialog.peer &amp;&amp; isLoggedIn" class="dropdown-menu">
<li><a ng-click="toggleEdit()">Edit messages</a></li>
<li ng-if="!historyFilter.mediaType" class="divider"></li>
<li ng-if="!historyFilter.mediaType"><a ng-click="toggleMedia('photos')">Photos</a></li>
<li ng-if="!historyFilter.mediaType"><a ng-click="toggleMedia('video')">Videos</a></li>
<li ng-if="!historyFilter.mediaType"><a ng-click="toggleMedia('documents')">Documents</a></li>
<li ng-if="!historyFilter.mediaType"><a ng-click="toggleMedia('audio')">Voice notes</a></li>
</ul>
<ul ng-if="!isLoggedIn" class="dropdown-menu">
<li><a href="https://github.com/zhukov/webogram" target="_blank">About</a></li>
</ul>
</div>
<a ng-if="isLoggedIn" class="navbar-search-wrap" ng-click="toggleSearch()">
<i class="icon-search"></i>
</a>
<div class="navbar-header">
<a class="navbar-brand" href="{{isLoggedIn ? '#/im' : '#/'}}"><span class="tg_head_logo"></span></a>
<div ng-show="curDialog.peer" ng-switch="curDialog.peer &amp;&amp; historyFilter.mediaType.length > 0">
<ul ng-switch-when="true" class="nav navbar-nav navbar-quick-nav">
<li>
<a ng-click="toggleMedia()" class="navbar-quick-media-back">
<i class="icon icon-back"></i>
<div class="navbar-quick-back-title" ng-switch="historyFilter.mediaType">
<h4 ng-switch-when="photos">Photos</h4>
<h4 ng-switch-when="video">Videos</h4>
<h4 ng-switch-when="documents">Documents</h4>
<h4 ng-switch-when="audio">Voice messages</h4>
</div>
</a>
</li>
</ul>
<div ng-switch-default ng-switch="historyState.selectActions">
<ul ng-switch-when="true" class="nav navbar-navbar navbar-quick-nav navbar-history-edit">
<li class="navbar-quick-right">
<a ng-click="toggleEdit()">Cancel</a>
</li>
<li class="navbar-quick-left">
<a ng-click="selectedFlush()">Clear All</a>
</li>
<li class="navbar-quick-title">Edit</li>
</ul>
<ul ng-switch-default class="nav navbar-nav navbar-quick-nav" ng-switch="historyPeer.id > 0">
<li ng-switch-when="true">
<a href="#/im" class="navbar-quick-profile-back">
<i class="icon icon-back"></i>
<div class="navbar-quick-back-title">
<h4 ng-bind-html="historyPeer.data.rFullName"></h4>
<small ng-switch="historyState.typing.length">
<span ng-switch-when="1" class="status_online">
typing<span my-loading-dots></span>
</span>
<span ng-switch-default my-user-status="historyPeer.id"></span>
</small>
</div>
</a>
</li>
<li ng-switch-default>
<a href="#/im" class="navbar-quick-group-back">
<i class="icon icon-back"></i>
<div class="navbar-quick-back-title">
<h4 ng-bind-html="historyPeer.data.rTitle"></h4>
<small ng-switch="historyState.typing.length">
<ng-pluralize ng-switch-when="0" count="historyPeer.data.participants_count"
when="{'0': 'No members', 'one': '1 member', 'other': '{} members'}">
</ng-pluralize>
<span ng-switch-when="1" class="status_online">
<span my-user-link="historyState.typing[0]" short="true"></span> is typing<span my-loading-dots></span>
</span>
<span ng-switch-when="2" class="status_online">
<span my-user-link="historyState.typing[0]" short="true"></span>, <span my-user-link="historyState.typing[1]" short="true"></span><span my-loading-dots></span>
</span>
<span ng-switch-default class="status_online">
<span my-user-link="historyState.typing[0]" short="true"></span>+{{historyState.typing.length - 1}}<span my-loading-dots></span>
</span>
</small>
</div>
</a>
</li>
</ul>
</div>
</div>
</div>
<div class="navbar-menu" ng-switch="offline">
<ul ng-switch-when="true" class="nav navbar-nav navbar-offline">
<li ng-show="!offlineConnecting"><span class="navbar-offline-text">Waiting for network<span my-loading-dots></span></span></li>
<li ng-show="!offlineConnecting" class="hidden-xs"><a href="" ng-click="retryOnline()">Retry</a></li>
<li ng-show="offlineConnecting"><span class="navbar-offline-text">Connecting<span my-loading-dots></span></span></li>
</ul>
<ul ng-switch-default class="nav navbar-nav navbar-right">
<li ng-if="isLoggedIn &amp;&amp; !isEmpty.contacts"><a href="" ng-click="openContacts()">Contacts</a></li>
<li ng-if="isLoggedIn"><a href="" ng-click="openSettings()">Settings</a></li>
<li ng-if="isLoggedIn"><a href="" ng-click="logOut()">Log Out</a></li>
<li ng-if="!isLoggedIn"><a href="https://github.com/zhukov/webogram" target="_blank">About</a></li>
</ul>
</div>
</div>
</div>
</div>

278
app/partials/mobile/im.html

@ -0,0 +1,278 @@
<div my-head></div>
<div class="im_page_wrap" ng-class="{im_page_peer_not_selected: !curDialog.peer}">
<div class="im_page_split clearfix">
<div class="im_dialogs_col_wrap" ng-controller="AppImDialogsController" my-dialogs has-tabs="{{search.query.length > 0}}">
<div class="im_dialogs_panel">
<div class="dropdown im_dialogs_panel_dropdown pull-right">
<a class="dropdown-toggle">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<ul class="dropdown-menu">
<li><a ng-click="openGroup()">New Group</a></li>
<li><a ng-click="importContact()">New Contact</a></li>
<li><a ng-click="openContacts()">Contacts</a></li>
<li><a ng-click="openSettings()">Settings</a></li>
</ul>
</div>
<div class="im_dialogs_search">
<input class="form-control im_dialogs_search_field no_outline" type="search" placeholder="Search" ng-model="search.query"/>
<a class="im_dialogs_search_clear" ng-click="searchClear()" ng-show="search.query.length"></a>
</div>
<div class="im_dialogs_tabs_wrap">
<div class="im_dialogs_tabs clearfix">
<a href="" class="im_dialogs_tab" ng-class="{active: !search.messages}" ng-click="search.messages = false">Conversations</a>
<a href="" class="im_dialogs_tab" ng-class="{active: search.messages}" ng-click="search.messages = true">Messages</a>
</div>
</div>
</div>
<div my-dialogs-list class="im_dialogs_col">
<div class="im_dialogs_wrap nano">
<div class="im_dialogs_scrollable_wrap nano-content">
<div class="im_dialogs_empty_wrap" ng-if="isEmpty.contacts">
<h3 class="im_dialogs_empty_header">No contacts yet</h3>
<p class="im_dialogs_empty_lead">Get started by adding a contact to chat with</p>
<button type="button" class="btn btn-primary btn-sm" ng-click="importContact()">Add contact</button>
<button ng-if="phonebookAvailable" type="button" class="btn btn-primary btn-sm im_dialogs_import_phonebook" ng-click="importPhonebook()">Import phonebook</button>
</div>
<div ng-switch="search.messages">
<ul ng-switch-when="true" class="nav nav-pills nav-stacked">
<li class="im_dialog_wrap" my-dialog dialog-message="dialogMessage" ng-repeat="dialogMessage in dialogs track by dialogMessage.id" ng-class="{active: curDialog.peerID == dialogMessage.peerID &amp;&amp; curDialog.messageID == dialogMessage.id}"></li>
</ul>
<ul ng-switch-default class="nav nav-pills nav-stacked">
<li class="im_dialog_wrap" my-dialog dialog-message="dialogMessage" ng-repeat="dialogMessage in dialogs track by dialogMessage.peerID" ng-class="{active: curDialog.peerID == dialogMessage.peerID}"></li>
</ul>
</div>
<div class="im_dialogs_contacts_wrap" ng-show="!search.messages &amp;&amp; contacts.length > 0">
<h5>Contacts</h5>
<ul class="nav nav-pills nav-stacked">
<li class="im_dialog_wrap" ng-repeat="contact in contacts | orderBy:'user.sortName' track by contact.userID" ng-class="{active: curDialog.peerID == contact.userID}">
<a class="im_dialog" ng-click="dialogSelect(contact.peerString)">
<div class="im_dialog_photo pull-left">
<img
class="im_dialog_photo"
my-load-thumb
thumb="contact.userPhoto"
/>
</div>
<div class="im_dialog_message_wrap">
<div class="im_dialog_peer">
<span class="im_dialog_user" ng-bind-html="contact.user.rFullName"></span>
</div>
<div class="im_dialog_message">
<span class="im_dialog_message_text" my-user-status="::contact.userID"></span>
</div>
</div>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<div class="im_history_col_wrap" ng-controller="AppImHistoryController">
<div ng-show="state.notSelected" ng-switch="isEmpty.contacts &amp;&amp; isEmpty.dialogs">
<div ng-switch-when="true" class="im_history_no_dialogs_wrap">
<h3 class="im_dialogs_empty_header">Get started</h3>
<p class="im_dialogs_empty_lead">Welcome to Telegram Web. You can always set your profile photo and change your name in Settings.</p>
<button type="button" class="btn btn-primary btn-sm" ng-click="openSettings()">Open Settings</button>
</div>
<div ng-switch-default class="im_history_not_selected" my-vertical-position="0.35" padding="true">
Please select a chat to start messaging
</div>
</div>
<div ng-show="!state.notSelected &amp;&amp; !state.loaded" class="im_history_not_selected" my-vertical-position="0.35" padding="true">
Loading history<span my-loading-dots></span>
</div>
<div ng-show="state.loaded">
<div my-history class="im_history_col">
<div class="im_history_panel_wrap">
<div class="im_history_panel clearfix" ng-controller="AppImPanelController">
<div class="im_history_panel_title">
<a class="im_history_panel_info_link pull-right" ng-click="showPeerInfo()">Info</a>
<a class="im_history_panel_edit_link pull-right" ng-click="toggleEdit()">Edit</a>
<div class="dropdown im_history_panel_media_dropdown pull-right">
<a class="dropdown-toggle">Media<i class="icon icon-caret"></i></a>
<ul class="dropdown-menu">
<li><a ng-click="toggleMedia('photos')">Photos</a></li>
<li><a ng-click="toggleMedia('video')">Videos</a></li>
<li><a ng-click="toggleMedia('documents')">Documents</a></li>
<li><a ng-click="toggleMedia('audio')">Voice messages</a></li>
</ul>
</div>
<a ng-show="historyFilter.mediaType.length || skippedHistory" class="im_history_panel_return_link pull-right" ng-click="returnToRecent()" ng-switch="skippedHistory">
<span ng-switch-when="true">Show recent messages</span>
<span ng-switch-default>Show all messages</span>
<strong class="im_history_panel_return_count" ng-show="missedCount > 0" ng-bind="'+' + missedCount"></strong>
</a>
<div ng-switch="historyFilter.mediaType">
<h4 ng-switch-when="photos">Photos</h4>
<h4 ng-switch-when="video">Videos</h4>
<h4 ng-switch-when="documents">Documents</h4>
<h4 ng-switch-when="audio">Voice messages</h4>
<h4 ng-switch-default ng-switch="historyPeer.id > 0" ng-click="showPeerInfo()">
<div ng-switch-when="true">
<span ng-bind-html="historyPeer.data.rFullName"></span>
<small class="im_peer_online" my-user-status="historyPeer.id"></small>
</div>
<div ng-switch-default>
<span ng-bind-html="historyPeer.data.rTitle"></span>
<small class="im_chat_users">
<ng-pluralize count="historyPeer.data.participants_count"
when="{'0': 'No members', 'one': '1 member', 'other': '{} members'}">
</ng-pluralize>
</small>
</div>
</h4>
</div>
</div>
</div>
</div>
<div class="im_history_wrap nano">
<div class="im_history_scrollable_wrap nano-content">
<div class="im_history_scrollable">
<div class="im_history" ng-class="{im_history_selectable: historyState.selectActions}">
<div ng-if="!history.length" class="im_history_empty" ng-switch="state.mayBeHasMore" my-vertical-position="0.25" padding="true">
<span ng-switch-when="true">Loading history<span my-loading-dots></span></span>
<span ng-switch-default>No messages here yet...</span>
</div>
<div class="im_history_messages" ng-class="{im_history_messages_group: historyPeer.id < 0}">
<div class="im_history_message_wrap" my-message ng-repeat="historyMessage in history"></div>
</div>
</div>
<div class="im_history_typing_wrap">
<div class="im_history_typing" ng-show="historyState.typing.length > 0 &amp;&amp; !historyFilter.mediaType" ng-switch="historyState.typing.length">
<span ng-switch-when="1">
<a class="im_history_typing_author" my-user-link="historyState.typing[0]"></a> is typing<span my-loading-dots></span>
</span>
<span ng-switch-when="2">
<a class="im_history_typing_author" my-user-link="historyState.typing[0]"></a> and <a class="im_history_typing_author" my-user-link="historyState.typing[1]"></a> are typing<span my-loading-dots></span>
</span>
<span ng-switch-default>
<a class="im_history_typing_author" my-user-link="historyState.typing[0]"></a>, <a class="im_history_typing_author" my-user-link="historyState.typing[1]"></a> and {{historyState.typing.length - 2}} more are typing<span my-loading-dots></span>
</span>
</div>
</div>
</div>
</div>
</div>
<div class="im_bottom_panel_wrap">
<div class="im_edit_panel_wrap clearfix" ng-show="historyState.selectActions">
<div class="im_edit_panel_border"></div>
<a class="im_edit_flush_link" ng-click="selectedFlush()" ng-switch="historyPeer.id > 0">
<span ng-switch-when="true">Delete Chat</span>
<span ng-switch-default>Clear History</span>
</a>
<a class="im_edit_cancel_link" ng-click="selectedCancel()">Cancel</a>
<div class="im_edit_selected_actions">
<a class="btn btn-primary im_edit_forward_btn" ng-click="selectedForward()" ng-class="{disabled: !selectedCount}" ng-disabled="!selectedCount">
Forward <strong class="im_selected_count" ng-show="selectedCount > 0" ng-bind="selectedCount"></strong>
</a><a class="btn btn-danger im_edit_delete_btn" ng-click="selectedDelete()" ng-class="{disabled: !selectedCount}" ng-disabled="!selectedCount">
Delete <strong class="im_selected_count" ng-show="selectedCount > 0" ng-bind="selectedCount"></strong>
</a>
</div>
</div>
<div class="im_send_panel_wrap" ng-hide="historyState.selectActions">
<div class="im_send_form_wrap1">
<div class="im_send_form_wrap clearfix" ng-controller="AppImSendController">
<div class="pull-right im_panel_peer_photo" ng-click="showPeerInfo()">
<img
class="im_panel_peer_photo"
my-load-thumb
watch="true"
thumb="historyPeer.photo"
/>
<i class="icon im_panel_peer_online" ng-show="historyPeer.id > 0 &amp;&amp; historyPeer.data.status._ == 'userStatusOnline'"></i>
</div>
<div class="pull-left im_panel_own_photo">
<img
class="im_panel_own_photo"
my-load-thumb
watch="true"
thumb="ownPhoto"
/>
</div>
<form my-send-form draft-message="draftMessage" class="im_send_form" ng-class="{im_send_form_empty: !draftMessage.text.length}" ng-submit="sendMessage($event)">
<div class="im_send_field_wrap">
<div class="im_send_dropbox_wrap"> Drop photos here to send </div>
<textarea ng-model="draftMessage.text" placeholder="Write a message..." class="form-control im_message_field no_outline"></textarea>
</div>
<div class="im_media_attach pull-right">
<input type="file" class="im_media_attach_input" size="28" multiple="true" accept="image/*, video/*, audio/*" title="Send media"/>
<i class="icon icon-camera"></i>
</div>
<div class="im_attach pull-right">
<input type="file" class="im_attach_input" size="28" multiple="true" title="Send file" />
<i class="icon icon-paperclip"></i>
</div>
<div class="im_emoji_btn pull-right" title="Insert emoticon">
<i class="icon icon-emoji"></i>
</div>
<button type="submit" class="btn btn-success im_submit">
<span class="im_submit_text">Send</span>
</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="im_page_footer">
<a class="im_page_footer_brand" target="_blank" href="https://github.com/zhukov/webogram">Telegram beta</a> by izhukov &amp; toberg
</div>
<div id="notify_sound"></div>

31
app/partials/mobile/import_contact_modal.html

@ -0,0 +1,31 @@
<div class="import_modal_wrap" my-modal-position>
<a class="modal-close-button" ng-click="$dismiss()"><i></i></a>
<div class="modal-body">
<form class="modal_simple_form" ng-submit="doImport()">
<h4>Add new contact</h4>
<div class="form-group">
<input class="form-control input-sm" my-focused type="text" placeholder="Phone number" ng-model="importContact.phone"/>
</div>
<div class="form-group">
<input class="form-control input-sm" type="text" placeholder="First name" ng-model="importContact.first_name"/>
</div>
<div class="form-group">
<input class="form-control input-sm" type="text" placeholder="Last name" ng-model="importContact.last_name"/>
</div>
</form>
</div>
<div class="modal-footer">
<a class="btn btn-link pull-left" ng-if="phonebookAvailable" ng-click="importPhonebook()">Phonebook</a>
<a class="btn btn-link" ng-click="$dismiss()">Cancel</a>
<button class="btn btn-primary" ng-class="{disabled: progress.enabled}" ng-click="doImport()" ng-bind="progress.enabled ? 'Importing...' : 'Save'" ng-disabled="progress.enabled"></button>
</div>
</div>

84
app/partials/mobile/login.html

@ -0,0 +1,84 @@
<div my-head></div>
<div class="login_form_wrap" my-vertical-position="0.4">
<div class="error" ng-if="error.message" ng-bind="error.message"></div>
<form name="mySendCodeForm" ng-if="!credentials.phone_code_hash" ng-submit="sendCode()">
<h3 class="login_form_head">Sign in</h3>
<p class="login_form_lead">Please choose your country and enter your full phone number.</p>
<div class="login_country_selector" ng-click="chooseCountry()">
<span ng-bind="credentials.phone_country_name"></span>
<i class="icon icon-caret pull-right"></i>
</div>
<div class="form-group" ng-class="{'has-error': error.field == 'phone'}">
<label class="control-label" ng-if="error.field == 'phone'">Incorrect phone number</label>
<div class="clearfix">
<input type="tel" autocomplete="off" class="form-control pull-left login_phone_country" my-focused name="phone_country" ng-model="credentials.phone_country">
<input type="tel" autocomplete="off" class="form-control pull-left login_phone_number" my-focus-on="country_selected" name="phone_number" ng-model="credentials.phone_number" placeholder="Enter your phone" required>
</div>
</div>
<button class="btn btn-primary btn-block" ng-class="{disabled: progress.enabled}" ng-disabled="progress.enabled" type="submit" ng-switch="progress.enabled">
<span ng-switch-when="true">Generating keys<span my-loading-dots></span></span>
<span ng-switch-default>Next</span>
</button>
<div class="login_form_messaging" ng-show="progress.enabled">Keys are only generated once. This can take a few minutes on slower devices, please be patient.</div>
</form>
<form name="myLoginForm" ng-if="credentials.phone_code_hash &amp;&amp; !credentials.phone_code_valid" ng-submit="logIn()">
<h3 class="login_form_head"><span ng-bind="credentials.phone_country"></span> <span ng-bind="credentials.phone_number"></span></h3>
<div class="login_edit_phone"><a ng-click="editPhone()">Edit phone number</a></div>
<div ng-switch="credentials.viaApp">
<div ng-switch-when="true">
<p class="login_form_lead">
Please enter the code you've just received in your other <strong>Telegram</strong> app
</p>
<p class="login_form_lead">
<a ng-click="sendSms()">Haven't received the code?</a>
</p>
</div>
<div ng-switch-default>
<p class="login_form_lead">We have sent you a code via SMS.<br/>Please enter it below.</p>
<p class="login_form_lead">
<span ng-show="callPending.remaining > 0">Telegram will call you in {{callPending.remaining | duration}}</span>
<span ng-show="!callPending.remaining &amp;&amp; !callPending.success">Telegram is calling you</span>
<span ng-show="!callPending.remaining &amp;&amp; callPending.success">Telegram dialed your number</span>
</p>
</div>
</div>
<div class="form-group" ng-class="{'has-error': error.field == 'phone_code'}">
<label class="control-label" for="phone_code" ng-if="error.field == 'phone_code'">Incorrect SMS code</label>
<input type="number" my-focused class="form-control" name="phone_code" ng-model="credentials.phone_code" placeholder="Enter your code" autocomplete="off" required>
</div>
<button class="btn btn-primary btn-block" type="submit" ng-class="{disabled: progress.enabled}" ng-disabled="progress.enabled" ng-switch="progress.enabled">
<span ng-switch-when="true">Checking code<span my-loading-dots></span></span>
<span ng-switch-default>Next</span>
</button>
</form>
<form name="myFullNameForm" ng-if="credentials.phone_code_valid &amp;&amp; credentials.phone_unoccupied" ng-submit="logIn(true)">
<h3 class="login_form_head">Your info</h3>
<p class="login_form_lead">Please enter your full name to set up a Telegram account.</p>
<div class="form-group login_first_name_wrap" ng-class="{'has-error': error.field == 'first_name'}">
<label class="control-label" for="first_name" ng-if="error.field == 'first_name'">Incorrect first name</label>
<input my-focused class="form-control" name="first_name" ng-model="credentials.first_name" placeholder="First name" autocomplete="off" required>
</div>
<div class="form-group" ng-class="{'has-error': error.field == 'last_name'}">
<label class="control-label" for="last_name" ng-if="error.field == 'last_name'">Incorrect last name</label>
<input class="form-control" name="last_name" ng-model="credentials.last_name" placeholder="Last name" autocomplete="off">
</div>
<button class="btn btn-primary btn-block" ng-class="{disabled: progress.enabled}" ng-disabled="progress.enabled" type="submit" ng-switch="progress.enabled">
<span ng-switch-when="true">Signing up<span my-loading-dots></span></span>
<span ng-switch-default>Sign up</span>
</button>
</form>
</div>

79
app/partials/mobile/message.html

@ -0,0 +1,79 @@
<div class="im_message_unread_split" ng-if="::historyUnreadAfter == historyMessage.id || false" ng-show="historyUnreadAfter == historyMessage.id">
Unread messages
</div>
<div class="im_message_date_split im_service_message_wrap" ng-if="::historyMessage.needDate || false" ng-show="historyMessage.needDate">
<div class="im_service_message" ng-bind="historyMessage.date | myDate"></div>
</div>
<div class="im_message_outer_wrap" ng-class="[selectedMsgs[historyMessage.id] ? 'im_message_selected' : '', historyMessage.grouped, historyFocus == historyMessage.id ? 'im_message_focus' : '', historyMessage.unread ? 'im_message_unread' : '', historyMessage.error ? 'im_message_error' : '', historyMessage.pending ? 'im_message_pending' : '']" ng-click="toggleMessage(historyMessage.id, $event)">
<div class="im_message_wrap clearfix">
<div class="im_service_message_wrap" ng-if="::historyMessage._ == 'messageService'">
<div class="im_service_message">
<a class="im_message_author" my-user-link="historyMessage.from_id" short="!historyMessage.to_id.chat_id" color="historyMessage.to_id.chat_id > 0"></a>
<span class="im_message_service" my-service-message></span>
</div>
<a ng-if="::historyMessage.action._ == 'messageActionChatEditPhoto'" class="im_service_message_photo_thumb" href="" ng-click="openPhoto(historyMessage.action.photo.id)">
<img
class="im_service_message_photo_thumb"
my-load-thumb
thumb="historyMessage.action.photo.thumb"
/>
</a>
</div>
<div ng-if="::historyMessage._ != 'messageService'" class="im_content_message_wrap" ng-class="::[historyMessage.out ? 'im_message_out' : 'im_message_in', historyMessage._ == 'messageForwarded' ? 'im_message_fwd' : '']">
<div class="im_content_message_select_area">
<i class="icon icon-select-tick"></i>
</div>
<a class="im_message_error_btn" ng-if="::historyMessage.pending || historyMessage.error || false" ng-click="historyMessage.send()">
<i class="icon-message-status" tooltip="Try again"></i>
</a>
<i ng-if="::historyMessage.unread || historyMessage.pending || false" class="icon-message-status" ng-class="{'icon-message-status-unread': historyMessage.unread, 'icon-message-status-pending': historyMessage.pending}" ng-show="!historyMessage.error"></i>
<a class="im_message_from_photo pull-left" my-user-photolink="historyMessage.from_id" img-class="im_message_from_photo"></a>
<div class="im_message_meta pull-right text-right">
<i class="icon-message-status-tick"></i>
<span class="im_message_date" ng-bind="::historyMessage.date | time"></span>
</div>
<div class="im_message_body" ng-class="{im_message_body_media: historyMessage._ == 'message' &amp;&amp; historyMessage.media &amp;&amp; historyMessage.media._ != 'messageMediaEmpty'}">
<a class="im_message_author" my-user-link="historyMessage.from_id" short="!historyMessage.to_id.chat_id" color="historyMessage.to_id.chat_id > 0"></a>
<div ng-if="::historyMessage._ == 'messageForwarded' || false" class="im_message_fwd_from">
<div class="im_message_fwd_title" ng-if="::historyMessage.grouped == 'im_grouped_fwd_start'">Forwarded message</div>
<a class="im_message_fwd_photo pull-left" my-user-photolink="historyMessage.fwd_from_id" img-class="im_message_fwd_photo"></a>
<div class="im_message_fwd_author_wrap">
<a class="im_message_fwd_author" my-user-link="historyMessage.fwd_from_id" short="true"></a><span class="im_message_fwd_date" ng-bind="historyMessage.fwd_date | dateOrTime"></span>
</div>
</div>
<div ng-if="::historyMessage.media &amp;&amp; historyMessage.media._ != 'messageMediaEmpty' || false" class="im_message_media" ng-switch="historyMessage.media._">
<div ng-switch-when="messageMediaPhoto" my-message-photo></div>
<div ng-switch-when="messageMediaVideo" my-message-video></div>
<div ng-switch-when="messageMediaDocument" my-message-document></div>
<div ng-switch-when="messageMediaAudio" my-message-audio></div>
<div ng-switch-when="messageMediaGeo" my-message-map></div>
<div ng-switch-when="messageMediaContact" my-message-contact></div>
<div ng-switch-when="messageMediaPending" my-message-pending></div>
</div>
<div class="im_message_text" ng-if="::historyMessage.message.length || false" ng-bind-html="::historyMessage.richMessage"></div>
</div>
</div>
</div>
</div>

33
app/partials/mobile/message_attach_audio.html

@ -0,0 +1,33 @@
<div class="im_message_document im_message_audio" ng-class="{im_message_audio_done: historyMessage.media.audio.url, im_message_audio_progress: historyMessage.media.audio.progress.enabled}">
<a href="" ng-click="openAudio(historyMessage.media.audio.id)" ng-if="!historyMessage.media.audio.progress.enabled &amp;&amp; !historyMessage.media.audio.url">
<i class="icon icon-audio"></i>
</a>
<i class="icon icon-audio" ng-if="historyMessage.media.audio.progress.enabled || historyMessage.media.audio.url"></i>
<div class="im_message_audio_info">
<div class="im_message_audio_name_wrap" ng-if="!historyMessage.media.audio.url">
<span class="im_message_audio_name">
Voice message
</span>
<span class="im_message_audio_duration" ng-if="!historyMessage.media.audio.progress.enabled" ng-bind="::historyMessage.media.audio.duration | duration"></span>
<span class="im_message_audio_size" ng-if="historyMessage.media.audio.progress.enabled" ng-bind="historyMessage.media.audio.progress | formatSizeProgress"></span>
</div>
<div class="im_message_audio_actions" ng-if="!historyMessage.media.audio.progress.enabled &amp;&amp; !historyMessage.media.audio.url">
<a href="" ng-click="openAudio(historyMessage.media.audio.id)">Play</a>
</div>
<div class="clearfix cancelable_progress_wrap" ng-if="historyMessage.media.audio.progress.enabled">
<a class="im_message_media_progress_cancel pull-right" ng-click="historyMessage.media.audio.progress.cancel()">Cancel</a>
<div class="im_message_download_progress_wrap">
<div class="progress tg_down_progress">
<div class="progress-bar progress-bar-success" ng-style="{width: historyMessage.media.audio.progress.percent + '%'}"></div>
</div>
</div>
</div>
<div class="im_message_audio_player_wrap" ng-if="historyMessage.media.audio.url">
<audio my-audio-autoplay audio="historyMessage.media.audio" controls="controls">
<source ng-src="{{::historyMessage.media.audio.url}}" type="audio/ogg" />
<embed ng-src="{{::historyMessage.media.audio.url}}" hidden="true" autostart="true" loop="false" />
</audio>
</div>
</div>
</div>

8
app/partials/mobile/message_attach_contact.html

@ -0,0 +1,8 @@
<div>
<a class="im_message_contact_photo pull-left" my-user-photolink="historyMessage.media.user_id" img-class="im_message_contact_photo"></a>
<div class="im_message_contact_name" ng-switch="historyMessage.media.user_id > 0">
<a ng-switch-when="true" my-user-link="historyMessage.media.user_id"></a>
<span ng-switch-default ng-bind-html="::historyMessage.media.rFullName"></span>
</div>
<div class="im_message_contact_phone" ng-bind="::historyMessage.media.phone_number | phoneNumber"></div>
</div>

39
app/partials/mobile/message_attach_document.html

@ -0,0 +1,39 @@
<div ng-switch="::historyMessage.media.document.isSpecial">
<div ng-switch-when="gif" my-load-gif document="historyMessage.media.document"></div>
<div ng-switch-default class="im_message_document" ng-class="{im_message_document_thumbed: !!historyMessage.media.document.thumb, im_message_document_progress: historyMessage.media.document.progress.enabled}">
<a href="" ng-click="downloadDoc(historyMessage.media.document.id, historyMessage.media.document.withPreview)" ng-class="{im_message_document_link_disabled: historyMessage.media.document.progress.enabled}">
<i class="icon icon-document" ng-if="::!historyMessage.media.document.thumb"></i>
<div class="im_message_document_thumb_wrap" ng-if="::historyMessage.media.document.thumb">
<img
class="im_message_document_thumb"
my-load-thumb
thumb="historyMessage.media.document.thumb"
/>
</div>
</a>
<div class="im_message_document_info">
<div class="im_message_document_name_wrap">
<span class="im_message_document_name" ng-bind="::historyMessage.media.document.file_name"></span>
<span class="im_message_document_size" ng-if="!historyMessage.media.document.progress.enabled" ng-bind="::historyMessage.media.document.size | formatSize"></span>
<span class="im_message_document_size" ng-if="historyMessage.media.document.progress.enabled" ng-bind="historyMessage.media.document.progress | formatSizeProgress"></span>
</div>
<div class="im_message_document_actions" ng-if="!historyMessage.media.document.progress.enabled">
<a href="" ng-click="downloadDoc(historyMessage.media.document.id)">Download</a>
<a href="" ng-click="downloadDoc(historyMessage.media.document.id, 1)" ng-if="::historyMessage.media.document.withPreview">Open</a>
</div>
<div class="clearfix cancelable_progress_wrap" ng-if="historyMessage.media.document.progress.enabled">
<a class="im_message_media_progress_cancel pull-right" ng-click="historyMessage.media.document.progress.cancel()">Cancel</a>
<div class="im_message_download_progress_wrap">
<div class="progress tg_down_progress">
<div class="progress-bar progress-bar-success" ng-style="{width: historyMessage.media.document.progress.percent + '%'}"></div>
</div>
</div>
</div>
</div>
</div>
</div>

3
app/partials/mobile/message_attach_map.html

@ -0,0 +1,3 @@
<a my-map-point point="historyMessage.media.geo" class="im_message_geopoint">
<i class="icon icon-geo-point"></i>
</a>

17
app/partials/mobile/message_attach_pending.html

@ -0,0 +1,17 @@
<div class="im_message_document im_message_upload_file" ng-class="::'im_message_upload_' + historyMessage.media.type">
<i class="icon" ng-class="::'icon-' + historyMessage.media.type"></i>
<div class="im_message_document_info">
<div class="im_message_document_name_wrap">
<span class="im_message_document_name" ng-bind="::historyMessage.media.file_name"></span>
<span class="im_message_document_size" ng-if="historyMessage.media.progress" ng-bind="historyMessage.media.progress | formatSizeProgress"></span>
</div>
<div class="clearfix cancelable_progress_wrap">
<a class="im_message_media_progress_cancel pull-right" ng-click="historyMessage.media.progress.cancel()">Cancel</a>
<div class="im_message_download_progress_wrap">
<div class="progress tg_down_progress">
<div class="progress-bar progress-bar-success" role="progressbar" ng-style="{width: historyMessage.media.progress.percent + '%'}"></div>
</div>
</div>
</div>
</div>
</div>

7
app/partials/mobile/message_attach_photo.html

@ -0,0 +1,7 @@
<a class="im_message_photo_thumb" href="" ng-click="openPhoto(historyMessage.media.photo.id, historyMessage.id)" ng-style="::{width: historyMessage.media.photo.thumb.width + 'px'}" ng-mouseover="preloadPhoto(historyMessage.media.photo.id)">
<img
class="im_message_photo_thumb"
my-load-thumb
thumb="historyMessage.media.photo.thumb"
/>
</a>

31
app/partials/mobile/message_attach_video.html

@ -0,0 +1,31 @@
<div class="im_message_video im_message_document_thumbed">
<a class="im_message_video_thumb" href="" ng-click="openVideo(historyMessage.media.video.id, historyMessage.id)" ng-style="::{width: historyMessage.media.video.thumb.width + 'px'}">
<span class="im_message_video_duration" ng-bind="::historyMessage.media.video.duration | duration"></span>
<i class="icon icon-videoplay"></i>
<img
class="im_message_video_thumb"
my-load-thumb
thumb="historyMessage.media.video.thumb"
/>
</a>
<div class="im_message_document_info">
<div class="im_message_document_name_wrap">
<span class="im_message_document_name">Video</span>
<span class="im_message_document_size" ng-if="!historyMessage.media.video.progress.enabled" ng-bind="::historyMessage.media.video.size | formatSize"></span>
<span class="im_message_document_size" ng-if="historyMessage.media.video.progress.enabled" ng-bind="historyMessage.media.video.progress | formatSizeProgress"></span>
</div>
<div class="im_message_document_actions" ng-if="!historyMessage.media.video.progress.enabled">
<a href="" ng-click="downloadVideo(historyMessage.media.video.id)">Download</a>
<a href="" ng-click="openVideo(historyMessage.media.video.id, historyMessage.id)">Play video</a>
</div>
<div class="clearfix cancelable_progress_wrap" ng-if="historyMessage.media.video.progress.enabled">
<a class="im_message_media_progress_cancel pull-right" ng-click="historyMessage.media.video.progress.cancel()">Cancel</a>
<div class="im_message_download_progress_wrap">
<div class="progress tg_down_progress">
<div class="progress-bar progress-bar-success" ng-style="{width: historyMessage.media.video.progress.percent + '%'}"></div>
</div>
</div>
</div>
</div>
</div>

32
app/partials/mobile/message_service.html

@ -0,0 +1,32 @@
<span ng-switch="::historyMessage.action._">
<span ng-switch-when="messageActionChatCreate">
created the group &laquo;<strong ng-bind-html="::historyMessage.action.rTitle"></strong>&raquo;
</span>
<span ng-switch-when="messageActionChatEditTitle">
changed group name to &laquo;<strong ng-bind-html="::historyMessage.action.rTitle"></strong>&raquo;
</span>
<span ng-switch-when="messageActionChatEditPhoto">
changed group photo
</span>
<span ng-switch-when="messageActionChatDeletePhoto">
removed group photo
</span>
<span ng-switch-when="messageActionChatAddUser" ng-switch="::historyMessage.from_id != historyMessage.action.user_id">
<span ng-switch-when="true">
invited <a my-user-link="historyMessage.action.user_id" color="true"></a>
</span>
<span ng-switch-default>
returned to group
</span>
</span>
<span ng-switch-when="messageActionChatDeleteUser" ng-switch="::historyMessage.from_id != historyMessage.action.user_id">
<span ng-switch-when="true">
kicked <a my-user-link="historyMessage.action.user_id" color="true"></a>
</span>
<span ng-switch-default>
left group
</span>
</span>
<span ng-switch-default ng-bind="'Unsupported action ' + historyMessage.action._"></span>
</span>

22
app/partials/mobile/photo_modal.html

@ -0,0 +1,22 @@
<div my-modal-width="{{photo.full.modalWidth}}" class="media_modal_wrap photo_modal_wrap" my-modal-position animation="no" my-modal-nav next="nav.next()" prev="nav.prev()">
<div class="modal-body">
<div class="photo_modal_image_wrap" my-load-full-photo full-photo="photo.full" thumb-location="photo.thumb.location" ng-click="nav.next()"> </div>
<div class="media_meta_wrap clearfix">
<div class="media_modal_actions pull-right">
<a href="" class="media_modal_action_link" ng-click="download()">Download</a>
<a href="" class="media_modal_action_link" ng-if="canForward" ng-click="forward()">Forward</a>
<a href="" class="media_modal_action_link" ng-if="canDelete" ng-click="delete()">Delete</a>
</div>
<p class="media_modal_info">
<span class="media_modal_author" ng-bind-html="::photo.fromUser.rFullName"></span>, <span ng-bind="photo.date | dateOrTime"></span>
</p>
</div>
</div>
</div>

27
app/partials/mobile/profile_edit_modal.html

@ -0,0 +1,27 @@
<div class="profile_edit_modal_wrap" my-modal-position>
<a class="modal-close-button" ng-click="$dismiss()"><i></i></a>
<div class="modal-body">
<form class="modal_simple_form" ng-submit="updateProfile()">
<h4>Edit Profile</h4>
<div class="form-group import_modal_field_wrap" ng-class="{'has-error': error.field == 'first_name'}">
<input class="form-control input-sm" my-focused type="text" placeholder="First name" ng-model="profile.first_name" name="first_name"/>
</div>
<div class="form-group import_modal_field_wrap" ng-class="{'has-error': error.field == 'last_name'}">
<input class="form-control input-sm" type="text" placeholder="Last name" ng-model="profile.last_name"/>
</div>
</form>
</div>
<div class="modal-footer">
<a class="btn btn-link" ng-click="$dismiss()">Cancel</a>
<button class="btn btn-primary" ng-class="{disabled: profile.updating}" ng-click="updateProfile()" ng-bind="profile.updating ? 'Saving...' : 'Save'" ng-disabled="profile.updating"></button>
</div>
</div>

21
app/partials/mobile/video_modal.html

@ -0,0 +1,21 @@
<div class="media_modal_wrap video_modal_wrap" my-modal-position>
<div class="modal-body">
<div class="video_modal_image_wrap" my-load-video video="video"></div>
<div class="media_meta_wrap clearfix">
<div class="media_modal_actions pull-right">
<a href="" class="media_modal_action_link" ng-click="download()">Download</a>
<a ng-if="messageID" href="" class="media_modal_action_link" ng-click="forward()">Forward</a>
<a ng-if="messageID" href="" class="media_modal_action_link" ng-click="delete()">Delete</a>
</div>
<p class="media_modal_info">
<span class="media_modal_author" ng-bind-html="video.fromUser.rFullName"></span>, <span ng-bind="video.date | dateOrTime"></span>
</p>
</div>
</div>
</div>

56
app/partials/mobile/welcome.html

@ -0,0 +1,56 @@
<div my-head></div>
<div ng-if="showWelcome">
<div class="welcome_form">
<div class="welcome_logo"></div>
<h3 class="welcome_header"><strong>Telegram</strong> Web</h3>
<div class="welcome_text">
<p>This is an unofficial web-client for the <strong>Telegram Messenger</strong>.</p>
<p>It's still an <strong>alpha-version</strong> and may not be 200% reliable</p>
</div>
<div class="welcome_btn_wrap">
<a href="#/login" class="btn btn-primary btn-block">Start Messaging</a>
</div>
</div>
<div class="welcome_footer" my-custom-background="#f8f8f8">
<div class="welcome_cards_wrap clearfix">
<div class="container-fluid">
<div class="row">
<div class="col-md-4 col-sm-4">
<div class="welcome_footer_card_wrap row">
<div class="welcome_footer_card welcome_footer_card_messaging"></div>
<h4>Fast messaging</h4>
<div class="welcome_footer_card_lead">Send messages with rich emoji support right from your desktop or laptop computer</div>
</div>
</div>
<div class="col-md-4 col-sm-4">
<div class="welcome_footer_card_wrap">
<div class="welcome_footer_card welcome_footer_card_filesharing"></div>
<h4>Easy file sharing</h4>
<div class="welcome_footer_card_lead">Share files of any type using drag-and-drop or the attachment icon</div>
</div>
</div>
<div class="col-md-4 col-sm-4">
<div class="welcome_footer_card_wrap">
<div class="welcome_footer_card welcome_footer_card_powerful"></div>
<h4>Powerful tools</h4>
<div class="welcome_footer_card_lead">Browse shared media and files by type <br/> and set custom notifications</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

2
app/webogram.appcache

@ -1,6 +1,6 @@
CACHE MANIFEST CACHE MANIFEST
# 28 # 30
NETWORK: NETWORK:
* *

Loading…
Cancel
Save