Browse Source

Added dialogs modal, added connection status bar, added forward button, invite users to chat, kick users from chat

master
Igor Zhukov 11 years ago
parent
commit
629d49b445
  1. 151
      app/css/app.css
  2. 230
      app/js/controllers.js
  3. 47
      app/js/directives.js
  4. 23
      app/js/lib/mtproto.js
  5. 100
      app/js/services.js
  6. 30
      app/partials/chat_create_modal.html
  7. 7
      app/partials/chat_modal.html
  8. 53
      app/partials/contacts_modal.html
  9. 2
      app/partials/dialog.html
  10. 11
      app/partials/head.html
  11. 1
      app/partials/im.html
  12. 28
      app/partials/peer_select.html

151
app/css/app.css

@ -109,6 +109,7 @@ fieldset[disabled] .btn-tg:active, @@ -109,6 +109,7 @@ fieldset[disabled] .btn-tg:active,
.btn-tg.disabled.active,
.btn-tg[disabled].active,
fieldset[disabled] .btn-tg.active {
color: #DDD;
background-color: #999;
border-color: #999;
}
@ -145,6 +146,19 @@ fieldset[disabled] .btn-tg.active { @@ -145,6 +146,19 @@ fieldset[disabled] .btn-tg.active {
line-height: 0;
height: auto;
}
.navbar-offline {
max-width: 250px;
margin: 0 auto;
float: none;
}
.navbar-offline-text {
padding: 12px 15px;
/*color: #FFF;*/
color: #b9cfe3;
font-size: 13px;
display: block;
line-height: 20px;
}
.tg_head_logo {
@ -438,7 +452,6 @@ fieldset[disabled] .btn-tg.active { @@ -438,7 +452,6 @@ fieldset[disabled] .btn-tg.active {
/* Dialogs list */
.im_dialogs_col {
/*min-width: 315px;*/
margin-right: -7px;
}
.im_dialogs_col .nano > .pane {
@ -588,6 +601,9 @@ a.im_dialog:hover .im_dialog_message_text { @@ -588,6 +601,9 @@ a.im_dialog:hover .im_dialog_message_text {
color: #428bca;
background-color: #fff;
}
.im_dialogs_modal_col .im_dialog_badge {
display: none;
}
.im_dialog_unread {
background: #c1d6e5;
@ -649,11 +665,13 @@ a.im_dialog:hover .im_dialog_date { @@ -649,11 +665,13 @@ a.im_dialog:hover .im_dialog_date {
.im_history_col {
}
.im_history_col .nano > .pane {
.im_history_col .nano > .pane,
.contacts_modal_col .nano > .pane,
.im_dialogs_modal_col .nano > .pane {
background : rgba(3,36,64,0.08);
width : 9px;
top: 10px;
right: 8px;
right: 0;
top: 0;
-webkit-transition : .2s;
-moz-transition : .2s;
-o-transition : .2s;
@ -662,7 +680,14 @@ a.im_dialog:hover .im_dialog_date { @@ -662,7 +680,14 @@ a.im_dialog:hover .im_dialog_date {
-webkit-border-radius : 2px;
border-radius : 2px;
}
.im_history_col .nano > .pane > .slider {
.im_history_col .nano > .pane {
top: 10px;
right: 8px;
}
.im_history_col .nano > .pane > .slider,
.contacts_modal_col .nano > .pane > .slider,
.im_dialogs_modal_col .nano > .pane > .slider {
background : rgba(3,46,79,0.22);
margin: 0;
-moz-border-radius : 2px;
@ -1103,7 +1128,8 @@ div.im_message_video_thumb { @@ -1103,7 +1128,8 @@ div.im_message_video_thumb {
.im_content_message_wrap {
margin: 10px 0px 5px 16px;
/*margin: 10px 0px 5px 16px;*/
margin: 8px 0px 8px 16px
}
.icon-message-status {
background: #43A4DB;
@ -1150,6 +1176,7 @@ div.im_message_video_thumb { @@ -1150,6 +1176,7 @@ div.im_message_video_thumb {
.im_message_date {
color: #adadad;
font-size: 0.85em;
padding-bottom: 20px;
}
div.im_message_author,
div.im_message_body {
@ -1498,6 +1525,10 @@ img.img_fullsize { @@ -1498,6 +1525,10 @@ img.img_fullsize {
padding: 8px 7px;
border-top: 1px solid #F0F0F0;
}
.chat_modal_participant_kick {
padding: 11px 0;
display: block;
}
.chat_modal_participant_name {
display: block;
color: #3C6E97;
@ -1777,13 +1808,38 @@ img.img_fullsize { @@ -1777,13 +1808,38 @@ img.img_fullsize {
opacity: 1;
}
.contacts_modal_contact_wrap {
padding: 8px 7px;
border-top: 1px solid #F0F0F0;
.contacts_modal_col {
margin-right: -17px;
}
.contacts_scrollable_wrap {
padding: 0 17px 0 0;
outline: none ! important;
}
.contacts_modal_members_list .contacts_modal_contact_wrap {
/*margin-top: 0;*/
}
.contacts_modal_members_list a.contacts_modal_contact {
clear: both;
overflow: hidden;
color: #000;
padding: 8px 9px;
border-radius: 0;
}
.contacts_modal_members_list a.contacts_modal_contact:hover {
border-radius: 2px;
background: #f2f6fa;
}
.contacts_modal_contact_wrap:first-child {
border-top: 0;
.contacts_modal_members_list .active a.contacts_modal_contact {
border-radius: 2px;
background-color: #6490b1;
}
.contacts_modal_members_list .active a.contacts_modal_contact:hover {
background-color: #6490b1;
}
.contacts_modal_contact_name {
display: block;
color: #3C6E97;
@ -1793,9 +1849,6 @@ img.img_fullsize { @@ -1793,9 +1849,6 @@ img.img_fullsize {
.non_osx .contacts_modal_contact_name {
font-size: 12px;
}
.contacts_modal_contact_status {
color: #999;
}
.contacts_modal_contact_photo {
width: 40px;
height: 40px;
@ -1803,6 +1856,50 @@ img.img_fullsize { @@ -1803,6 +1856,50 @@ img.img_fullsize {
overflow: hidden;
}
.contacts_modal_contact_status {
color: #999;
}
a.contacts_modal_contact:hover .contacts_modal_contact_status {
color: #91a6ba;
}
.contacts_modal_members_list .active .contacts_modal_contact_name,
.contacts_modal_members_list .active a.contacts_modal_contact .contacts_modal_contact_status {
color: #FFF;
}
.icon-contact-tick {
position: absolute;
right: 10px;
top: 22px;
width: 17px;
height: 15px;
/*margin: 10px 0 0 -75px;*/
background: url(../img/icons/IconsetW.png?1) -13px -343px no-repeat;
background-size: 42px 460px;
}
.is_1x .icon-contact-tick {
background-image: url(../img/icons/IconsetW_1x.png?2);
}
.contacts_modal_members_list .active .icon-contact-tick,
.contacts_modal_members_list a.contacts_modal_contact:hover .icon-contact-tick {
background-position: -13px -367px;
opacity: 0.5;
}
.contacts_modal_members_list .active .icon-contact-tick {
opacity: 1 !important;
}
.contacts_modal_panel {
padding-top: 10px;
}
.contacts_modal_actions {
padding-top: 10px;
}
/* Messages edit panel */
.im_edit_panel_wrap {
@ -1816,6 +1913,7 @@ img.img_fullsize { @@ -1816,6 +1913,7 @@ img.img_fullsize {
width: 100%;
}
.im_edit_delete_link,
.im_edit_forward_link,
.im_edit_cancel_link {
display: block;
padding: 8px 17px;
@ -1823,11 +1921,13 @@ img.img_fullsize { @@ -1823,11 +1921,13 @@ img.img_fullsize {
.im_edit_cancel_link {
float: left;
}
.im_edit_delete_link {
.im_edit_delete_link,
.im_edit_forward_link {
float: right;
}
.im_edit_delete_link:hover,
.im_edit_forward_link:hover,
.im_edit_cancel_link:hover {
background: #f2f6fa;
text-decoration: none;
@ -1898,8 +1998,11 @@ img.img_fullsize { @@ -1898,8 +1998,11 @@ img.img_fullsize {
.is_1x .icon-select-tick {
background-image: url(../img/icons/IconsetW_1x.png?2);
}
.im_history_selectable .icon-select-tick {
display: inline-block;
@media (min-width: 1024px) {
.im_history_selectable .icon-select-tick {
display: inline-block;
}
}
.im_message_selected .icon-select-tick,
@ -2067,4 +2170,18 @@ img.img_fullsize { @@ -2067,4 +2170,18 @@ img.img_fullsize {
.im_emoji_btn {
display: none;
}
}
/* Dialogs modal */
.peer_select_window .modal-dialog {
max-width: 506px;
}
.peer_select_modal_wrap .modal-body {
padding: 10px 10px 15px;
}
.text-invisible {
visibility: hidden;
}

230
app/js/controllers.js

@ -151,7 +151,7 @@ angular.module('myApp.controllers', []) @@ -151,7 +151,7 @@ angular.module('myApp.controllers', [])
};
})
.controller('AppIMController', function ($scope, $location, $routeParams, $modal, $rootScope, $modalStack, MtpApiManager) {
.controller('AppIMController', function ($scope, $location, $routeParams, $modal, $rootScope, $modalStack, MtpApiManager, AppUsersManager, ContactsSelectService) {
$scope.$on('$routeUpdate', updateCurDialog);
@ -176,14 +176,35 @@ angular.module('myApp.controllers', []) @@ -176,14 +176,35 @@ angular.module('myApp.controllers', [])
}
$scope.openContacts = function () {
$modal.open({
templateUrl: 'partials/contacts_modal.html?3',
controller: 'ContactsModalController',
scope: $rootScope.$new(),
windowClass: 'contacts_modal_window'
ContactsSelectService.selectContact().then(function (userID) {
$scope.dialogSelect(AppUsersManager.getUserString(userID));
});
}
$scope.openGroup = function () {
ContactsSelectService.selectContacts().then(function (userIDs) {
if (userIDs.length == 1) {
$scope.dialogSelect(AppUsersManager.getUserString(userIDs[0]));
} else if (userIDs.length > 1) {
var scope = $rootScope.$new();
scope.userIDs = userIDs;
$modal.open({
templateUrl: 'partials/chat_create_modal.html?3',
controller: 'ChatCreateModalController',
scope: scope,
windowClass: 'contacts_modal_window'
});
}
});
}
$scope.dialogSelect = function (peerString) {
$rootScope.$broadcast('history_focus', {peerString: peerString});
};
updateCurDialog();
function updateCurDialog() {
@ -300,11 +321,11 @@ angular.module('myApp.controllers', []) @@ -300,11 +321,11 @@ angular.module('myApp.controllers', [])
$scope.$broadcast('ui_dialogs_append');
});
}
};
})
.controller('AppImHistoryController', function ($scope, $location, $timeout, $rootScope, MtpApiManager, AppUsersManager, AppChatsManager, AppMessagesManager, AppPeersManager, ApiUpdatesManager, IdleManager, StatusManager) {
.controller('AppImHistoryController', function ($scope, $location, $timeout, $rootScope, MtpApiManager, AppUsersManager, AppChatsManager, AppMessagesManager, AppPeersManager, ApiUpdatesManager, PeersSelectService, IdleManager, StatusManager) {
$scope.$watch('curDialog.peer', applyDialogSelect);
@ -324,6 +345,7 @@ angular.module('myApp.controllers', []) @@ -324,6 +345,7 @@ angular.module('myApp.controllers', [])
$scope.toggleMessage = toggleMessage;
$scope.selectedDelete = selectedDelete;
$scope.selectedForward = selectedForward;
$scope.selectedCancel = selectedCancel;
$scope.toggleEdit = toggleEdit;
$scope.toggleMedia = toggleMedia;
@ -391,16 +413,14 @@ angular.module('myApp.controllers', []) @@ -391,16 +413,14 @@ angular.module('myApp.controllers', [])
if (!hasMore || !offset) {
return;
}
// console.trace('load history');
console.trace('load history');
var inputMediaFilter = $scope.mediaType && {_: inputMediaFilters[$scope.mediaType]},
getMessagesPromise = inputMediaFilter
? AppMessagesManager.getSearch($scope.curDialog.inputPeer, '', inputMediaFilter, maxID, startLimit)
: AppMessagesManager.getHistory($scope.curDialog.inputPeer, maxID, startLimit);
? AppMessagesManager.getSearch($scope.curDialog.inputPeer, '', inputMediaFilter, maxID, limit)
: AppMessagesManager.getHistory($scope.curDialog.inputPeer, maxID, limit);
getMessagesPromise.then(function (historyResult) {
console.log('got', maxID, historyResult);
offset += limit;
hasMore = offset < historyResult.count;
maxID = historyResult.history[historyResult.history.length - 1];
@ -497,6 +517,24 @@ angular.module('myApp.controllers', []) @@ -497,6 +517,24 @@ angular.module('myApp.controllers', [])
}
}
function selectedForward () {
if ($scope.selectedCount > 0) {
var selectedMessageIDs = [];
angular.forEach($scope.selectedMsgs, function (t, messageID) {
selectedMessageIDs.push(messageID);
});
PeersSelectService.selectPeer().then(function (peerString) {
var inputPeer = AppPeersManager.getInputPeer(peerString);
AppMessagesManager.forwardMessages(selectedMessageIDs, inputPeer).then(function () {
selectedCancel();
});
});
}
}
function toggleEdit () {
if ($scope.selectActions) {
selectedCancel();
@ -757,7 +795,7 @@ angular.module('myApp.controllers', []) @@ -757,7 +795,7 @@ angular.module('myApp.controllers', [])
};
})
.controller('ChatModalController', function ($scope, $timeout, $rootScope, AppUsersManager, AppChatsManager, MtpApiManager, NotificationsManager, AppMessagesManager, AppPeersManager, ApiUpdatesManager) {
.controller('ChatModalController', function ($scope, $timeout, $rootScope, AppUsersManager, AppChatsManager, MtpApiManager, NotificationsManager, AppMessagesManager, AppPeersManager, ApiUpdatesManager, ContactsSelectService) {
$scope.chatFull = AppChatsManager.wrapForFull($scope.chatID, {});
@ -826,6 +864,73 @@ angular.module('myApp.controllers', []) @@ -826,6 +864,73 @@ angular.module('myApp.controllers', [])
};
$scope.inviteToGroup = function () {
var disabled = [];
angular.forEach($scope.chatFull.participants.participants, function(participant){
disabled.push(participant.user_id);
});
ContactsSelectService.selectContacts({disabled: disabled}).then(function (userIDs) {
angular.forEach(userIDs, function () {
MtpApiManager.invokeApi('messages.addChatUser', {
chat_id: $scope.chatID,
user_id: {_: 'inputUserContact', user_id: userIDs},
fwd_limit: 100
}).then(function (addResult) {
AppUsersManager.saveApiUsers(addResult.users);
AppChatsManager.saveApiChats(addResult.chats);
if (ApiUpdatesManager.saveSeq(addResult.seq)) {
ApiUpdatesManager.saveUpdate({
_: 'updateNewMessage',
message: addResult.message,
pts: addResult.pts
});
}
});
});
$rootScope.$broadcast('history_focus', {peerString: $scope.chatFull.peerString});
});
MtpApiManager.invokeApi('messages.addChatUser', {
chat_id: $scope.chatID,
user_id: {_: 'inputUserSelf'}
}).then(function (result) {
if (ApiUpdatesManager.saveSeq(result.seq)) {
ApiUpdatesManager.saveUpdate({
_: 'updateNewMessage',
message: result.message,
pts: result.pts
});
}
$rootScope.$broadcast('history_focus', {peerString: $scope.chatFull.peerString});
});
};
$scope.kickFromGroup = function (userID) {
var user = AppUsersManager.getUser(userID);
console.log({_: 'inputUserForeign', user_id: userID, access_hash: user.access_hash || '0'}, user);
MtpApiManager.invokeApi('messages.deleteChatUser', {
chat_id: $scope.chatID,
user_id: {_: 'inputUserForeign', user_id: userID, access_hash: user.access_hash || '0'}
}).then(function (result) {
if (ApiUpdatesManager.saveSeq(result.seq)) {
ApiUpdatesManager.saveUpdate({
_: 'updateNewMessage',
message: result.message,
pts: result.pts
});
}
$rootScope.$broadcast('history_focus', {peerString: $scope.chatFull.peerString});
});
};
$scope.flushHistory = function () {
if (confirm('Are you sure? This can not be undone!') !== true) {
@ -931,9 +1036,29 @@ angular.module('myApp.controllers', []) @@ -931,9 +1036,29 @@ angular.module('myApp.controllers', [])
}
})
.controller('ContactsModalController', function ($scope, AppUsersManager) {
.controller('ContactsModalController', function ($scope, $modalInstance, AppUsersManager) {
$scope.contacts = [];
$scope.search = [];
$scope.search = {};
$scope.selectedContacts = {};
$scope.disabledContacts = {};
$scope.selectedCount = 0;
if ($scope.disabled) {
for (var i = 0; i < $scope.disabled.length; i++) {
$scope.disabledContacts[$scope.disabled[i]] = true;
}
}
console.log($scope.disabled, $scope.disabledContacts);
if ($scope.selected) {
for (var i = 0; i < $scope.selected.length; i++) {
if (!$scope.selectedContacts[$scope.selected[i]]) {
$scope.selectedContacts[$scope.selected[i]] = true;
$scope.selectedCount++;
}
}
}
$scope.$watch('search.query', function (newValue) {
AppUsersManager.getContacts(newValue).then(function (contactsList) {
@ -946,10 +1071,81 @@ angular.module('myApp.controllers', []) @@ -946,10 +1071,81 @@ angular.module('myApp.controllers', [])
}
$scope.contacts.push(contact);
});
$scope.$broadcast('contacts_change');
});
})
});
$scope.contactSelect = function (userID) {
if ($scope.disabledContacts[userID]) {
return false;
}
if (!$scope.multiSelect) {
return $modalInstance.close(userID);
}
if ($scope.selectedContacts[userID]) {
delete $scope.selectedContacts[userID];
$scope.selectedCount--;
} else {
$scope.selectedContacts[userID] = true;
$scope.selectedCount++;
}
};
$scope.submitSelected = function () {
if ($scope.selectedCount > 0) {
var selectedUserIDs = [];
angular.forEach($scope.selectedContacts, function (t, userID) {
selectedUserIDs.push(userID);
});
return $modalInstance.close(selectedUserIDs);
}
}
})
.controller('PeerSelectController', function ($scope, $modalInstance) {
$scope.dialogSelect = function (peerString) {
$modalInstance.close(peerString);
};
})
.controller('ChatCreateModalController', function ($scope, $modalInstance, $rootScope, MtpApiManager, AppChatsManager) {
$scope.group = {name: ''};
$scope.createGroup = function () {
if (!$scope.group.name) {
return;
}
var inputUsers = [];
angular.forEach($scope.userIDs, function(userID) {
inputUsers.push({_: 'inputUserContact', user_id: userID});
});
return MtpApiManager.invokeApi('messages.createChat', {
title: $scope.group.name,
users: inputUsers
}).then(function (createdResult) {
$modalInstance.close();
AppUsersManager.saveApiUsers(createdResult.users);
AppChatsManager.saveApiChats(createdResult.chats);
if (ApiUpdatesManager.saveSeq(createdResult.seq)) {
ApiUpdatesManager.saveUpdate({
_: 'updateNewMessage',
message: createdResult.message,
pts: createdResult.pts
});
}
var peerString = AppChatsManager.getChatString(message.to_id.chat_id);
$rootScope.$broadcast('history_focus', {peerString: peerString});
});
};
$scope.back = function () {
$modalInstance.dismiss();
};
})

47
app/js/directives.js

@ -81,9 +81,18 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -81,9 +81,18 @@ angular.module('myApp.directives', ['myApp.filters'])
function updateSizes () {
if (attrs.modal) {
$(element).css({
height: $($window).height() - 200
});
updateScroller();
return;
}
$(element).css({
height: $($window).height() - footer.offsetHeight - (headWrap ? headWrap.offsetHeight : 50) - 72
});
updateScroller();
if (!headWrap) {
headWrap = $('.tg_page_head')[0];
}
@ -96,6 +105,38 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -96,6 +105,38 @@ angular.module('myApp.directives', ['myApp.filters'])
})
.directive('myContactsList', function($window, $timeout) {
return {
link: link
};
function link (scope, element, attrs) {
var searchWrap = $('.contacts_modal_search')[0],
panelWrap = $('.contacts_modal_panel')[0],
contactsWrap = $('.contacts_wrap', element)[0];
onContentLoaded(function () {
$(contactsWrap).nanoScroller({preventPageScrolling: true, tabIndex: -1, iOSNativeScrolling: true});
updateSizes();
});
function updateSizes () {
$(element).css({
height: $($window).height() - (panelWrap && panelWrap.offsetHeight || 0) - (searchWrap && searchWrap.offsetHeight || 0) - 200
});
$(contactsWrap).nanoScroller();
}
$($window).on('resize', updateSizes);
scope.$on('contacts_change', function () {
onContentLoaded(updateSizes)
});
};
})
.directive('myHistory', function ($window, $timeout) {
return {
@ -711,7 +752,11 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -711,7 +752,11 @@ angular.module('myApp.directives', ['myApp.filters'])
} else if (time % 1000 <= 600) {
cnt = 2;
}
element.html((new Array(cnt + 1)).join('.'));
var text = '...',
html = text.substr(0, cnt + 1) + (cnt < 2 ? ('<span class="text-invisible">' + text.substr(cnt + 1) + '</span>') : '');
element.html(html);
}, 200);
scope.$on('$destroy', function cleanup() {

23
app/js/lib/mtproto.js

@ -893,12 +893,12 @@ factory('MtpDcConfigurator', function () { @@ -893,12 +893,12 @@ factory('MtpDcConfigurator', function () {
var dcOptions = window._testMode
? [
{id: 1, host: '173.240.5.253', port: 80},
{id: 2, host: '95.142.192.65', port: 80},
{id: 2, host: '109.239.131.195', port: 80},
{id: 3, host: '174.140.142.5', port: 80}
]
: [
{id: 1, host: '173.240.5.1', port: 80},
{id: 2, host: '95.142.192.66', port: 80},
{id: 2, host: '109.239.131.193', port: 80},
{id: 3, host: '174.140.142.6', port: 80},
{id: 4, host: '31.210.235.12', port: 80},
{id: 5, host: '116.51.22.2', port: 80},
@ -1500,11 +1500,16 @@ factory('MtpSha1Service', function ($q) { @@ -1500,11 +1500,16 @@ factory('MtpSha1Service', function ($q) {
}
}).
factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerator, MtpSecureRandom, MtpSha1Service, MtpAesService, AppConfigManager, $http, $q, $timeout, $interval) {
factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerator, MtpSecureRandom, MtpSha1Service, MtpAesService, AppConfigManager, $http, $q, $timeout, $interval, $rootScope) {
var updatesProcessor,
iii = 0,
offline = false;
offline;
$rootScope.offline = true;
$rootScope.retryOnline = function () {
$(document.body).trigger('online');
}
function MtpNetworker(dcID, authKey, serverSalt, options) {
options = options || {};
@ -1759,6 +1764,8 @@ factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerato @@ -1759,6 +1764,8 @@ factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerato
};
MtpNetworker.prototype.checkConnection = function(event) {
$rootScope.offlineConnecting = true;
console.log('check connection', event);
$timeout.cancel(this.checkConnectionPromise);
@ -1775,21 +1782,26 @@ factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerato @@ -1775,21 +1782,26 @@ factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerato
var self = this;
this.sendEncryptedRequest(pingMessage).then(function (result) {
delete $rootScope.offlineConnecting;
self.toggleOffline(false);
}, function () {
console.log('delay ', self.checkConnectionPeriod * 1000);
self.checkConnectionPromise = $timeout(self.checkConnection.bind(self), parseInt(self.checkConnectionPeriod * 1000));
self.checkConnectionPeriod = Math.min(60, self.checkConnectionPeriod * 1.5);
$timeout(function () {
delete $rootScope.offlineConnecting;
}, 1000);
})
};
MtpNetworker.prototype.toggleOffline = function(enabled) {
console.log('toggle ', enabled, this.dcID, this.iii);
if (this.offline == enabled) {
if (this.offline !== undefined && this.offline == enabled) {
return false;
}
this.offline = enabled;
$rootScope.offline = enabled;
if (this.offline) {
$timeout.cancel(this.nextReqPromise);
@ -1912,6 +1924,7 @@ factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerato @@ -1912,6 +1924,7 @@ factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerato
var self = this;
this.sendEncryptedRequest(message).then(function (result) {
self.toggleOffline(false);
self.parseResponse(result.data).then(function (response) {
if (window._debugMode) {
console.log('Server response', self.dcID, response);

100
app/js/services.js

@ -118,7 +118,7 @@ angular.module('myApp.services', []) @@ -118,7 +118,7 @@ angular.module('myApp.services', [])
};
})
.service('AppUsersManager', function ($rootScope, $modal, $modalStack, MtpApiFileManager, MtpApiManager, RichTextProcessor, SearchIndexManager) {
.service('AppUsersManager', function ($rootScope, $modal, $modalStack, $filter, MtpApiFileManager, MtpApiManager, RichTextProcessor, SearchIndexManager) {
var users = {},
contactsFillPromise,
contactsIndex = SearchIndexManager.createIndex();
@ -180,12 +180,16 @@ angular.module('myApp.services', []) @@ -180,12 +180,16 @@ angular.module('myApp.services', [])
return;
}
if (apiUser.phone) {
apiUser.rPhone = $filter('phoneNumber')(apiUser.phone);
}
if (apiUser.first_name) {
apiUser.rFirstName = RichTextProcessor.wrapRichText(apiUser.first_name, {noLinks: true, noLinebreaks: true});
apiUser.rFullName = RichTextProcessor.wrapRichText(apiUser.first_name + ' ' + (apiUser.last_name || ''), {noLinks: true, noLinebreaks: true});
} else {
apiUser.rFirstName = RichTextProcessor.wrapRichText(apiUser.last_name, {noLinks: true, noLinebreaks: true}) || 'DELETED';
apiUser.rFullName = RichTextProcessor.wrapRichText(apiUser.last_name, {noLinks: true, noLinebreaks: true}) || 'DELETED';
apiUser.rFirstName = RichTextProcessor.wrapRichText(apiUser.last_name, {noLinks: true, noLinebreaks: true}) || apiUser.rPhone || 'DELETED';
apiUser.rFullName = RichTextProcessor.wrapRichText(apiUser.last_name, {noLinks: true, noLinebreaks: true}) || apiUser.rPhone || 'DELETED';
}
apiUser.sortName = $.trim((apiUser.last_name || '') + ' ' + apiUser.first_name);
apiUser.sortStatus = apiUser.status && (apiUser.status.expires || apiUser.status.was_online) || 0;
@ -361,11 +365,15 @@ angular.module('myApp.services', []) @@ -361,11 +365,15 @@ angular.module('myApp.services', [])
var chatFull = angular.copy(fullChat),
chat = getChat(id);
if (chatFull.participants && chatFull.participants._ == 'chatParticipants') {
angular.forEach(chatFull.participants.participants, function(participant){
participant.user = AppUsersManager.getUser(participant.user_id);
participant.userPhoto = AppUsersManager.getUserPhoto(participant.user_id, 'User');
participant.inviter = AppUsersManager.getUser(participant.inviter_id);
MtpApiManager.getUserID().then(function (myID) {
angular.forEach(chatFull.participants.participants, function(participant){
participant.user = AppUsersManager.getUser(participant.user_id);
participant.userPhoto = AppUsersManager.getUserPhoto(participant.user_id, 'User');
participant.inviter = AppUsersManager.getUser(participant.inviter_id);
participant.canKick = myID == chat.admin_id || myID == participant.inviter_id;
});
});
}
@ -1126,6 +1134,28 @@ angular.module('myApp.services', []) @@ -1126,6 +1134,28 @@ angular.module('myApp.services', [])
pendingByRandomID[randomIDS] = [peerID, messageID];
}
function forwardMessages (msgIDs, inputPeer) {
return MtpApiManager.invokeApi('messages.forwardMessages', {
peer: inputPeer,
id: msgIDs
}).then(function (forwardResult) {
AppUsersManager.saveApiUsers(forwardResult.users);
AppChatsManager.saveApiChats(forwardResult.chats);
if (ApiUpdatesManager.saveSeq(forwardResult.seq)) {
angular.forEach(forwardResult.messages, function(apiMessage) {
ApiUpdatesManager.saveUpdate({
_: 'updateNewMessage',
message: apiMessage,
pts: forwardResult.pts
});
});
}
});
};
function finalizePendingMessage(randomID, finalMessage) {
var pendingData = pendingByRandomID[randomID];
@ -1178,7 +1208,7 @@ angular.module('myApp.services', []) @@ -1178,7 +1208,7 @@ angular.module('myApp.services', [])
if (toID < 0) {
return toID;
} else if (message.out) {
return toID
return toID;
}
return message.from_id;
}
@ -1533,6 +1563,7 @@ angular.module('myApp.services', []) @@ -1533,6 +1563,7 @@ angular.module('myApp.services', [])
saveMessages: saveMessages,
sendText: sendText,
sendFile: sendFile,
forwardMessages: forwardMessages,
getMessagePeer: getMessagePeer,
wrapForDialog: wrapForDialog,
wrapForHistory: wrapForHistory
@ -2231,7 +2262,7 @@ angular.module('myApp.services', []) @@ -2231,7 +2262,7 @@ angular.module('myApp.services', [])
'<a href="',
encodeEntities(match[2] + '://' + match[4]),
'" target="_blank">',
encodeEntities((match[2] != 'http' ? match[2] + '://' : '') + match[4]),
encodeEntities(match[2] + '://' + match[4]),
'</a>'
);
}
@ -2591,3 +2622,54 @@ angular.module('myApp.services', []) @@ -2591,3 +2622,54 @@ angular.module('myApp.services', [])
showSimpleError: showSimpleError
}
})
.service('PeersSelectService', function ($rootScope, $modal) {
function selectPeer () {
var scope = $rootScope.$new();
// angular.extend(scope, params);
return $modal.open({
templateUrl: 'partials/peer_select.html',
controller: 'PeerSelectController',
scope: scope,
windowClass: 'peer_select_window'
}).result;
}
return {
selectPeer: selectPeer
}
})
.service('ContactsSelectService', function ($rootScope, $modal) {
function select (multiSelect, options) {
options = options || {};
var scope = $rootScope.$new();
scope.multiSelect = multiSelect;
angular.extend(scope, options);
return $modal.open({
templateUrl: 'partials/contacts_modal.html',
controller: 'ContactsModalController',
scope: scope,
windowClass: 'contacts_modal_window'
}).result;
}
return {
selectContacts: function (options) {
return select (true, options);
},
selectContact: function (options) {
return select (false, options);
},
}
})

30
app/partials/chat_create_modal.html

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
<div class="contacts_modal_wrap">
<div class="modal-header">
<a class="modal-close-link" ng-click="$close()">Close</a>
<h4 class="modal-title">Create Chat</h4>
</div>
<div class="modal-body">
<form ng-submit="createGroup()">
<div class="contacts_modal_group_title">
<input class="form-control" my-focused type="text" placeholder="Group name" ng-model="group.name"/>
</div>
<div class="contacts_modal_panel clearfix">
<div class="contacts_modal_actions pull-right">
<button class="btn btn-default" ng-click="$dismiss()"> Cancel </button>
<button class="btn btn-tg" type="submit"> Create </button>
</div>
</div>
</form>
</div>
</div>

7
app/partials/chat_modal.html

@ -41,14 +41,19 @@ @@ -41,14 +41,19 @@
<div class="chat_modal_leave" ng-if="chatFull.chat.left">
<a href="" ng-click="returnToGroup()">Return to group</a>
</div>
</div>
</div>
</div>
<h5 class="chat_modal_members_header">Members</h5>
<h5 class="chat_modal_members_header">
<a href="" ng-click="inviteToGroup()" ng-if="!chatFull.chat.left &amp;&amp; chatFull.participants.participants.length" class="pull-right">Add participant</a>
Members
</h5>
<div class="chat_modal_members_list">
<div class="chat_modal_participant_wrap clearfix" ng-repeat="participant in chatFull.participants.participants | orderBy:'-user.sortStatus'">
<a ng-if="participant.canKick" ng-click="kickFromGroup(participant.userID)" class="chat_modal_participant_kick pull-right">Kick</a>
<a ng-click="openUser(participant.user_id)" class="chat_modal_participant_photo pull-left">
<img
class="chat_modal_participant_photo"

53
app/partials/contacts_modal.html

@ -12,25 +12,50 @@ @@ -12,25 +12,50 @@
<a class="contacts_modal_search_clear" ng-click="search.query = ''" ng-show="search.query.length"></a>
</div>
<div class="contacts_modal_members_list">
<div class="contacts_modal_contact_wrap clearfix" ng-repeat="contact in contacts | orderBy:'user.sortName' track by contact.userID">
<a ng-click="openUser(contact.userID)" class="contacts_modal_contact_photo pull-left">
<img
class="contacts_modal_contact_photo"
my-load-thumb
thumb="contact.userPhoto"
/>
<i class="icon status_online" ng-show="contact.user.status._ == 'userStatusOnline'"></i>
</a>
<div class="contacts_modal_contact_name">
<a ng-click="openUser(contact.user.id)" ng-bind-html="contact.user.rFullName"></a>
<div my-contacts-list class="contacts_modal_col">
<div class="contacts_wrap nano">
<div class="contacts_scrollable_wrap content">
<ul class="contacts_modal_members_list nav nav-pills nav-stacked">
<li class="contacts_modal_contact_wrap clearfix" ng-repeat="contact in contacts | orderBy:'user.sortName' track by contact.userID" ng-class="{active: selectedContacts[contact.userID], disabled: disabledContacts[contact.userID]}">
<a class="contacts_modal_contact" ng-click="contactSelect(contact.userID)">
<i ng-if="multiSelect" class="icon icon-contact-tick"></i>
<div class="contacts_modal_contact_photo pull-left">
<img
class="contacts_modal_contact_photo"
my-load-thumb
thumb="contact.userPhoto"
/>
<i class="icon status_online" ng-show="contact.user.status._ == 'userStatusOnline'"></i>
</div>
<div class="contacts_modal_contact_name" ng-bind-html="contact.user.rFullName"></div>
<div class="contacts_modal_contact_status">{{contact.user | userStatus}}</div>
</a>
</li>
</ul>
</div>
<div class="contacts_modal_contact_status">{{contact.user | userStatus}}</div>
</div>
</div>
<div ng-if="multiSelect" class="contacts_modal_panel">
<button class="btn btn-tg btn-block" ng-class="{disabled: !selectedCount}" ng-disabled="!selectedCount" ng-click="submitSelected()" type="submit">
Next »
</button>
</div>
</div>
</div>

2
app/partials/dialog.html

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
<a class="im_dialog" href="#/im?p={{dialogMessage.peerString}}">
<a class="im_dialog" ng-click="dialogSelect(dialogMessage.peerString)">
<div class="im_dialog_meta pull-right text-right">
<div class="im_dialog_date">

11
app/partials/head.html

@ -20,11 +20,20 @@ @@ -20,11 +20,20 @@
<div class="navbar-collapse" collapse="navbarCollapsed">
<ul class="nav navbar-nav navbar-right">
<ul ng-if="offline" class="nav navbar-nav navbar-offline">
<li ng-show="!offlineConnecting"><span class="navbar-offline-text">Waiting for network<span my-typing-dots></span></span></li>
<li ng-show="!offlineConnecting"><a href="" ng-click="retryOnline()">Retry</a></li>
<li ng-show="offlineConnecting"><span class="navbar-offline-text">Connecting<span my-typing-dots></span></span></li>
</ul>
<ul ng-if="!offline" class="nav navbar-nav navbar-right">
<li ng-if="isLoggedIn"><a href="" ng-click="openGroup()">New Chat</a></li>
<li ng-if="isLoggedIn"><a href="" ng-click="openContacts()">Contacts</a></li>
<li ng-if="isLoggedIn"><a href="" ng-click="openSettings()">Settings</a></li>
<li><a href="https://github.com/zhukov/webogram" target="_blank">About</a></li>
</ul>
</div>
</div>
</div>

1
app/partials/im.html

@ -79,6 +79,7 @@ @@ -79,6 +79,7 @@
<div class="im_edit_panel_wrap clearfix" ng-show="selectActions">
<a class="im_edit_delete_link" ng-click="selectedDelete()"><i class="icon icon-delete"></i></a>
<a class="im_edit_forward_link" ng-click="selectedForward()">Forward</a>
<a class="im_edit_cancel_link" ng-click="selectedCancel()">Cancel</a>
<h4 class="im_edit_panel_title">
<ng-pluralize count="selectedCount"

28
app/partials/peer_select.html

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
<div class="peer_select_modal_wrap">
<div class="modal-header">
<a class="modal-close-link" ng-click="$close()">Close</a>
<h4 class="modal-title">Select conversation</h4>
</div>
<div class="modal-body">
<div class="im_dialogs_modal_col_wrap" ng-controller="AppImDialogsController">
<div class="im_dialogs_search">
<input class="form-control im_dialogs_search_field" type="search" placeholder="Search" ng-model="search.query"/>
<a class="im_dialogs_search_clear" ng-click="search.query = ''" ng-show="search.query.length"></a>
</div>
<div my-dialogs-list modal="true" class="im_dialogs_modal_col">
<div class="im_dialogs_wrap nano">
<div class="im_dialogs_scrollable_wrap content">
<ul 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"></li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
Loading…
Cancel
Save