Improved message date format
Added date splitters when messages were sent on different days Closes #286
This commit is contained in:
parent
cf9a770679
commit
8682586ca9
@ -1818,6 +1818,16 @@ img.im_message_document_thumb {
|
|||||||
padding: 0 0 20px 10px;
|
padding: 0 0 20px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.im_message_date_seconds {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
position: absolute;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.im_message_meta:hover .im_message_date_seconds {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 900px) {
|
@media (max-width: 900px) {
|
||||||
|
|
||||||
/* Status ticks */
|
/* Status ticks */
|
||||||
|
@ -728,39 +728,6 @@ angular.module('myApp.controllers', [])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateHistoryGroups (limit) {
|
|
||||||
var start = 0,
|
|
||||||
end = $scope.history.length,
|
|
||||||
i, curMessage, prevMessage;
|
|
||||||
|
|
||||||
if (limit > 0) {
|
|
||||||
end = limit;
|
|
||||||
} else if (limit < 0) {
|
|
||||||
start = end + limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = start; i < end; i++) {
|
|
||||||
curMessage = $scope.history[i];
|
|
||||||
if (prevMessage &&
|
|
||||||
curMessage.from_id == prevMessage.from_id &&
|
|
||||||
!prevMessage.fwd_from_id == !curMessage.fwd_from_id &&
|
|
||||||
!prevMessage.action &&
|
|
||||||
!curMessage.action &&
|
|
||||||
curMessage.date < prevMessage.date + 900) {
|
|
||||||
|
|
||||||
var singleLine = curMessage.message && curMessage.message.length < 70 && curMessage.message.indexOf("\n") == -1;
|
|
||||||
if (curMessage.fwd_from_id && curMessage.fwd_from_id == prevMessage.fwd_from_id) {
|
|
||||||
curMessage.grouped = singleLine ? 4 : 3;
|
|
||||||
} else {
|
|
||||||
curMessage.grouped = !curMessage.fwd_from_id && singleLine ? 1 : 2;
|
|
||||||
}
|
|
||||||
} else if (prevMessage || !i) {
|
|
||||||
delete curMessage.grouped;
|
|
||||||
}
|
|
||||||
prevMessage = curMessage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function messageFocusHistory () {
|
function messageFocusHistory () {
|
||||||
var i, found = false;
|
var i, found = false;
|
||||||
for (i = 0; i < $scope.history.length; i++) {
|
for (i = 0; i < $scope.history.length; i++) {
|
||||||
@ -803,7 +770,7 @@ angular.module('myApp.controllers', [])
|
|||||||
minID = historyResult.history.length >= backLimit
|
minID = historyResult.history.length >= backLimit
|
||||||
? historyResult.history[0]
|
? historyResult.history[0]
|
||||||
: 0;
|
: 0;
|
||||||
updateHistoryGroups(-backLimit);
|
AppMessagesManager.regroupWrappedHistory($scope.history, -backLimit);
|
||||||
$scope.$broadcast('ui_history_append');
|
$scope.$broadcast('ui_history_append');
|
||||||
} else {
|
} else {
|
||||||
minID = 0;
|
minID = 0;
|
||||||
@ -837,7 +804,7 @@ angular.module('myApp.controllers', [])
|
|||||||
|
|
||||||
if (historyResult.history.length) {
|
if (historyResult.history.length) {
|
||||||
maxID = historyResult.history[historyResult.history.length - 1];
|
maxID = historyResult.history[historyResult.history.length - 1];
|
||||||
updateHistoryGroups(historyResult.history.length + 1);
|
AppMessagesManager.regroupWrappedHistory($scope.history, historyResult.history.length + 1);
|
||||||
$scope.$broadcast('ui_history_prepend');
|
$scope.$broadcast('ui_history_prepend');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -898,7 +865,7 @@ angular.module('myApp.controllers', [])
|
|||||||
});
|
});
|
||||||
$scope.history.reverse();
|
$scope.history.reverse();
|
||||||
|
|
||||||
updateHistoryGroups();
|
AppMessagesManager.regroupWrappedHistory($scope.history);
|
||||||
|
|
||||||
if (historyResult.unreadOffset) {
|
if (historyResult.unreadOffset) {
|
||||||
$scope.historyUnreadAfter = historyResult.history[historyResult.unreadOffset - 1];
|
$scope.historyUnreadAfter = historyResult.history[historyResult.unreadOffset - 1];
|
||||||
@ -1074,7 +1041,7 @@ angular.module('myApp.controllers', [])
|
|||||||
// console.log('append', addedMessage);
|
// console.log('append', addedMessage);
|
||||||
// console.trace();
|
// console.trace();
|
||||||
$scope.history.push(AppMessagesManager.wrapForHistory(addedMessage.messageID));
|
$scope.history.push(AppMessagesManager.wrapForHistory(addedMessage.messageID));
|
||||||
updateHistoryGroups(-3);
|
AppMessagesManager.regroupWrappedHistory($scope.history, -3);
|
||||||
$scope.typing = {};
|
$scope.typing = {};
|
||||||
$scope.$broadcast('ui_history_append_new', {my: addedMessage.my});
|
$scope.$broadcast('ui_history_append_new', {my: addedMessage.my});
|
||||||
if (addedMessage.my) {
|
if (addedMessage.my) {
|
||||||
@ -1100,7 +1067,7 @@ angular.module('myApp.controllers', [])
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
$scope.history = newHistory;
|
$scope.history = newHistory;
|
||||||
updateHistoryGroups();
|
AppMessagesManager.regroupWrappedHistory($scope.history);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -74,6 +74,37 @@ angular.module('myApp.filters', [])
|
|||||||
}
|
}
|
||||||
}])
|
}])
|
||||||
|
|
||||||
|
.filter('time', ['$filter', function($filter) {
|
||||||
|
var cachedDates = {};
|
||||||
|
|
||||||
|
return function (timestamp) {
|
||||||
|
if (cachedDates[timestamp]) {
|
||||||
|
return cachedDates[timestamp];
|
||||||
|
}
|
||||||
|
|
||||||
|
return cachedDates[timestamp] = $filter('date')(timestamp * 1000, 'HH:mm');
|
||||||
|
}
|
||||||
|
}])
|
||||||
|
|
||||||
|
.filter('myDate', ['$filter', function($filter) {
|
||||||
|
var cachedDates = {};
|
||||||
|
|
||||||
|
return function (timestamp) {
|
||||||
|
if (cachedDates[timestamp]) {
|
||||||
|
return cachedDates[timestamp];
|
||||||
|
}
|
||||||
|
|
||||||
|
return cachedDates[timestamp] = $filter('date')(timestamp * 1000, 'fullDate');
|
||||||
|
}
|
||||||
|
}])
|
||||||
|
|
||||||
|
.filter('seconds', function($filter) {
|
||||||
|
return function (timestamp) {
|
||||||
|
var sec = timestamp % 60;
|
||||||
|
return sec < 10 ? '0' + sec : sec;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
.filter('duration', [function() {
|
.filter('duration', [function() {
|
||||||
return function (duration) {
|
return function (duration) {
|
||||||
var secs = duration % 60,
|
var secs = duration % 60,
|
||||||
|
@ -118,7 +118,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
return new SecureRandom();
|
return new SecureRandom();
|
||||||
})
|
})
|
||||||
|
|
||||||
.factory('MtpDateManager', function (Storage) {
|
.factory('MtpTimeManager', function (Storage) {
|
||||||
var lastMessageID = [0, 0],
|
var lastMessageID = [0, 0],
|
||||||
timeOffset = 0;
|
timeOffset = 0;
|
||||||
|
|
||||||
@ -171,7 +171,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
||||||
.factory('MtpAuthorizer', function (MtpDcConfigurator, MtpRsaKeysManager, MtpSecureRandom, MtpDateManager, CryptoWorker, $http, $q, $timeout) {
|
.factory('MtpAuthorizer', function (MtpDcConfigurator, MtpRsaKeysManager, MtpSecureRandom, MtpTimeManager, CryptoWorker, $http, $q, $timeout) {
|
||||||
|
|
||||||
function mtpSendPlainRequest (dcID, requestBuffer) {
|
function mtpSendPlainRequest (dcID, requestBuffer) {
|
||||||
var requestLength = requestBuffer.byteLength,
|
var requestLength = requestBuffer.byteLength,
|
||||||
@ -179,7 +179,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
|
|
||||||
var header = new TLSerialization();
|
var header = new TLSerialization();
|
||||||
header.storeLongP(0, 0, 'auth_key_id'); // Auth key
|
header.storeLongP(0, 0, 'auth_key_id'); // Auth key
|
||||||
header.storeLong(MtpDateManager.generateID(), 'msg_id'); // Msg_id
|
header.storeLong(MtpTimeManager.generateID(), 'msg_id'); // Msg_id
|
||||||
header.storeInt(requestLength, 'request_length');
|
header.storeInt(requestLength, 'request_length');
|
||||||
|
|
||||||
var headerBuffer = header.getBuffer(),
|
var headerBuffer = header.getBuffer(),
|
||||||
@ -391,7 +391,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
throw new Error('server_DH_inner_data SHA1-hash mismatch');
|
throw new Error('server_DH_inner_data SHA1-hash mismatch');
|
||||||
}
|
}
|
||||||
|
|
||||||
MtpDateManager.applyServerTime(auth.serverTime, auth.localTime);
|
MtpTimeManager.applyServerTime(auth.serverTime, auth.localTime);
|
||||||
};
|
};
|
||||||
|
|
||||||
function mtpSendSetClientDhParams(auth) {
|
function mtpSendSetClientDhParams(auth) {
|
||||||
@ -539,7 +539,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
.factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpDateManager, MtpSecureRandom, Storage, CryptoWorker, $http, $q, $timeout, $interval, $rootScope) {
|
.factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpTimeManager, MtpSecureRandom, Storage, CryptoWorker, $http, $q, $timeout, $interval, $rootScope) {
|
||||||
|
|
||||||
var updatesProcessor,
|
var updatesProcessor,
|
||||||
iii = 0,
|
iii = 0,
|
||||||
@ -642,7 +642,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
sentMessage.inner = newInner;
|
sentMessage.inner = newInner;
|
||||||
}
|
}
|
||||||
|
|
||||||
sentMessage.msg_id = MtpDateManager.generateID();
|
sentMessage.msg_id = MtpTimeManager.generateID();
|
||||||
sentMessage.seq_no = this.generateSeqNo(
|
sentMessage.seq_no = this.generateSeqNo(
|
||||||
sentMessage.notContentRelated ||
|
sentMessage.notContentRelated ||
|
||||||
sentMessage.container
|
sentMessage.container
|
||||||
@ -669,7 +669,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
|
|
||||||
serializer.storeMethod(method, params);
|
serializer.storeMethod(method, params);
|
||||||
|
|
||||||
var messageID = MtpDateManager.generateID(),
|
var messageID = MtpTimeManager.generateID(),
|
||||||
seqNo = this.generateSeqNo(),
|
seqNo = this.generateSeqNo(),
|
||||||
message = {
|
message = {
|
||||||
msg_id: messageID,
|
msg_id: messageID,
|
||||||
@ -690,7 +690,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
var serializer = new TLSerialization({mtproto: true});
|
var serializer = new TLSerialization({mtproto: true});
|
||||||
serializer.storeObject(object, 'Object');
|
serializer.storeObject(object, 'Object');
|
||||||
|
|
||||||
var messageID = MtpDateManager.generateID(),
|
var messageID = MtpTimeManager.generateID(),
|
||||||
seqNo = this.generateSeqNo(options.notContentRelated),
|
seqNo = this.generateSeqNo(options.notContentRelated),
|
||||||
message = {
|
message = {
|
||||||
msg_id: messageID,
|
msg_id: messageID,
|
||||||
@ -725,7 +725,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
|
|
||||||
options.resultType = serializer.storeMethod(method, params);
|
options.resultType = serializer.storeMethod(method, params);
|
||||||
|
|
||||||
var messageID = MtpDateManager.generateID(),
|
var messageID = MtpTimeManager.generateID(),
|
||||||
seqNo = this.generateSeqNo(),
|
seqNo = this.generateSeqNo(),
|
||||||
message = {
|
message = {
|
||||||
msg_id: messageID,
|
msg_id: messageID,
|
||||||
@ -849,7 +849,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
serializer.storeMethod('ping', {ping_id: pingID});
|
serializer.storeMethod('ping', {ping_id: pingID});
|
||||||
|
|
||||||
var pingMessage = {
|
var pingMessage = {
|
||||||
msg_id: MtpDateManager.generateID(),
|
msg_id: MtpTimeManager.generateID(),
|
||||||
seq_no: this.generateSeqNo(true),
|
seq_no: this.generateSeqNo(true),
|
||||||
body: serializer.getBytes()
|
body: serializer.getBytes()
|
||||||
};
|
};
|
||||||
@ -964,7 +964,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
var serializer = new TLSerialization({mtproto: true});
|
var serializer = new TLSerialization({mtproto: true});
|
||||||
serializer.storeMethod('http_wait', {max_delay: 0, wait_after: 0, max_wait: 1000});
|
serializer.storeMethod('http_wait', {max_delay: 0, wait_after: 0, max_wait: 1000});
|
||||||
messages.push({
|
messages.push({
|
||||||
msg_id: MtpDateManager.generateID(),
|
msg_id: MtpTimeManager.generateID(),
|
||||||
seq_no: this.generateSeqNo(),
|
seq_no: this.generateSeqNo(),
|
||||||
body: serializer.getBytes()
|
body: serializer.getBytes()
|
||||||
});
|
});
|
||||||
@ -995,7 +995,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
}
|
}
|
||||||
|
|
||||||
var containerSentMessage = {
|
var containerSentMessage = {
|
||||||
msg_id: MtpDateManager.generateID(),
|
msg_id: MtpTimeManager.generateID(),
|
||||||
seq_no: this.generateSeqNo(true),
|
seq_no: this.generateSeqNo(true),
|
||||||
container: true,
|
container: true,
|
||||||
inner: innerMessages
|
inner: innerMessages
|
||||||
@ -1345,7 +1345,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (message.error_code == 16 || message.error_code == 17) {
|
if (message.error_code == 16 || message.error_code == 17) {
|
||||||
if (MtpDateManager.applyServerTime(
|
if (MtpTimeManager.applyServerTime(
|
||||||
bigStringInt(messageID).shiftRight(32).toString(10)
|
bigStringInt(messageID).shiftRight(32).toString(10)
|
||||||
)) {
|
)) {
|
||||||
this.updateSession();
|
this.updateSession();
|
||||||
|
@ -673,7 +673,7 @@ angular.module('myApp.services', [])
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
.service('AppMessagesManager', function ($q, $rootScope, $location, $filter, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, AppAudioManager, MtpApiManager, MtpApiFileManager, RichTextProcessor, NotificationsManager, SearchIndexManager) {
|
.service('AppMessagesManager', function ($q, $rootScope, $location, $filter, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, AppAudioManager, MtpApiManager, MtpApiFileManager, MtpTimeManager, RichTextProcessor, NotificationsManager, SearchIndexManager) {
|
||||||
|
|
||||||
var messagesStorage = {};
|
var messagesStorage = {};
|
||||||
var messagesForHistory = {};
|
var messagesForHistory = {};
|
||||||
@ -692,6 +692,17 @@ angular.module('myApp.services', [])
|
|||||||
var lastSearchFilter = {},
|
var lastSearchFilter = {},
|
||||||
lastSearchResults = [];
|
lastSearchResults = [];
|
||||||
|
|
||||||
|
var serverTimeOffset = MtpTimeManager.getTimeOffset(),
|
||||||
|
timestampNow = tsNow(true),
|
||||||
|
midnightNoOffset = timestampNow - (timestampNow % 86400),
|
||||||
|
midnightOffseted = new Date(),
|
||||||
|
midnightOffset;
|
||||||
|
|
||||||
|
midnightOffseted.setHours(0);
|
||||||
|
midnightOffseted.setMinutes(0);
|
||||||
|
midnightOffseted.setSeconds(0);
|
||||||
|
midnightOffset = midnightNoOffset - (Math.floor(+midnightOffseted / 1000));
|
||||||
|
|
||||||
NotificationsManager.start();
|
NotificationsManager.start();
|
||||||
|
|
||||||
function getDialogs (query, maxID, limit) {
|
function getDialogs (query, maxID, limit) {
|
||||||
@ -1773,6 +1784,46 @@ angular.module('myApp.services', [])
|
|||||||
return messagesForHistory[msgID] = message;
|
return messagesForHistory[msgID] = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function regroupWrappedHistory (history, limit) {
|
||||||
|
var start = 0,
|
||||||
|
end = history.length,
|
||||||
|
i, curDay, prevDay, curMessage, prevMessage;
|
||||||
|
|
||||||
|
if (limit > 0) {
|
||||||
|
end = limit;
|
||||||
|
} else if (limit < 0) {
|
||||||
|
start = end + limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = start; i < end; i++) {
|
||||||
|
curMessage = history[i];
|
||||||
|
curDay = Math.floor((curMessage.date - midnightOffset) / 86400);
|
||||||
|
if (curDay !== prevDay) {
|
||||||
|
curMessage.needDate = true;
|
||||||
|
} else if (prevMessage) {
|
||||||
|
delete curMessage.needDate;
|
||||||
|
}
|
||||||
|
if (prevMessage &&
|
||||||
|
curMessage.from_id == prevMessage.from_id &&
|
||||||
|
!prevMessage.fwd_from_id == !curMessage.fwd_from_id &&
|
||||||
|
!prevMessage.action &&
|
||||||
|
!curMessage.action &&
|
||||||
|
curMessage.date < prevMessage.date + 900) {
|
||||||
|
|
||||||
|
var singleLine = curMessage.message && curMessage.message.length < 70 && curMessage.message.indexOf("\n") == -1;
|
||||||
|
if (curMessage.fwd_from_id && curMessage.fwd_from_id == prevMessage.fwd_from_id) {
|
||||||
|
curMessage.grouped = singleLine ? 4 : 3;
|
||||||
|
} else {
|
||||||
|
curMessage.grouped = !curMessage.fwd_from_id && singleLine ? 1 : 2;
|
||||||
|
}
|
||||||
|
} else if (prevMessage || !i) {
|
||||||
|
delete curMessage.grouped;
|
||||||
|
}
|
||||||
|
prevMessage = curMessage;
|
||||||
|
prevDay = curDay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getDialogByPeerID (peerID) {
|
function getDialogByPeerID (peerID) {
|
||||||
for (var i = 0; i < dialogsStorage.dialogs.length; i++) {
|
for (var i = 0; i < dialogsStorage.dialogs.length; i++) {
|
||||||
if (dialogsStorage.dialogs[i].peerID == peerID) {
|
if (dialogsStorage.dialogs[i].peerID == peerID) {
|
||||||
@ -1886,6 +1937,9 @@ angular.module('myApp.services', [])
|
|||||||
historyStorage = historiesStorage[peerID] = {count: null, history: [message.id], pending: []};
|
historyStorage = historiesStorage[peerID] = {count: null, history: [message.id], pending: []};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fix time offset
|
||||||
|
message.date -= serverTimeOffset;
|
||||||
|
|
||||||
saveMessages([message]);
|
saveMessages([message]);
|
||||||
|
|
||||||
if (historyStorage.count !== null) {
|
if (historyStorage.count !== null) {
|
||||||
@ -2054,7 +2108,8 @@ angular.module('myApp.services', [])
|
|||||||
forwardMessages: forwardMessages,
|
forwardMessages: forwardMessages,
|
||||||
getMessagePeer: getMessagePeer,
|
getMessagePeer: getMessagePeer,
|
||||||
wrapForDialog: wrapForDialog,
|
wrapForDialog: wrapForDialog,
|
||||||
wrapForHistory: wrapForHistory
|
wrapForHistory: wrapForHistory,
|
||||||
|
regroupWrappedHistory: regroupWrappedHistory
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
Unread messages
|
Unread messages
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="im_message_date_split im_service_message_wrap" bo-if="historyMessage.needDate" 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 && ('im_message_grouped' + historyMessage.grouped) , historyFocus == historyMessage.id && 'im_message_focus']" ng-click="toggleMessage(historyMessage.id, $event)">
|
<div class="im_message_outer_wrap" ng-class="[ selectedMsgs[historyMessage.id] && 'im_message_selected', historyMessage.grouped && ('im_message_grouped' + historyMessage.grouped) , historyFocus == historyMessage.id && 'im_message_focus']" ng-click="toggleMessage(historyMessage.id, $event)">
|
||||||
|
|
||||||
|
|
||||||
@ -77,7 +81,7 @@
|
|||||||
</a>
|
</a>
|
||||||
<div class="im_message_meta pull-right text-right">
|
<div class="im_message_meta pull-right text-right">
|
||||||
<i class="icon-message-status-tick"></i>
|
<i class="icon-message-status-tick"></i>
|
||||||
<span class="im_message_date" bo-bind="historyMessage.date | dateOrTime"></span>
|
<span class="im_message_date" ng-bind="historyMessage.date | time"></span><span class="im_message_date im_message_date_seconds">:<span ng-bind="historyMessage.date | seconds"></span></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="im_message_body">
|
<div class="im_message_body">
|
||||||
|
Loading…
Reference in New Issue
Block a user