Different improvements

This commit is contained in:
DrKLO 2014-10-23 00:01:07 +04:00
parent e3d2b9cece
commit e5def002f7
25 changed files with 1222 additions and 343 deletions

View file

@ -80,7 +80,7 @@ android {
defaultConfig {
minSdkVersion 8
targetSdkVersion 19
versionCode 363
versionCode 371
versionName "1.9.5"
}
}

View file

@ -425,7 +425,7 @@ public class AndroidUtilities {
final NumberPicker numberPicker = new NumberPicker(context);
numberPicker.setMinValue(0);
numberPicker.setMaxValue(20);
if (encryptedChat.ttl >= 0 && encryptedChat.ttl < 16) {
if (encryptedChat.ttl > 0 && encryptedChat.ttl < 16) {
numberPicker.setValue(encryptedChat.ttl);
} else if (encryptedChat.ttl == 30) {
numberPicker.setValue(16);
@ -437,6 +437,8 @@ public class AndroidUtilities {
numberPicker.setValue(19);
} else if (encryptedChat.ttl == 60 * 60 * 24 * 7) {
numberPicker.setValue(20);
} else if (encryptedChat.ttl == 0) {
numberPicker.setValue(5);
}
numberPicker.setFormatter(new NumberPicker.Formatter() {
@Override
@ -479,7 +481,7 @@ public class AndroidUtilities {
encryptedChat.ttl = 60 * 60 * 24 * 7;
}
if (oldValue != encryptedChat.ttl) {
SendMessagesHelper.getInstance().sendTTLMessage(encryptedChat);
SendMessagesHelper.getInstance().sendTTLMessage(encryptedChat, null);
MessagesStorage.getInstance().updateEncryptedChatTTL(encryptedChat);
}
}

View file

@ -791,7 +791,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
photoW = bmOptions.outWidth;
photoH = bmOptions.outHeight;
}
if (photoW == 0 || photoH == 0 || (photoW == width && photoH == height || photoH == width && photoW == height)) {
if (photoW <= 0 || photoH <= 0 || (photoW == width && photoH == height || photoH == width && photoW == height)) {
screenshotDates.add(date);
}
} catch (Exception e) {
@ -834,7 +834,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
}
}
if (send) {
SendMessagesHelper.getInstance().sendScreenshotMessage(lastSecretChat, lastSecretChatVisibleMessages);
SendMessagesHelper.getInstance().sendScreenshotMessage(lastSecretChat, lastSecretChatVisibleMessages, null);
}
}
@ -2200,6 +2200,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
File inputFile = new File(videoPath);
if (!inputFile.canRead()) {
didWriteData(messageObject, cacheFile, true, true);
return false;
}
@ -2577,6 +2578,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
FileLog.e("tmessages", "time = " + (System.currentTimeMillis() - time));
}
} else {
didWriteData(messageObject, cacheFile, true, true);
return false;
}
didWriteData(messageObject, cacheFile, true, error);

View file

@ -232,7 +232,7 @@ public class MessageObject {
} else {
messageText = LocaleController.formatString("NotificationContactNewPhoto", R.string.NotificationContactNewPhoto, "");
}
} else if (message.action instanceof TLRPC.TL_messageEcryptedAction) {
} else if (message.action instanceof TLRPC.TL_messageEncryptedAction) {
if (message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) {
if (isFromMe()) {
messageText = LocaleController.formatString("ActionTakeScreenshootYou", R.string.ActionTakeScreenshootYou);
@ -243,6 +243,29 @@ public class MessageObject {
messageText = LocaleController.formatString("ActionTakeScreenshoot", R.string.ActionTakeScreenshoot).replace("un1", "");
}
}
} else if (message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) {
TLRPC.TL_decryptedMessageActionSetMessageTTL action = (TLRPC.TL_decryptedMessageActionSetMessageTTL) message.action.encryptedAction;
if (action.ttl_seconds != 0) {
if (isFromMe()) {
messageText = LocaleController.formatString("MessageLifetimeChangedOutgoing", R.string.MessageLifetimeChangedOutgoing, AndroidUtilities.formatTTLString(action.ttl_seconds));
} else {
if (fromUser != null) {
messageText = LocaleController.formatString("MessageLifetimeChanged", R.string.MessageLifetimeChanged, fromUser.first_name, AndroidUtilities.formatTTLString(action.ttl_seconds));
} else {
messageText = LocaleController.formatString("MessageLifetimeChanged", R.string.MessageLifetimeChanged, "", AndroidUtilities.formatTTLString(action.ttl_seconds));
}
}
} else {
if (isFromMe()) {
messageText = LocaleController.getString("MessageLifetimeYouRemoved", R.string.MessageLifetimeYouRemoved);
} else {
if (fromUser != null) {
messageText = LocaleController.formatString("MessageLifetimeRemoved", R.string.MessageLifetimeRemoved, fromUser.first_name);
} else {
messageText = LocaleController.formatString("MessageLifetimeRemoved", R.string.MessageLifetimeRemoved, "");
}
}
}
}
} else if (message.action instanceof TLRPC.TL_messageActionCreatedBroadcastList) {
messageText = LocaleController.formatString("YouCreatedBroadcastList", R.string.YouCreatedBroadcastList);
@ -301,6 +324,14 @@ public class MessageObject {
} else if (message.action instanceof TLRPC.TL_messageActionChatEditPhoto || message.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) {
contentType = 4;
type = 11;
} else if (message.action instanceof TLRPC.TL_messageEncryptedAction) {
if (message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages || message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) {
contentType = 4;
type = 10;
} else {
contentType = -1;
type = -1;
}
} else {
contentType = 4;
type = 10;

View file

@ -980,7 +980,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesDeleted, messages);
if (randoms != null && encryptedChat != null && !randoms.isEmpty()) {
SendMessagesHelper.getInstance().sendMessagesDeleteMessage(randoms, encryptedChat);
SendMessagesHelper.getInstance().sendMessagesDeleteMessage(encryptedChat, randoms, null);
}
ArrayList<Integer> toSend = new ArrayList<Integer>();
@ -1071,7 +1071,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
});
} else {
if (onlyHistory) {
SendMessagesHelper.getInstance().sendClearHistoryMessage(getEncryptedChat(high_id));
SendMessagesHelper.getInstance().sendClearHistoryMessage(getEncryptedChat(high_id), null);
} else {
declineSecretChat(high_id);
}
@ -1643,6 +1643,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter
putChats(dialogsRes.chats, isCache);
if (encChats != null) {
for (TLRPC.EncryptedChat encryptedChat : encChats) {
if (encryptedChat instanceof TLRPC.TL_encryptedChat && AndroidUtilities.getMyLayerVersion(encryptedChat.layer) < SendMessagesHelper.CURRENT_SECRET_CHAT_LAYER) {
SendMessagesHelper.getInstance().sendNotifyLayerMessage(encryptedChat, null);
}
putEncryptedChat(encryptedChat, true);
}
}
@ -1707,7 +1710,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
});
}
public void markMessageAsRead(final long dialog_id, final long random_id) {
public void markMessageAsRead(final long dialog_id, final long random_id, int ttl) {
if (random_id == 0 || dialog_id == 0) {
return;
}
@ -1722,12 +1725,11 @@ public class MessagesController implements NotificationCenter.NotificationCenter
}
ArrayList<Long> random_ids = new ArrayList<Long>();
random_ids.add(random_id);
SendMessagesHelper.getInstance().sendMessagesReadMessage(random_ids, chat);
if (chat.ttl > 0) {
SendMessagesHelper.getInstance().sendMessagesReadMessage(chat, random_ids, null);
if (ttl > 0) {
int time = ConnectionsManager.getInstance().getCurrentTime();
MessagesStorage.getInstance().createTaskForSecretChat(chat.id, time, time, 0, random_ids);
}
//TODO resend request
}
public void markDialogAsRead(final long dialog_id, final int max_id, final int max_positive_id, final int offset, final int max_date, final boolean was, final boolean popup) {
@ -3558,7 +3560,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
public TLRPC.Message decryptMessage(TLRPC.EncryptedMessage message) {
final TLRPC.EncryptedChat chat = getEncryptedChatDB(message.chat_id);
if (chat == null) {
if (chat == null || chat instanceof TLRPC.TL_encryptedChatDiscarded) {
return null;
}
ByteBufferDesc is = BuffersStorage.getInstance().getFreeBuffer(message.bytes.length);
@ -3582,13 +3584,38 @@ public class MessagesController implements NotificationCenter.NotificationCenter
if (object instanceof TLRPC.TL_decryptedMessageLayer) {
final TLRPC.TL_decryptedMessageLayer layer = (TLRPC.TL_decryptedMessageLayer)object;
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
chat.seq_in = layer.out_seq_no;
MessagesStorage.getInstance().updateEncryptedChatSeq(chat);
if (chat.seq_in == 0 && chat.seq_out == 0) {
if (chat.admin_id == UserConfig.getClientUserId()) {
chat.seq_out = 1;
} else {
chat.seq_in = 1;
}
});
}
if (chat.seq_in != layer.out_seq_no && chat.seq_in != layer.out_seq_no - 2) {
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
final TLRPC.TL_encryptedChatDiscarded newChat = new TLRPC.TL_encryptedChatDiscarded();
newChat.id = chat.id;
newChat.user_id = chat.user_id;
newChat.auth_key = chat.auth_key;
newChat.seq_in = chat.seq_in;
newChat.seq_out = chat.seq_out;
MessagesStorage.getInstance().updateEncryptedChat(newChat);
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
putEncryptedChat(newChat, false);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, newChat);
}
});
declineSecretChat(chat.id);
}
});
return null;
}
chat.seq_in = layer.out_seq_no;
MessagesStorage.getInstance().updateEncryptedChatSeq(chat);
object = layer.message;
}
@ -3597,8 +3624,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter
TLRPC.TL_message newMessage = null;
if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 17) {
newMessage = new TLRPC.TL_message_secret();
newMessage.ttl = decryptedMessage.ttl;
} else {
newMessage = new TLRPC.TL_message();
newMessage.ttl = chat.ttl;
}
newMessage.message = decryptedMessage.message;
newMessage.date = message.date;
@ -3610,7 +3639,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter
newMessage.to_id.user_id = UserConfig.getClientUserId();
newMessage.flags = TLRPC.MESSAGE_FLAG_UNREAD;
newMessage.dialog_id = ((long)chat.id) << 32;
newMessage.ttl = chat.ttl;
if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaEmpty) {
newMessage.media = new TLRPC.TL_messageMediaEmpty();
} else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaContact) {
@ -3751,13 +3779,15 @@ public class MessagesController implements NotificationCenter.NotificationCenter
if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL || serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) {
TLRPC.TL_messageService newMessage = new TLRPC.TL_messageService();
if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) {
newMessage.action = new TLRPC.TL_messageActionTTLChange();
newMessage.action = new TLRPC.TL_messageEncryptedAction();
if (serviceMessage.action.ttl_seconds < 0 || serviceMessage.action.ttl_seconds > 60 * 60 * 24 * 365) {
serviceMessage.action.ttl_seconds = 60 * 60 * 24 * 365;
}
newMessage.action.ttl = chat.ttl = serviceMessage.action.ttl_seconds;
chat.ttl = serviceMessage.action.ttl_seconds;
newMessage.action.encryptedAction = serviceMessage.action;
MessagesStorage.getInstance().updateEncryptedChatTTL(chat);
} else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) {
newMessage.action = new TLRPC.TL_messageEcryptedAction();
newMessage.action = new TLRPC.TL_messageEncryptedAction();
newMessage.action.encryptedAction = serviceMessage.action;
}
newMessage.local_id = newMessage.id = UserConfig.getNewMessageId();
@ -3768,7 +3798,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter
newMessage.to_id = new TLRPC.TL_peerUser();
newMessage.to_id.user_id = UserConfig.getClientUserId();
newMessage.dialog_id = ((long)chat.id) << 32;
MessagesStorage.getInstance().updateEncryptedChatTTL(chat);
return newMessage;
} else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionFlushHistory) {
final long did = ((long)chat.id) << 32;
@ -3818,7 +3847,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
chat.layer = AndroidUtilities.setPeerLayerVersion(chat.layer, serviceMessage.action.layer);
MessagesStorage.getInstance().updateEncryptedChatLayer(chat);
if (currentPeerLayer < 17) {
SendMessagesHelper.getInstance().sendNotifyLayerMessage(chat);
SendMessagesHelper.getInstance().sendNotifyLayerMessage(chat, null);
}
}
});
@ -3878,7 +3907,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
public void run() {
putEncryptedChat(encryptedChat, false);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, encryptedChat);
SendMessagesHelper.getInstance().sendNotifyLayerMessage(encryptedChat);
SendMessagesHelper.getInstance().sendNotifyLayerMessage(encryptedChat, null);
}
});
} else {
@ -4003,7 +4032,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
public void run() {
putEncryptedChat(newChat, false);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, newChat);
SendMessagesHelper.getInstance().sendNotifyLayerMessage(newChat);
SendMessagesHelper.getInstance().sendNotifyLayerMessage(newChat, null);
}
});
}

View file

@ -110,6 +110,7 @@ public class MessagesStorage {
database.executeFast("CREATE TABLE download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, PRIMARY KEY (uid, type));").stepThis().dispose();
database.executeFast("CREATE TABLE dialog_settings(did INTEGER PRIMARY KEY, flags INTEGER);").stepThis().dispose();
database.executeFast("CREATE TABLE messages_seq(mid INTEGER PRIMARY KEY, seq_in INTEGER, seq_out INTEGER);").stepThis().dispose();
//database.executeFast("CREATE TABLE attach_data(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose();
database.executeFast("CREATE TABLE user_contacts_v6(uid INTEGER PRIMARY KEY, fname TEXT, sname TEXT)").stepThis().dispose();
@ -137,6 +138,9 @@ public class MessagesStorage {
database.executeFast("CREATE INDEX IF NOT EXISTS mid_out_idx_messages ON messages(mid, out);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS task_idx_messages ON messages(uid, out, read_state, ttl, date, send_state);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_messages ON messages(mid, send_state, date) WHERE mid < 0 AND send_state = 1;").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS seq_idx_messages_seq ON messages_seq(seq_in, seq_out);").stepThis().dispose();
database.executeFast("PRAGMA user_version = 7").stepThis().dispose();
} else {
try {
@ -292,6 +296,7 @@ public class MessagesStorage {
}
if (version == 6 && version < 7) {
database.executeFast("CREATE TABLE IF NOT EXISTS messages_seq(mid INTEGER PRIMARY KEY, seq_in INTEGER, seq_out INTEGER);").stepThis().dispose();
database.executeFast("CREATE INDEX IF NOT EXISTS seq_idx_messages_seq ON messages_seq(seq_in, seq_out);").stepThis().dispose();
database.executeFast("ALTER TABLE enc_chats ADD COLUMN layer INTEGER default 0").stepThis().dispose();
database.executeFast("ALTER TABLE enc_chats ADD COLUMN seq_in INTEGER default 0").stepThis().dispose();
database.executeFast("ALTER TABLE enc_chats ADD COLUMN seq_out INTEGER default 0").stepThis().dispose();
@ -1559,9 +1564,9 @@ public class MessagesStorage {
}
} else {
if (max_id != 0) {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid FROM media WHERE uid = %d AND mid > %d ORDER BY mid ASC LIMIT %d", uid, max_id, count));
cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.data, m.mid, r.random_id FROM media as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid > %d ORDER BY m.mid ASC LIMIT %d", uid, max_id, count));
} else {
cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid FROM media WHERE uid = %d ORDER BY mid ASC LIMIT %d,%d", uid, offset, count));
cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.data, m.mid, r.random_id FROM media as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d ORDER BY m.mid ASC LIMIT %d,%d", uid, offset, count));
}
}
@ -1571,6 +1576,9 @@ public class MessagesStorage {
TLRPC.Message message = (TLRPC.Message)TLClassStore.Instance().TLdeserialize(data, data.readInt32());
message.id = cursor.intValue(1);
message.dialog_id = uid;
if ((int)uid == 0) {
message.random_id = cursor.longValue(2);
}
res.messages.add(message);
fromUser.add(message.from_id);
}
@ -1659,7 +1667,7 @@ public class MessagesStorage {
ArrayList<Integer> chatIds = new ArrayList<Integer>();
ArrayList<Integer> broadcastIds = new ArrayList<Integer>();
ArrayList<Integer> encryptedChatIds = new ArrayList<Integer>();
SQLiteCursor cursor = database.queryFinalized("SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.uid FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.mid < 0 AND m.send_state = 1 ORDER BY m.mid DESC LIMIT " + count);
SQLiteCursor cursor = database.queryFinalized("SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.uid, s.seq_in, s.seq_out FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid LEFT JOIN messages_seq as s ON m.mid = s.mid WHERE m.mid < 0 AND m.send_state = 1 ORDER BY m.mid DESC LIMIT " + count);
while (cursor.next()) {
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(1));
if (data != null && cursor.byteBufferValue(1, data.buffer) != 0) {
@ -1671,6 +1679,8 @@ public class MessagesStorage {
message.random_id = cursor.longValue(5);
}
message.dialog_id = cursor.longValue(6);
message.seq_in = cursor.intValue(7);
message.seq_out = cursor.intValue(8);
messages.add(message);
int lower_id = (int)message.dialog_id;
@ -2629,10 +2639,19 @@ public class MessagesStorage {
ByteBufferDesc data = buffersStorage.getFreeBuffer(message.getObjectSize());
message.serializeToStream(data);
TLRPC.Message lastMessage = messagesMap.get(dialog_id);
if (lastMessage == null || message.date > lastMessage.date) {
messagesMap.put(dialog_id, message);
boolean updateDialog = true;
if (message.action != null && message.action instanceof TLRPC.TL_messageEncryptedAction && !(message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL || message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages)) {
updateDialog = false;
}
if (updateDialog) {
TLRPC.Message lastMessage = messagesMap.get(dialog_id);
if (lastMessage == null || message.date > lastMessage.date) {
messagesMap.put(dialog_id, message);
}
}
state.bindInteger(1, messageId);
state.bindLong(2, dialog_id);
state.bindInteger(3, (MessageObject.isUnread(message) ? 0 : 1));
@ -2820,6 +2839,25 @@ public class MessagesStorage {
});
}
public void setMessageSeq(final int mid, final int seq_in, final int seq_out) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages_seq VALUES(?, ?, ?)");
state.requery();
state.bindInteger(1, mid);
state.bindInteger(2, seq_in);
state.bindInteger(3, seq_out);
state.step();
state.dispose();
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
});
}
private Integer updateMessageStateAndIdInternal(long random_id, Integer _oldId, int newId, int date) {
if (_oldId != null && _oldId == newId && date != 0) {
SQLitePreparedStatement state = null;
@ -2835,6 +2873,7 @@ public class MessagesStorage {
state.dispose();
}
}
return newId;
} else {
Integer oldId = _oldId;
@ -2875,6 +2914,7 @@ public class MessagesStorage {
} finally {
if (state != null) {
state.dispose();
state = null;
}
}
@ -2888,6 +2928,7 @@ public class MessagesStorage {
} finally {
if (state != null) {
state.dispose();
state = null;
}
}
@ -2901,6 +2942,7 @@ public class MessagesStorage {
} finally {
if (state != null) {
state.dispose();
state = null;
}
}
@ -3113,10 +3155,63 @@ public class MessagesStorage {
}
try {
String ids = TextUtils.join(",", messages);
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT uid, data FROM messages WHERE mid IN(%s)", ids));
ArrayList<File> filesToDelete = new ArrayList<File>();
try {
while (cursor.next()) {
long did = cursor.longValue(0);
if ((int)did != 0) {
continue;
}
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(1));
if (data != null && cursor.byteBufferValue(1, data.buffer) != 0) {
TLRPC.Message message = (TLRPC.Message)TLClassStore.Instance().TLdeserialize(data, data.readInt32());
if (message == null || message.media == null) {
continue;
}
if (message.media instanceof TLRPC.TL_messageMediaAudio) {
File file = FileLoader.getPathToAttach(message.media.audio);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
} else if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) {
File file = FileLoader.getPathToAttach(photoSize);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
}
} else if (message.media instanceof TLRPC.TL_messageMediaVideo) {
File file = FileLoader.getPathToAttach(message.media.video);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
file = FileLoader.getPathToAttach(message.media.video.thumb);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
} else if (message.media instanceof TLRPC.TL_messageMediaDocument) {
File file = FileLoader.getPathToAttach(message.media.document);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
file = FileLoader.getPathToAttach(message.media.document.thumb);
if (file != null && file.toString().length() > 0) {
filesToDelete.add(file);
}
}
}
buffersStorage.reuseFreeBuffer(data);
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
cursor.dispose();
FileLoader.getInstance().deleteFiles(filesToDelete);
database.executeFast(String.format(Locale.US, "DELETE FROM messages WHERE mid IN(%s)", ids)).stepThis().dispose();
database.executeFast(String.format(Locale.US, "DELETE FROM messages_seq WHERE mid IN(%s)", ids)).stepThis().dispose();
database.executeFast(String.format(Locale.US, "DELETE FROM media WHERE mid IN(%s)", ids)).stepThis().dispose();
database.executeFast("DELETE FROM media_counts WHERE 1").stepThis().dispose();
} catch (Exception e) {
FileLog.e("tmessages", e);
}

View file

@ -113,18 +113,18 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
if (file != null && media != null) {
if (message.type == 0) {
media.file = file;
performSendMessageRequest(message.sendRequest, message.obj, message.originalPath);
performSendMessageRequest(message.sendRequest, message.obj.messageOwner, message.originalPath);
} else if (message.type == 1) {
if (media.file == null) {
media.file = file;
if (media.thumb == null && message.location != null) {
performSendDelayedMessage(message);
} else {
performSendMessageRequest(message.sendRequest, message.obj, message.originalPath);
performSendMessageRequest(message.sendRequest, message.obj.messageOwner, message.originalPath);
}
} else {
media.thumb = file;
performSendMessageRequest(message.sendRequest, message.obj, message.originalPath);
performSendMessageRequest(message.sendRequest, message.obj.messageOwner, message.originalPath);
}
} else if (message.type == 2) {
if (media.file == null) {
@ -132,22 +132,22 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
if (media.thumb == null && message.location != null) {
performSendDelayedMessage(message);
} else {
performSendMessageRequest(message.sendRequest, message.obj, message.originalPath);
performSendMessageRequest(message.sendRequest, message.obj.messageOwner, message.originalPath);
}
} else {
media.thumb = file;
performSendMessageRequest(message.sendRequest, message.obj, message.originalPath);
performSendMessageRequest(message.sendRequest, message.obj.messageOwner, message.originalPath);
}
} else if (message.type == 3) {
media.file = file;
performSendMessageRequest(message.sendRequest, message.obj, message.originalPath);
performSendMessageRequest(message.sendRequest, message.obj.messageOwner, message.originalPath);
}
arr.remove(a);
a--;
} else if (encryptedFile != null && message.sendEncryptedRequest != null) {
message.sendEncryptedRequest.media.key = encryptedFile.key;
message.sendEncryptedRequest.media.iv = encryptedFile.iv;
performSendEncryptedRequest(message.sendEncryptedRequest, message.obj, message.encryptedChat, encryptedFile, message.originalPath, null);
performSendEncryptedRequest(message.sendEncryptedRequest, message.obj.messageOwner, message.encryptedChat, encryptedFile, message.originalPath);
arr.remove(a);
a--;
}
@ -288,6 +288,35 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
if (messageObject.messageOwner.id >= 0) {
return false;
}
if (messageObject.messageOwner.action instanceof TLRPC.TL_messageEncryptedAction) {
int enc_id = (int) (messageObject.getDialogId() >> 32);
TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance().getEncryptedChat(enc_id);
if (encryptedChat == null) {
MessagesStorage.getInstance().markMessageAsSendError(messageObject.messageOwner.id);
messageObject.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR;
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, messageObject.messageOwner.id);
processSentMessage(messageObject.messageOwner.id);
return false;
}
if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) {
sendTTLMessage(encryptedChat, messageObject.messageOwner);
} else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionDeleteMessages) {
sendMessagesDeleteMessage(encryptedChat, null, messageObject.messageOwner);
} else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionFlushHistory) {
sendClearHistoryMessage(encryptedChat, messageObject.messageOwner);
} else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) {
sendNotifyLayerMessage(encryptedChat, messageObject.messageOwner);
} else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionReadMessages) {
sendMessagesReadMessage(encryptedChat, null, messageObject.messageOwner);
} else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) {
sendScreenshotMessage(encryptedChat, null, messageObject.messageOwner);
} else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionTyping) {
} else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionResend) {
}
return true;
}
if (unsent) {
unsentMessages.put(messageObject.messageOwner.id, messageObject);
}
@ -623,13 +652,13 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
reqSend.message = message;
reqSend.contacts = sendToPeers;
reqSend.media = new TLRPC.TL_inputMediaEmpty();
performSendMessageRequest(reqSend, newMsgObj, null);
performSendMessageRequest(reqSend, newMsgObj.messageOwner, null);
} else {
TLRPC.TL_messages_sendMessage reqSend = new TLRPC.TL_messages_sendMessage();
reqSend.message = message;
reqSend.peer = sendToPeer;
reqSend.random_id = newMsg.random_id;
performSendMessageRequest(reqSend, newMsgObj, null);
performSendMessageRequest(reqSend, newMsgObj.messageOwner, null);
}
} else {
TLRPC.TL_decryptedMessage reqSend;
@ -644,7 +673,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
reqSend.random_id = newMsg.random_id;
reqSend.message = message;
reqSend.media = new TLRPC.TL_decryptedMessageMediaEmpty();
performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null, null);
performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, null, null);
}
} else if (type >= 1 && type <= 3 || type >= 5 && type <= 8) {
if (encryptedChat == null) {
@ -761,32 +790,32 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
reqSend = request;
}
if (type == 1) {
performSendMessageRequest(reqSend, newMsgObj, null);
performSendMessageRequest(reqSend, newMsgObj.messageOwner, null);
} else if (type == 2) {
if (photo.access_hash == 0) {
performSendDelayedMessage(delayedMessage);
} else {
performSendMessageRequest(reqSend, newMsgObj, null);
performSendMessageRequest(reqSend, newMsgObj.messageOwner, null);
}
} else if (type == 3) {
if (video.access_hash == 0) {
performSendDelayedMessage(delayedMessage);
} else {
performSendMessageRequest(reqSend, newMsgObj, null);
performSendMessageRequest(reqSend, newMsgObj.messageOwner, null);
}
} else if (type == 6) {
performSendMessageRequest(reqSend, newMsgObj, null);
performSendMessageRequest(reqSend, newMsgObj.messageOwner, null);
} else if (type == 7) {
if (document.access_hash == 0) {
performSendDelayedMessage(delayedMessage);
} else {
performSendMessageRequest(reqSend, newMsgObj, null);
performSendMessageRequest(reqSend, newMsgObj.messageOwner, null);
}
} else if (type == 8) {
if (audio.access_hash == 0) {
performSendDelayedMessage(delayedMessage);
} else {
performSendMessageRequest(reqSend, newMsgObj, null);
performSendMessageRequest(reqSend, newMsgObj.messageOwner, null);
}
}
} else {
@ -805,7 +834,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
reqSend.media = new TLRPC.TL_decryptedMessageMediaGeoPoint();
reqSend.media.lat = lat;
reqSend.media._long = lon;
performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null, null);
performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, null, null);
} else if (type == 2) {
TLRPC.PhotoSize small = photo.sizes.get(0);
TLRPC.PhotoSize big = photo.sizes.get(photo.sizes.size() - 1);
@ -831,7 +860,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
encryptedFile.access_hash = big.location.secret;
reqSend.media.key = big.location.key;
reqSend.media.iv = big.location.iv;
performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, encryptedFile, null, null);
performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, encryptedFile, null);
}
} else if (type == 3) {
if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) {
@ -862,7 +891,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
encryptedFile.access_hash = video.access_hash;
reqSend.media.key = video.key;
reqSend.media.iv = video.iv;
performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, encryptedFile, null, null);
performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, encryptedFile, null);
}
} else if (type == 6) {
reqSend.media = new TLRPC.TL_decryptedMessageMediaContact();
@ -870,7 +899,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
reqSend.media.first_name = user.first_name;
reqSend.media.last_name = user.last_name;
reqSend.media.user_id = user.id;
performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null, null);
performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, null, null);
} else if (type == 7) {
reqSend.media = new TLRPC.TL_decryptedMessageMediaDocument();
reqSend.media.size = document.size;
@ -900,7 +929,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
encryptedFile.access_hash = document.access_hash;
reqSend.media.key = document.key;
reqSend.media.iv = document.iv;
performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, encryptedFile, null, null);
performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, encryptedFile, null);
}
} else if (type == 8) {
if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) {
@ -930,7 +959,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
} else {
reqSend.id = msgObj.messageOwner.fwd_msg_id;
}
performSendMessageRequest(reqSend, newMsgObj, null);
performSendMessageRequest(reqSend, newMsgObj.messageOwner, null);
}
} catch (Exception e) {
FileLog.e("tmessages", e);
@ -1046,26 +1075,26 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
});
}
private void performSendMessageRequest(final TLObject req, final MessageObject newMsgObj, final String originalPath) {
private void performSendMessageRequest(final TLObject req, final TLRPC.Message newMsgObj, final String originalPath) {
ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
if (error == null) {
final int oldId = newMsgObj.messageOwner.id;
final int oldId = newMsgObj.id;
final boolean isBroadcast = req instanceof TLRPC.TL_messages_sendBroadcast;
final ArrayList<TLRPC.Message> sentMessages = new ArrayList<TLRPC.Message>();
final String attachPath = newMsgObj.messageOwner.attachPath;
final String attachPath = newMsgObj.attachPath;
if (response instanceof TLRPC.messages_SentMessage) {
TLRPC.messages_SentMessage res = (TLRPC.messages_SentMessage) response;
newMsgObj.messageOwner.id = res.id;
newMsgObj.messageOwner.date = res.date;
newMsgObj.id = res.id;
newMsgObj.date = res.date;
MessagesController.getInstance().processNewDifferenceParams(res.seq, res.pts, res.date);
} else if (response instanceof TLRPC.messages_StatedMessage) {
TLRPC.messages_StatedMessage res = (TLRPC.messages_StatedMessage) response;
sentMessages.add(res.message);
newMsgObj.messageOwner.id = res.message.id;
processSentMessage(newMsgObj.messageOwner, res.message, null, null, originalPath);
newMsgObj.id = res.message.id;
processSentMessage(newMsgObj, res.message, null, null, originalPath);
MessagesController.getInstance().processNewDifferenceParams(res.seq, res.pts, res.message.date);
} else if (response instanceof TLRPC.messages_StatedMessages) {
TLRPC.messages_StatedMessages res = (TLRPC.messages_StatedMessages) response;
@ -1073,27 +1102,27 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
sentMessages.addAll(res.messages);
TLRPC.Message message = res.messages.get(0);
if (!isBroadcast) {
newMsgObj.messageOwner.id = message.id;
newMsgObj.id = message.id;
}
processSentMessage(newMsgObj.messageOwner, message, null, null, originalPath);
processSentMessage(newMsgObj, message, null, null, originalPath);
}
MessagesController.getInstance().processNewDifferenceParams(res.seq, res.pts, -1);
}
MessagesStorage.getInstance().storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
MessagesStorage.getInstance().updateMessageStateAndId(newMsgObj.messageOwner.random_id, oldId, (isBroadcast ? oldId : newMsgObj.messageOwner.id), 0, false);
MessagesStorage.getInstance().updateMessageStateAndId(newMsgObj.random_id, oldId, (isBroadcast ? oldId : newMsgObj.id), 0, false);
MessagesStorage.getInstance().putMessages(sentMessages, true, false, isBroadcast, 0);
if (isBroadcast) {
ArrayList<TLRPC.Message> currentMessage = new ArrayList<TLRPC.Message>();
currentMessage.add(newMsgObj.messageOwner);
newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENT;
currentMessage.add(newMsgObj);
newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT;
MessagesStorage.getInstance().putMessages(currentMessage, true, false, false, 0);
}
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENT;
newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT;
if (isBroadcast) {
for (TLRPC.Message message : sentMessages) {
ArrayList<MessageObject> arr = new ArrayList<MessageObject>();
@ -1103,25 +1132,25 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
}
NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload);
}
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, oldId, (isBroadcast ? oldId : newMsgObj.messageOwner.id), newMsgObj);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, oldId, (isBroadcast ? oldId : newMsgObj.id), newMsgObj);
processSentMessage(oldId);
}
});
if (newMsgObj.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) {
if (newMsgObj.media instanceof TLRPC.TL_messageMediaVideo) {
stopVideoService(attachPath);
}
}
});
} else {
MessagesStorage.getInstance().markMessageAsSendError(newMsgObj.messageOwner.id);
MessagesStorage.getInstance().markMessageAsSendError(newMsgObj.id);
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR;
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, newMsgObj.messageOwner.id);
processSentMessage(newMsgObj.messageOwner.id);
if (newMsgObj.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) {
stopVideoService(newMsgObj.messageOwner.attachPath);
newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR;
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, newMsgObj.id);
processSentMessage(newMsgObj.id);
if (newMsgObj.media instanceof TLRPC.TL_messageMediaVideo) {
stopVideoService(newMsgObj.attachPath);
}
}
});
@ -1130,11 +1159,11 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
}, (req instanceof TLRPC.TL_messages_forwardMessages ? null : new RPCRequest.RPCQuickAckDelegate() {
@Override
public void quickAck() {
final int msg_id = newMsgObj.messageOwner.id;
final int msg_id = newMsgObj.id;
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENT;
newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT;
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByAck, msg_id);
}
});
@ -1142,7 +1171,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
}), true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassCanCompress, ConnectionsManager.DEFAULT_DATACENTER_ID);
}
private void performSendEncryptedRequest(final TLRPC.DecryptedMessage req, final MessageObject newMsgObj, final TLRPC.EncryptedChat chat, final TLRPC.InputEncryptedFile encryptedFile, final String originalPath, final Runnable callback) {
private void performSendEncryptedRequest(final TLRPC.DecryptedMessage req, final TLRPC.Message newMsgObj, final TLRPC.EncryptedChat chat, final TLRPC.InputEncryptedFile encryptedFile, final String originalPath) {
if (req == null || chat.auth_key == null || chat instanceof TLRPC.TL_encryptedChatRequested || chat instanceof TLRPC.TL_encryptedChatWaiting) {
return;
}
@ -1150,15 +1179,33 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 17) {
TLRPC.TL_decryptedMessageLayer layer = new TLRPC.TL_decryptedMessageLayer();
layer.layer = CURRENT_SECRET_CHAT_LAYER;
layer.in_seq_no = chat.seq_in;
layer.out_seq_no = chat.seq_out;
layer.message = req;
layer.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))];
Utilities.random.nextBytes(layer.random_bytes);
toEncryptObject = layer;
chat.seq_out += 2;
MessagesStorage.getInstance().updateEncryptedChatSeq(chat);
if (chat.seq_in == 0 && chat.seq_out == 0) {
if (chat.admin_id == UserConfig.getClientUserId()) {
chat.seq_out = 1;
} else {
chat.seq_in = 1;
}
}
if (newMsgObj.seq_in == 0 && newMsgObj.seq_out == 0) {
layer.in_seq_no = chat.seq_in;
layer.out_seq_no = chat.seq_out;
chat.seq_out += 2;
MessagesStorage.getInstance().updateEncryptedChatSeq(chat);
if (newMsgObj != null) {
newMsgObj.seq_in = layer.in_seq_no;
newMsgObj.seq_out = layer.out_seq_no;
MessagesStorage.getInstance().setMessageSeq(newMsgObj.id, newMsgObj.seq_in, newMsgObj.seq_out);
}
} else {
layer.in_seq_no = newMsgObj.seq_in;
layer.out_seq_no = newMsgObj.seq_out;
}
} else {
toEncryptObject = req;
}
@ -1199,13 +1246,23 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
TLObject reqToSend = null;
if (encryptedFile == null) {
TLRPC.TL_messages_sendEncrypted req2 = new TLRPC.TL_messages_sendEncrypted();
req2.data = data;
req2.random_id = req.random_id;
req2.peer = new TLRPC.TL_inputEncryptedChat();
req2.peer.chat_id = chat.id;
req2.peer.access_hash = chat.access_hash;
reqToSend = req2;
if (req instanceof TLRPC.TL_decryptedMessageService) {
TLRPC.TL_messages_sendEncryptedService req2 = new TLRPC.TL_messages_sendEncryptedService();
req2.data = data;
req2.random_id = req.random_id;
req2.peer = new TLRPC.TL_inputEncryptedChat();
req2.peer.chat_id = chat.id;
req2.peer.access_hash = chat.access_hash;
reqToSend = req2;
} else {
TLRPC.TL_messages_sendEncrypted req2 = new TLRPC.TL_messages_sendEncrypted();
req2.data = data;
req2.random_id = req.random_id;
req2.peer = new TLRPC.TL_inputEncryptedChat();
req2.peer.chat_id = chat.id;
req2.peer.access_hash = chat.access_hash;
reqToSend = req2;
}
} else {
TLRPC.TL_messages_sendEncryptedFile req2 = new TLRPC.TL_messages_sendEncryptedFile();
req2.data = data;
@ -1219,28 +1276,47 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
ConnectionsManager.getInstance().performRpc(reqToSend, new RPCRequest.RPCRequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
if (error == null && callback != null) {
callback.run();
if (error == null) {
if (req.action instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) {
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
TLRPC.EncryptedChat currentChat = MessagesController.getInstance().getEncryptedChat(chat.id);
sendingNotifyLayer.remove((Integer)currentChat.id);
currentChat.layer = AndroidUtilities.setMyLayerVersion(currentChat.layer, CURRENT_SECRET_CHAT_LAYER);
MessagesStorage.getInstance().updateEncryptedChatLayer(currentChat);
}
});
}
}
if (newMsgObj != null) {
if (error == null) {
final String attachPath = newMsgObj.messageOwner.attachPath;
final String attachPath = newMsgObj.attachPath;
final TLRPC.messages_SentEncryptedMessage res = (TLRPC.messages_SentEncryptedMessage) response;
newMsgObj.messageOwner.date = res.date;
if (newMsgObj.action instanceof TLRPC.TL_messageEncryptedAction) {
if (newMsgObj.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages || newMsgObj.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) {
newMsgObj.date = res.date;
}
}
if (res.file instanceof TLRPC.TL_encryptedFile) {
processSentMessage(newMsgObj.messageOwner, null, res.file, req, originalPath);
processSentMessage(newMsgObj, null, res.file, req, originalPath);
}
MessagesStorage.getInstance().storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
MessagesStorage.getInstance().updateMessageStateAndId(newMsgObj.messageOwner.random_id, newMsgObj.messageOwner.id, newMsgObj.messageOwner.id, res.date, false);
if (newMsgObj.action instanceof TLRPC.TL_messageEncryptedAction) {
if (!(newMsgObj.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages || newMsgObj.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL)) {
res.date = 0;
}
}
MessagesStorage.getInstance().updateMessageStateAndId(newMsgObj.random_id, newMsgObj.id, newMsgObj.id, res.date, false);
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENT;
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, newMsgObj.messageOwner.id, newMsgObj.messageOwner.id, newMsgObj);
processSentMessage(newMsgObj.messageOwner.id);
if (newMsgObj.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) {
newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT;
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, newMsgObj.id, newMsgObj.id, newMsgObj);
processSentMessage(newMsgObj.id);
if (newMsgObj.media instanceof TLRPC.TL_messageMediaVideo) {
stopVideoService(attachPath);
}
}
@ -1248,15 +1324,15 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
}
});
} else {
MessagesStorage.getInstance().markMessageAsSendError(newMsgObj.messageOwner.id);
MessagesStorage.getInstance().markMessageAsSendError(newMsgObj.id);
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR;
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, newMsgObj.messageOwner.id);
processSentMessage(newMsgObj.messageOwner.id);
if (newMsgObj.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) {
stopVideoService(newMsgObj.messageOwner.attachPath);
newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR;
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, newMsgObj.id);
processSentMessage(newMsgObj.id);
if (newMsgObj.media instanceof TLRPC.TL_messageMediaVideo) {
stopVideoService(newMsgObj.attachPath);
}
}
});
@ -1492,7 +1568,38 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
}
}
public void sendMessagesReadMessage(ArrayList<Long> random_ids, TLRPC.EncryptedChat encryptedChat) {
private TLRPC.TL_messageService createServiceSecretMessage(final TLRPC.EncryptedChat encryptedChat, TLRPC.DecryptedMessageAction decryptedMessage) {
TLRPC.TL_messageService newMsg = new TLRPC.TL_messageService();
newMsg.action = new TLRPC.TL_messageEncryptedAction();
newMsg.action.encryptedAction = decryptedMessage;
newMsg.local_id = newMsg.id = UserConfig.getNewMessageId();
newMsg.from_id = UserConfig.getClientUserId();
newMsg.flags = TLRPC.MESSAGE_FLAG_UNREAD | TLRPC.MESSAGE_FLAG_OUT;
newMsg.dialog_id = ((long)encryptedChat.id) << 32;
newMsg.to_id = new TLRPC.TL_peerUser();
newMsg.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING;
if (encryptedChat.participant_id == UserConfig.getClientUserId()) {
newMsg.to_id.user_id = encryptedChat.admin_id;
} else {
newMsg.to_id.user_id = encryptedChat.participant_id;
}
if (decryptedMessage instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages || decryptedMessage instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) {
newMsg.date = ConnectionsManager.getInstance().getCurrentTime();
} else {
newMsg.date = 0;
}
newMsg.random_id = getNextRandomId();
UserConfig.saveConfig(false);
ArrayList<TLRPC.Message> arr = new ArrayList<TLRPC.Message>();
arr.add(newMsg);
MessagesStorage.getInstance().putMessages(arr, false, true, true, 0);
return newMsg;
}
public void sendMessagesReadMessage(TLRPC.EncryptedChat encryptedChat, ArrayList<Long> random_ids, TLRPC.Message resendMessage) {
if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) {
return;
}
@ -1504,13 +1611,23 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))];
Utilities.random.nextBytes(reqSend.random_bytes);
}
reqSend.random_id = getNextRandomId();
reqSend.action = new TLRPC.TL_decryptedMessageActionReadMessages();
reqSend.action.random_ids = random_ids;
performSendEncryptedRequest(reqSend, null, encryptedChat, null, null, null);
TLRPC.Message message = null;
if (resendMessage != null) {
message = resendMessage;
reqSend.action = message.action.encryptedAction;
} else {
reqSend.action = new TLRPC.TL_decryptedMessageActionReadMessages();
reqSend.action.random_ids = random_ids;
message = createServiceSecretMessage(encryptedChat, reqSend.action);
}
reqSend.random_id = message.random_id;
performSendEncryptedRequest(reqSend, message, encryptedChat, null, null);
}
public void sendMessagesDeleteMessage(ArrayList<Long> random_ids, TLRPC.EncryptedChat encryptedChat) {
public void sendMessagesDeleteMessage(TLRPC.EncryptedChat encryptedChat, ArrayList<Long> random_ids, TLRPC.Message resendMessage) {
if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) {
return;
}
@ -1522,13 +1639,23 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))];
Utilities.random.nextBytes(reqSend.random_bytes);
}
reqSend.random_id = getNextRandomId();
reqSend.action = new TLRPC.TL_decryptedMessageActionDeleteMessages();
reqSend.action.random_ids = random_ids;
performSendEncryptedRequest(reqSend, null, encryptedChat, null, null, null);
TLRPC.Message message = null;
if (resendMessage != null) {
message = resendMessage;
reqSend.action = message.action.encryptedAction;
} else {
reqSend.action = new TLRPC.TL_decryptedMessageActionDeleteMessages();
reqSend.action.random_ids = random_ids;
message = createServiceSecretMessage(encryptedChat, reqSend.action);
}
reqSend.random_id = message.random_id;
performSendEncryptedRequest(reqSend, message, encryptedChat, null, null);
}
public void sendClearHistoryMessage(TLRPC.EncryptedChat encryptedChat) {
public void sendClearHistoryMessage(TLRPC.EncryptedChat encryptedChat, TLRPC.Message resendMessage) {
if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) {
return;
}
@ -1540,12 +1667,22 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))];
Utilities.random.nextBytes(reqSend.random_bytes);
}
reqSend.random_id = getNextRandomId();
reqSend.action = new TLRPC.TL_decryptedMessageActionFlushHistory();
performSendEncryptedRequest(reqSend, null, encryptedChat, null, null, null);
TLRPC.Message message = null;
if (resendMessage != null) {
message = resendMessage;
reqSend.action = message.action.encryptedAction;
} else {
reqSend.action = new TLRPC.TL_decryptedMessageActionFlushHistory();
message = createServiceSecretMessage(encryptedChat, reqSend.action);
}
reqSend.random_id = message.random_id;
performSendEncryptedRequest(reqSend, message, encryptedChat, null, null);
}
public void sendNotifyLayerMessage(final TLRPC.EncryptedChat encryptedChat) {
public void sendNotifyLayerMessage(final TLRPC.EncryptedChat encryptedChat, TLRPC.Message resendMessage) {
if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) {
return;
}
@ -1561,57 +1698,26 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))];
Utilities.random.nextBytes(reqSend.random_bytes);
}
reqSend.random_id = getNextRandomId();
reqSend.action = new TLRPC.TL_decryptedMessageActionNotifyLayer();
reqSend.action.layer = CURRENT_SECRET_CHAT_LAYER;
Runnable callback = new Runnable() {
@Override
public void run() {
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
TLRPC.EncryptedChat chat = MessagesController.getInstance().getEncryptedChat(encryptedChat.id);
sendingNotifyLayer.remove((Integer)chat.id);
chat.layer = AndroidUtilities.setMyLayerVersion(chat.layer, CURRENT_SECRET_CHAT_LAYER);
MessagesStorage.getInstance().updateEncryptedChatLayer(chat);
}
});
}
};
performSendEncryptedRequest(reqSend, null, encryptedChat, null, null, callback);
TLRPC.Message message = null;
if (resendMessage != null) {
message = resendMessage;
reqSend.action = message.action.encryptedAction;
} else {
reqSend.action = new TLRPC.TL_decryptedMessageActionNotifyLayer();
reqSend.action.layer = CURRENT_SECRET_CHAT_LAYER;
message = createServiceSecretMessage(encryptedChat, reqSend.action);
}
reqSend.random_id = message.random_id;
performSendEncryptedRequest(reqSend, message, encryptedChat, null, null);
}
public void sendTTLMessage(TLRPC.EncryptedChat encryptedChat) {
public void sendTTLMessage(TLRPC.EncryptedChat encryptedChat, TLRPC.Message resendMessage) {
if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) {
return;
}
TLRPC.TL_messageService newMsg = new TLRPC.TL_messageService();
newMsg.action = new TLRPC.TL_messageActionTTLChange();
newMsg.action.ttl = encryptedChat.ttl;
newMsg.local_id = newMsg.id = UserConfig.getNewMessageId();
newMsg.from_id = UserConfig.getClientUserId();
newMsg.flags = TLRPC.MESSAGE_FLAG_UNREAD | TLRPC.MESSAGE_FLAG_OUT;
newMsg.dialog_id = ((long)encryptedChat.id) << 32;
newMsg.to_id = new TLRPC.TL_peerUser();
if (encryptedChat.participant_id == UserConfig.getClientUserId()) {
newMsg.to_id.user_id = encryptedChat.admin_id;
} else {
newMsg.to_id.user_id = encryptedChat.participant_id;
}
newMsg.date = ConnectionsManager.getInstance().getCurrentTime();
newMsg.random_id = getNextRandomId();
UserConfig.saveConfig(false);
final MessageObject newMsgObj = new MessageObject(newMsg, null);
newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING;
final ArrayList<MessageObject> objArr = new ArrayList<MessageObject>();
objArr.add(newMsgObj);
ArrayList<TLRPC.Message> arr = new ArrayList<TLRPC.Message>();
arr.add(newMsg);
MessagesStorage.getInstance().putMessages(arr, false, true, false, 0);
MessagesController.getInstance().updateInterfaceWithMessages(newMsg.dialog_id, objArr);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload);
TLRPC.TL_decryptedMessageService reqSend = null;
if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) {
@ -1621,49 +1727,34 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))];
Utilities.random.nextBytes(reqSend.random_bytes);
}
reqSend.random_id = newMsg.random_id;
reqSend.action = new TLRPC.TL_decryptedMessageActionSetMessageTTL();
reqSend.action.ttl_seconds = encryptedChat.ttl;
performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null, null);
TLRPC.Message message = null;
if (resendMessage != null) {
message = resendMessage;
reqSend.action = message.action.encryptedAction;
} else {
reqSend.action = new TLRPC.TL_decryptedMessageActionSetMessageTTL();
reqSend.action.ttl_seconds = encryptedChat.ttl;
message = createServiceSecretMessage(encryptedChat, reqSend.action);
MessageObject newMsgObj = new MessageObject(message, null);
newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING;
ArrayList<MessageObject> objArr = new ArrayList<MessageObject>();
objArr.add(newMsgObj);
MessagesController.getInstance().updateInterfaceWithMessages(message.dialog_id, objArr);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload);
}
reqSend.random_id = message.random_id;
performSendEncryptedRequest(reqSend, message, encryptedChat, null, null);
}
public void sendScreenshotMessage(TLRPC.EncryptedChat encryptedChat, ArrayList<Long> random_ids) {
public void sendScreenshotMessage(TLRPC.EncryptedChat encryptedChat, ArrayList<Long> random_ids, TLRPC.Message resendMessage) {
if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) {
return;
}
TLRPC.TL_decryptedMessageActionScreenshotMessages action = new TLRPC.TL_decryptedMessageActionScreenshotMessages();
action.random_ids = random_ids;
TLRPC.TL_messageService newMsg = new TLRPC.TL_messageService();
newMsg.action = new TLRPC.TL_messageEcryptedAction();
newMsg.action.encryptedAction = action;
newMsg.local_id = newMsg.id = UserConfig.getNewMessageId();
newMsg.from_id = UserConfig.getClientUserId();
newMsg.flags = TLRPC.MESSAGE_FLAG_UNREAD | TLRPC.MESSAGE_FLAG_OUT;
newMsg.dialog_id = ((long)encryptedChat.id) << 32;
newMsg.to_id = new TLRPC.TL_peerUser();
if (encryptedChat.participant_id == UserConfig.getClientUserId()) {
newMsg.to_id.user_id = encryptedChat.admin_id;
} else {
newMsg.to_id.user_id = encryptedChat.participant_id;
}
newMsg.date = ConnectionsManager.getInstance().getCurrentTime();
newMsg.random_id = getNextRandomId();
UserConfig.saveConfig(false);
final MessageObject newMsgObj = new MessageObject(newMsg, null);
newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING;
final ArrayList<MessageObject> objArr = new ArrayList<MessageObject>();
objArr.add(newMsgObj);
ArrayList<TLRPC.Message> arr = new ArrayList<TLRPC.Message>();
arr.add(newMsg);
MessagesStorage.getInstance().putMessages(arr, false, true, false, 0);
MessagesController.getInstance().updateInterfaceWithMessages(newMsg.dialog_id, objArr);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload);
TLRPC.TL_decryptedMessageService reqSend = null;
if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) {
reqSend = new TLRPC.TL_decryptedMessageService();
@ -1672,9 +1763,27 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
reqSend.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))];
Utilities.random.nextBytes(reqSend.random_bytes);
}
reqSend.random_id = newMsg.random_id;
reqSend.action = action;
performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null, null, null);
TLRPC.Message message = null;
if (resendMessage != null) {
message = resendMessage;
reqSend.action = message.action.encryptedAction;
} else {
reqSend.action = new TLRPC.TL_decryptedMessageActionScreenshotMessages();
reqSend.action.random_ids = random_ids;
message = createServiceSecretMessage(encryptedChat, reqSend.action);
MessageObject newMsgObj = new MessageObject(message, null);
newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING;
ArrayList<MessageObject> objArr = new ArrayList<MessageObject>();
objArr.add(newMsgObj);
MessagesController.getInstance().updateInterfaceWithMessages(message.dialog_id, objArr);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload);
}
reqSend.random_id = message.random_id;
performSendEncryptedRequest(reqSend, message, encryptedChat, null, null);
}
private void putToDelayedMessages(String location, DelayedMessage message) {
@ -1695,7 +1804,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
}
public void checkUnsentMessages() {
MessagesStorage.getInstance().getUnsentMessages(10);
MessagesStorage.getInstance().getUnsentMessages(1000);
}
protected void processUnsentMessages(final ArrayList<TLRPC.Message> messages, final ArrayList<TLRPC.User> users, final ArrayList<TLRPC.Chat> chats, final ArrayList<TLRPC.EncryptedChat> encryptedChats) {

View file

@ -704,4 +704,26 @@ public class FileLoader {
}
return "";
}
public void deleteFiles(final ArrayList<File> files) {
if (files == null || files.isEmpty()) {
return;
}
fileLoaderQueue.postRunnable(new Runnable() {
@Override
public void run() {
for (File file : files) {
if (file.exists()) {
try {
if (!file.delete()) {
file.deleteOnExit();
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
}
}
});
}
}

View file

@ -370,7 +370,7 @@ public class TLClassStore {
classStore.put(TLRPC.TL_userRequest_old.constructor, TLRPC.TL_userRequest_old.class);
classStore.put(TLRPC.TL_userForeign_old.constructor, TLRPC.TL_userForeign_old.class);
classStore.put(TLRPC.TL_userDeleted_old.constructor, TLRPC.TL_userDeleted_old.class);
classStore.put(TLRPC.TL_messageEcryptedAction.constructor, TLRPC.TL_messageEcryptedAction.class);
classStore.put(TLRPC.TL_messageEncryptedAction.constructor, TLRPC.TL_messageEncryptedAction.class);
}
static TLClassStore store = null;

View file

@ -8429,33 +8429,38 @@ public class TLRPC {
}
}
//manually created
public static class TL_messages_sendEncryptedService extends TLObject {
public static int constructor = 0x32d439a4;
public TL_inputEncryptedChat peer;
public long random_id;
public byte[] data;
public ByteBufferDesc data;
public Class responseClass () {
return messages_SentEncryptedMessage.class;
}
public void readParams(AbsSerializedData stream) {
peer = (TL_inputEncryptedChat)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32());
random_id = stream.readInt64();
data = stream.readByteArray();
}
public void serializeToStream(AbsSerializedData stream) {
stream.writeInt32(constructor);
peer.serializeToStream(stream);
stream.writeInt64(random_id);
stream.writeByteArray(data);
stream.writeByteBuffer(data);
}
@Override
public void freeResources() {
if (disableFree) {
return;
}
if (data != null) {
BuffersStorage.getInstance().reuseFreeBuffer(data);
data = null;
}
}
}
//manually created
public static class TL_userDeleted_old extends TL_userDeleted {
public static int constructor = 0xb29ad7cc;
@ -8990,6 +8995,8 @@ public class TLRPC {
public int ttl;
public int destroyTime;
public int layer;
public int seq_in;
public int seq_out;
public VideoEditedInfo videoEditedInfo = null;
}
@ -9993,7 +10000,7 @@ public class TLRPC {
}
}
public static class TL_messageEcryptedAction extends MessageAction {
public static class TL_messageEncryptedAction extends MessageAction {
public static int constructor = 0x555555F7;
public void readParams(AbsSerializedData stream) {

View file

@ -43,36 +43,41 @@ public class ChatMessageCell extends ChatBaseCell {
y -= textY;
int blockNum = Math.max(0, y / currentMessageObject.blockHeight);
if (blockNum < currentMessageObject.textLayoutBlocks.size()) {
MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(blockNum);
x -= textX - (int)Math.ceil(block.textXOffset);
y -= block.textYOffset;
final int line = block.textLayout.getLineForVertical(y);
final int off = block.textLayout.getOffsetForHorizontal(line, x) + block.charactersOffset;
try {
MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(blockNum);
x -= textX - (int)Math.ceil(block.textXOffset);
y -= block.textYOffset;
final int line = block.textLayout.getLineForVertical(y);
final int off = block.textLayout.getOffsetForHorizontal(line, x) + block.charactersOffset;
final float left = block.textLayout.getLineLeft(line);
if (left <= x && left + block.textLayout.getLineWidth(line) >= x) {
Spannable buffer = (Spannable)currentMessageObject.messageText;
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
final float left = block.textLayout.getLineLeft(line);
if (left <= x && left + block.textLayout.getLineWidth(line) >= x) {
Spannable buffer = (Spannable)currentMessageObject.messageText;
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
pressedLink = link[0];
return true;
} else {
if (link[0] == pressedLink) {
try {
pressedLink.onClick(this);
} catch (Exception e) {
FileLog.e("tmessages", e);
}
if (link.length != 0) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
pressedLink = link[0];
return true;
} else {
if (link[0] == pressedLink) {
try {
pressedLink.onClick(this);
} catch (Exception e) {
FileLog.e("tmessages", e);
}
return true;
}
}
} else {
pressedLink = null;
}
} else {
pressedLink = null;
}
} else {
} catch (Exception e) {
pressedLink = null;
FileLog.e("tmessages", e);
}
} else {
pressedLink = null;

View file

@ -387,7 +387,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
typingDotsDrawable.setIsChat(currentChat != null);
if (currentEncryptedChat != null && AndroidUtilities.getMyLayerVersion(currentEncryptedChat.layer) != SendMessagesHelper.CURRENT_SECRET_CHAT_LAYER) {
SendMessagesHelper.getInstance().sendNotifyLayerMessage(currentEncryptedChat);
SendMessagesHelper.getInstance().sendNotifyLayerMessage(currentEncryptedChat, null);
}
return true;
@ -651,7 +651,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
actionModeViews.clear();
ActionBarMenu actionMode = actionBarLayer.createActionMode();
final ActionBarMenu actionMode = actionBarLayer.createActionMode();
actionModeViews.add(actionMode.addItem(-2, R.drawable.ic_ab_done_gray, R.drawable.bar_selector_mode));
FrameLayout layout = new FrameLayout(actionMode.getContext());
@ -822,6 +822,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
chatListView.setOnInterceptTouchEventListener(new LayoutListView.OnInterceptTouchEventListener() {
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (actionBarLayer.isActionModeShowed()) {
return false;
}
if (event.getAction() == MotionEvent.ACTION_DOWN) {
int x = (int)event.getX();
int y = (int)event.getY();
@ -880,14 +883,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
public boolean onTouch(View v, MotionEvent event) {
if (openSecretPhotoRunnable != null || SecretPhotoViewer.getInstance().isVisible()) {
if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_POINTER_UP) {
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
chatListView.setOnItemClickListener(onItemClickListener);
}
}, 150);
if (openSecretPhotoRunnable != null) {
AndroidUtilities.CancelRunOnUIThread(openSecretPhotoRunnable);
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
chatListView.setOnItemClickListener(onItemClickListener);
}
}, 150);
openSecretPhotoRunnable = null;
try {
Toast.makeText(v.getContext(), LocaleController.getString("PhotoTip", R.string.PhotoTip), Toast.LENGTH_SHORT).show();
@ -899,14 +902,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
chatListView.setOnItemClickListener(onItemClickListener);
chatListView.setOnItemLongClickListener(onItemLongClickListener);
chatListView.setLongClickable(true);
}
});
SecretPhotoViewer.getInstance().closePhoto();
} else {
chatListView.setOnItemClickListener(onItemClickListener);
}
}
} else if (event.getAction() != MotionEvent.ACTION_DOWN) {
@ -1043,7 +1043,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
if (messageObject == null || messageObject.isOut() || !messageObject.isSecretMedia() || messageObject.messageOwner.destroyTime != 0) {
return false;
}
MessagesController.getInstance().markMessageAsRead(dialog_id, messageObject.messageOwner.random_id);
MessagesController.getInstance().markMessageAsRead(dialog_id, messageObject.messageOwner.random_id, messageObject.messageOwner.ttl);
messageObject.messageOwner.destroyTime = messageObject.messageOwner.ttl + ConnectionsManager.getInstance().getCurrentTime();
return true;
}
@ -1290,11 +1290,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
} else {
return 6;
}
} else if (messageObject.type == 10 || messageObject.type == 11 || messageObject.isSending()) {
if (messageObject.messageOwner.id == 0) {
} else if (messageObject.type == 10 || messageObject.type == 11) {
if (messageObject.isSending()) {
return -1;
} else {
return 1;
}
return 1;
} else {
if (!(messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaEmpty)) {
if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVideo ||
@ -1502,10 +1503,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
SendMessagesHelper.prepareSendingVideo(videoPath, estimatedSize, estimatedDuration, resultWidth, resultHeight, videoEditedInfo, dialog_id);
}
});
if (parentLayout == null || !parentLayout.presentFragment(fragment, removeLast, true, true)) {
if (parentLayout == null || !fragment.onFragmentCreate()) {
SendMessagesHelper.prepareSendingVideo(videoPath, 0, 0, 0, 0, null, dialog_id);
return false;
}
parentLayout.presentFragment(fragment, removeLast, true, true);
return true;
}
@ -1686,6 +1689,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
if (minDate == 0 || obj.messageOwner.date < minDate) {
minDate = obj.messageOwner.date;
}
if (obj.type < 0) {
continue;
}
if (!obj.isOut() && obj.isUnread()) {
wasUnread = true;
}
@ -1876,14 +1884,18 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
ArrayList<MessageObject> arr = (ArrayList<MessageObject>)args[1];
if (currentEncryptedChat != null && arr.size() == 1) {
MessageObject messageObject = arr.get(0);
MessageObject obj = arr.get(0);
if (messageObject.isOut() && messageObject.messageOwner.action instanceof TLRPC.TL_messageActionTTLChange && getParentActivity() != null && AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) < 17 && currentEncryptedChat.ttl > 0 && currentEncryptedChat.ttl <= 60) {
AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity());
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
builder.setPositiveButton(R.string.OK, null);
builder.setMessage(LocaleController.formatString("CompatibilityChat", R.string.CompatibilityChat, currentUser.first_name, currentUser.first_name));
showAlertDialog(builder);
if (currentEncryptedChat != null && obj.isOut() && obj.messageOwner.action != null && obj.messageOwner.action instanceof TLRPC.TL_messageEncryptedAction &&
obj.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL && getParentActivity() != null) {
TLRPC.TL_decryptedMessageActionSetMessageTTL action = (TLRPC.TL_decryptedMessageActionSetMessageTTL)obj.messageOwner.action.encryptedAction;
if (AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) < 17 && currentEncryptedChat.ttl > 0 && currentEncryptedChat.ttl <= 60) {
AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity());
builder.setTitle(LocaleController.getString("AppName", R.string.AppName));
builder.setPositiveButton(R.string.OK, null);
builder.setMessage(LocaleController.formatString("CompatibilityChat", R.string.CompatibilityChat, currentUser.first_name, currentUser.first_name));
showAlertDialog(builder);
}
}
}
@ -1896,8 +1908,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
boolean currentMarkAsRead = false;
for (MessageObject obj : arr) {
if (currentEncryptedChat != null && obj.messageOwner.action != null && obj.messageOwner.action instanceof TLRPC.TL_messageActionTTLChange && timerButton != null) {
timerButton.setTime(obj.messageOwner.action.ttl);
if (currentEncryptedChat != null && obj.messageOwner.action != null && obj.messageOwner.action instanceof TLRPC.TL_messageEncryptedAction &&
obj.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL && timerButton != null) {
TLRPC.TL_decryptedMessageActionSetMessageTTL action = (TLRPC.TL_decryptedMessageActionSetMessageTTL)obj.messageOwner.action.encryptedAction;
timerButton.setTime(action.ttl_seconds);
}
if (obj.isOut() && obj.isSending()) {
scrollToLastMessage();
@ -1938,8 +1952,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
boolean markAsRead = false;
int oldCount = messages.size();
for (MessageObject obj : arr) {
if (currentEncryptedChat != null && obj.messageOwner.action != null && obj.messageOwner.action instanceof TLRPC.TL_messageActionTTLChange && timerButton != null) {
timerButton.setTime(obj.messageOwner.action.ttl);
if (currentEncryptedChat != null && obj.messageOwner.action != null && obj.messageOwner.action instanceof TLRPC.TL_messageEncryptedAction &&
obj.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL && timerButton != null) {
TLRPC.TL_decryptedMessageActionSetMessageTTL action = (TLRPC.TL_decryptedMessageActionSetMessageTTL)obj.messageOwner.action.encryptedAction;
timerButton.setTime(action.ttl_seconds);
}
if (messagesDict.containsKey(obj.messageOwner.id)) {
continue;
@ -2108,9 +2124,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
MessageObject obj = messagesDict.get(msgId);
if (obj != null) {
Integer newMsgId = (Integer)args[1];
MessageObject newMsgObj = (MessageObject)args[2];
TLRPC.Message newMsgObj = (TLRPC.Message)args[2];
if (newMsgObj != null) {
obj.messageOwner.media = newMsgObj.messageOwner.media;
obj.messageOwner.media = newMsgObj.media;
obj.generateThumbs(true, 1);
}
messagesDict.remove(msgId);

View file

@ -657,7 +657,16 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
if (obj.isSent()) {
ArrayList<Integer> arr = new ArrayList<Integer>();
arr.add(obj.messageOwner.id);
MessagesController.getInstance().deleteMessages(arr, null, null);
ArrayList<Long> random_ids = null;
TLRPC.EncryptedChat encryptedChat = null;
if ((int)obj.getDialogId() == 0 && obj.messageOwner.random_id != 0) {
random_ids = new ArrayList<Long>();
random_ids.add(obj.messageOwner.random_id);
encryptedChat = MessagesController.getInstance().getEncryptedChat((int)(obj.getDialogId() >> 32));
}
MessagesController.getInstance().deleteMessages(arr, random_ids, encryptedChat);
closePhoto(false);
}
} else if (!avatarsArr.isEmpty()) {

View file

@ -71,9 +71,7 @@ public class SettingsChangeUsernameActivity extends BaseFragment {
doneButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (firstNameField.getText().length() != 0) {
saveName();
}
saveName();
}
});

View file

@ -58,6 +58,7 @@ import java.util.List;
@TargetApi(16)
public class VideoEditorActivity extends BaseFragment implements TextureView.SurfaceTextureListener {
private boolean created = false;
private MediaPlayer videoPlayer = null;
private VideoTimelineView videoTimelineView = null;
private View videoContainerView = null;
@ -161,6 +162,9 @@ public class VideoEditorActivity extends BaseFragment implements TextureView.Sur
@Override
public boolean onFragmentCreate() {
if (created) {
return true;
}
if (videoPath == null || !processOpenVideo()) {
return false;
}
@ -191,6 +195,8 @@ public class VideoEditorActivity extends BaseFragment implements TextureView.Sur
return false;
}
created = true;
return super.onFragmentCreate();
}

View file

@ -36,7 +36,6 @@ import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.widget.LinearLayout;
import android.widget.Scroller;
import android.widget.TextView;
import org.telegram.messenger.R;
@ -726,6 +725,28 @@ public class NumberPicker extends LinearLayout {
}
}
public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = size;
break;
case MeasureSpec.AT_MOST:
if (specSize < size) {
result = specSize | 16777216;
} else {
result = size;
}
break;
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result | (childMeasuredState & (-16777216));
}
private void initializeSelectorWheelIndices() {
mSelectorIndexToStringCache.clear();
int[] selectorIndices = mSelectorIndices;

View file

@ -0,0 +1,502 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.telegram.ui.Views;
import android.content.Context;
import android.hardware.SensorManager;
import android.util.FloatMath;
import android.view.ViewConfiguration;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
/**
* This class encapsulates scrolling. The duration of the scroll
* can be passed in the constructor and specifies the maximum time that
* the scrolling animation should take. Past this time, the scrolling is
* automatically moved to its final stage and computeScrollOffset()
* will always return false to indicate that scrolling is over.
*/
public class Scroller {
private int mMode;
private int mStartX;
private int mStartY;
private int mFinalX;
private int mFinalY;
private int mMinX;
private int mMaxX;
private int mMinY;
private int mMaxY;
private int mCurrX;
private int mCurrY;
private long mStartTime;
private int mDuration;
private float mDurationReciprocal;
private float mDeltaX;
private float mDeltaY;
private boolean mFinished;
private Interpolator mInterpolator;
private boolean mFlywheel;
private float mVelocity;
private static final int DEFAULT_DURATION = 250;
private static final int SCROLL_MODE = 0;
private static final int FLING_MODE = 1;
private static float DECELERATION_RATE = (float) (Math.log(0.75) / Math.log(0.9));
private static float START_TENSION = 0.4f; // Tension at start: (0.4 * total T, 1.0 * Distance)
private static float END_TENSION = 1.0f - START_TENSION;
private static final int NB_SAMPLES = 100;
private static final float[] SPLINE = new float[NB_SAMPLES + 1];
private float mDeceleration;
private final float mPpi;
static {
float x_min = 0.0f;
for (int i = 0; i <= NB_SAMPLES; i++) {
final float t = (float) i / NB_SAMPLES;
float x_max = 1.0f;
float x, tx, coef;
while (true) {
x = x_min + (x_max - x_min) / 2.0f;
coef = 3.0f * x * (1.0f - x);
tx = coef * ((1.0f - x) * START_TENSION + x * END_TENSION) + x * x * x;
if (Math.abs(tx - t) < 1E-5) break;
if (tx > t) x_max = x;
else x_min = x;
}
final float d = coef + x * x * x;
SPLINE[i] = d;
}
SPLINE[NB_SAMPLES] = 1.0f;
// This controls the viscous fluid effect (how much of it)
sViscousFluidScale = 8.0f;
// must be set to 1.0 (used in viscousFluid())
sViscousFluidNormalize = 1.0f;
sViscousFluidNormalize = 1.0f / viscousFluid(1.0f);
}
private static float sViscousFluidScale;
private static float sViscousFluidNormalize;
/**
* Create a Scroller with the default duration and interpolator.
*/
public Scroller(Context context) {
this(context, null);
}
/**
* Create a Scroller with the specified interpolator. If the interpolator is
* null, the default (viscous) interpolator will be used. "Flywheel" behavior will
* be in effect for apps targeting Honeycomb or newer.
*/
public Scroller(Context context, Interpolator interpolator) {
this(context, interpolator, true);
}
/**
* Create a Scroller with the specified interpolator. If the interpolator is
* null, the default (viscous) interpolator will be used. Specify whether or
* not to support progressive "flywheel" behavior in flinging.
*/
public Scroller(Context context, Interpolator interpolator, boolean flywheel) {
mFinished = true;
mInterpolator = interpolator;
mPpi = context.getResources().getDisplayMetrics().density * 160.0f;
mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction());
mFlywheel = flywheel;
}
/**
* The amount of friction applied to flings. The default value
* is {@link android.view.ViewConfiguration#getScrollFriction}.
*
* @param friction A scalar dimension-less value representing the coefficient of
* friction.
*/
public final void setFriction(float friction) {
mDeceleration = computeDeceleration(friction);
}
private float computeDeceleration(float friction) {
return SensorManager.GRAVITY_EARTH // g (m/s^2)
* 39.37f // inch/meter
* mPpi // pixels per inch
* friction;
}
/**
*
* Returns whether the scroller has finished scrolling.
*
* @return True if the scroller has finished scrolling, false otherwise.
*/
public final boolean isFinished() {
return mFinished;
}
/**
* Force the finished field to a particular value.
*
* @param finished The new finished value.
*/
public final void forceFinished(boolean finished) {
mFinished = finished;
}
/**
* Returns how long the scroll event will take, in milliseconds.
*
* @return The duration of the scroll in milliseconds.
*/
public final int getDuration() {
return mDuration;
}
/**
* Returns the current X offset in the scroll.
*
* @return The new X offset as an absolute distance from the origin.
*/
public final int getCurrX() {
return mCurrX;
}
/**
* Returns the current Y offset in the scroll.
*
* @return The new Y offset as an absolute distance from the origin.
*/
public final int getCurrY() {
return mCurrY;
}
/**
* Returns the current velocity.
*
* @return The original velocity less the deceleration. Result may be
* negative.
*/
public float getCurrVelocity() {
return mVelocity - mDeceleration * timePassed() / 2000.0f;
}
/**
* Returns the start X offset in the scroll.
*
* @return The start X offset as an absolute distance from the origin.
*/
public final int getStartX() {
return mStartX;
}
/**
* Returns the start Y offset in the scroll.
*
* @return The start Y offset as an absolute distance from the origin.
*/
public final int getStartY() {
return mStartY;
}
/**
* Returns where the scroll will end. Valid only for "fling" scrolls.
*
* @return The final X offset as an absolute distance from the origin.
*/
public final int getFinalX() {
return mFinalX;
}
/**
* Returns where the scroll will end. Valid only for "fling" scrolls.
*
* @return The final Y offset as an absolute distance from the origin.
*/
public final int getFinalY() {
return mFinalY;
}
/**
* Call this when you want to know the new location. If it returns true,
* the animation is not yet finished. loc will be altered to provide the
* new location.
*/
public boolean computeScrollOffset() {
if (mFinished) {
return false;
}
int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
if (timePassed < mDuration) {
switch (mMode) {
case SCROLL_MODE:
float x = timePassed * mDurationReciprocal;
if (mInterpolator == null)
x = viscousFluid(x);
else
x = mInterpolator.getInterpolation(x);
mCurrX = mStartX + Math.round(x * mDeltaX);
mCurrY = mStartY + Math.round(x * mDeltaY);
break;
case FLING_MODE:
final float t = (float) timePassed / mDuration;
final int index = (int) (NB_SAMPLES * t);
final float t_inf = (float) index / NB_SAMPLES;
final float t_sup = (float) (index + 1) / NB_SAMPLES;
final float d_inf = SPLINE[index];
final float d_sup = SPLINE[index + 1];
final float distanceCoef = d_inf + (t - t_inf) / (t_sup - t_inf) * (d_sup - d_inf);
mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));
// Pin to mMinX <= mCurrX <= mMaxX
mCurrX = Math.min(mCurrX, mMaxX);
mCurrX = Math.max(mCurrX, mMinX);
mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));
// Pin to mMinY <= mCurrY <= mMaxY
mCurrY = Math.min(mCurrY, mMaxY);
mCurrY = Math.max(mCurrY, mMinY);
if (mCurrX == mFinalX && mCurrY == mFinalY) {
mFinished = true;
}
break;
}
}
else {
mCurrX = mFinalX;
mCurrY = mFinalY;
mFinished = true;
}
return true;
}
/**
* Start scrolling by providing a starting point and the distance to travel.
* The scroll will use the default value of 250 milliseconds for the
* duration.
*
* @param startX Starting horizontal scroll offset in pixels. Positive
* numbers will scroll the content to the left.
* @param startY Starting vertical scroll offset in pixels. Positive numbers
* will scroll the content up.
* @param dx Horizontal distance to travel. Positive numbers will scroll the
* content to the left.
* @param dy Vertical distance to travel. Positive numbers will scroll the
* content up.
*/
public void startScroll(int startX, int startY, int dx, int dy) {
startScroll(startX, startY, dx, dy, DEFAULT_DURATION);
}
/**
* Start scrolling by providing a starting point and the distance to travel.
*
* @param startX Starting horizontal scroll offset in pixels. Positive
* numbers will scroll the content to the left.
* @param startY Starting vertical scroll offset in pixels. Positive numbers
* will scroll the content up.
* @param dx Horizontal distance to travel. Positive numbers will scroll the
* content to the left.
* @param dy Vertical distance to travel. Positive numbers will scroll the
* content up.
* @param duration Duration of the scroll in milliseconds.
*/
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
mMode = SCROLL_MODE;
mFinished = false;
mDuration = duration;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStartX = startX;
mStartY = startY;
mFinalX = startX + dx;
mFinalY = startY + dy;
mDeltaX = dx;
mDeltaY = dy;
mDurationReciprocal = 1.0f / (float) mDuration;
}
/**
* Start scrolling based on a fling gesture. The distance travelled will
* depend on the initial velocity of the fling.
*
* @param startX Starting point of the scroll (X)
* @param startY Starting point of the scroll (Y)
* @param velocityX Initial velocity of the fling (X) measured in pixels per
* second.
* @param velocityY Initial velocity of the fling (Y) measured in pixels per
* second
* @param minX Minimum X value. The scroller will not scroll past this
* point.
* @param maxX Maximum X value. The scroller will not scroll past this
* point.
* @param minY Minimum Y value. The scroller will not scroll past this
* point.
* @param maxY Maximum Y value. The scroller will not scroll past this
* point.
*/
public void fling(int startX, int startY, int velocityX, int velocityY,
int minX, int maxX, int minY, int maxY) {
// Continue a scroll or fling in progress
if (mFlywheel && !mFinished) {
float oldVel = getCurrVelocity();
float dx = (float) (mFinalX - mStartX);
float dy = (float) (mFinalY - mStartY);
float hyp = FloatMath.sqrt(dx * dx + dy * dy);
float ndx = dx / hyp;
float ndy = dy / hyp;
float oldVelocityX = ndx * oldVel;
float oldVelocityY = ndy * oldVel;
if (Math.signum(velocityX) == Math.signum(oldVelocityX) &&
Math.signum(velocityY) == Math.signum(oldVelocityY)) {
velocityX += oldVelocityX;
velocityY += oldVelocityY;
}
}
mMode = FLING_MODE;
mFinished = false;
float velocity = FloatMath.sqrt(velocityX * velocityX + velocityY * velocityY);
mVelocity = velocity;
float ALPHA = 800;
final double l = Math.log(START_TENSION * velocity / ALPHA);
mDuration = (int) (1000.0 * Math.exp(l / (DECELERATION_RATE - 1.0)));
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStartX = startX;
mStartY = startY;
float coeffX = velocity == 0 ? 1.0f : velocityX / velocity;
float coeffY = velocity == 0 ? 1.0f : velocityY / velocity;
int totalDistance =
(int) (ALPHA * Math.exp(DECELERATION_RATE / (DECELERATION_RATE - 1.0) * l));
mMinX = minX;
mMaxX = maxX;
mMinY = minY;
mMaxY = maxY;
mFinalX = startX + Math.round(totalDistance * coeffX);
// Pin to mMinX <= mFinalX <= mMaxX
mFinalX = Math.min(mFinalX, mMaxX);
mFinalX = Math.max(mFinalX, mMinX);
mFinalY = startY + Math.round(totalDistance * coeffY);
// Pin to mMinY <= mFinalY <= mMaxY
mFinalY = Math.min(mFinalY, mMaxY);
mFinalY = Math.max(mFinalY, mMinY);
}
static float viscousFluid(float x)
{
x *= sViscousFluidScale;
if (x < 1.0f) {
x -= (1.0f - (float)Math.exp(-x));
} else {
float start = 0.36787944117f; // 1/e == exp(-1)
x = 1.0f - (float)Math.exp(1.0f - x);
x = start + x * (1.0f - start);
}
x *= sViscousFluidNormalize;
return x;
}
/**
* Stops the animation. Contrary to {@link #forceFinished(boolean)},
* aborting the animating cause the scroller to move to the final x and y
* position
*
* @see #forceFinished(boolean)
*/
public void abortAnimation() {
mCurrX = mFinalX;
mCurrY = mFinalY;
mFinished = true;
}
/**
* Extend the scroll animation. This allows a running animation to scroll
* further and longer, when used with {@link #setFinalX(int)} or {@link #setFinalY(int)}.
*
* @param extend Additional time to scroll in milliseconds.
* @see #setFinalX(int)
* @see #setFinalY(int)
*/
public void extendDuration(int extend) {
int passed = timePassed();
mDuration = passed + extend;
mDurationReciprocal = 1.0f / mDuration;
mFinished = false;
}
/**
* Returns the time elapsed since the beginning of the scrolling.
*
* @return The elapsed time in milliseconds.
*/
public int timePassed() {
return (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
}
/**
* Sets the final position (X) for this scroller.
*
* @param newX The new X offset as an absolute distance from the origin.
* @see #extendDuration(int)
* @see #setFinalY(int)
*/
public void setFinalX(int newX) {
mFinalX = newX;
mDeltaX = mFinalX - mStartX;
mFinished = false;
}
/**
* Sets the final position (Y) for this scroller.
*
* @param newY The new Y offset as an absolute distance from the origin.
* @see #extendDuration(int)
* @see #setFinalX(int)
*/
public void setFinalY(int newY) {
mFinalY = newY;
mDeltaY = mFinalY - mStartY;
mFinished = false;
}
public boolean isScrollingInDirection(float xvel, float yvel) {
return !mFinished && Math.signum(xvel) == Math.signum(mFinalX - mStartX) &&
Math.signum(yvel) == Math.signum(mFinalY - mStartY);
}
}

View file

@ -51,6 +51,7 @@
<string name="DeleteChat">حذف وخروج</string>
<string name="HiddenName">الاسم مخفي</string>
<string name="SelectChat">اختر محادثة</string>
<string name="PhotoTip">إضغط بإستمرار على المستخدم العرض</string>
<string name="CompatibilityChat">%1$s يستخدم إصدار قديم من تيليجرام، لذلك، الصور السرية ستظهر في وضع الموافقة.\n\nعندما يقوم %2$s بتحديث تيليجرام، الصور التي بها عداد دقيقة أو أقل ستعمل بطريقة \"الاستمرار بالضغط للإستعراض\"، وسيتم إخبارك عندما يلتقط المستقبل صورة من شاشته.</string>
<!--broadcasts-->
<string name="BroadcastList">قائمة الرسالة الجماعية</string>
@ -201,6 +202,7 @@
<string name="NumberUnknown">غير معروف</string>
<string name="Info">معلومات</string>
<string name="Phone">هاتف</string>
<!--usernames-->
<string name="Username">اسم مستخدم</string>
<string name="UsernamePlaceholder">معرّفك</string>
<string name="UsernameInUse">المعذرة، اسم المستخدم تم اختياره مسبقًا.</string>
@ -211,8 +213,8 @@
<string name="UsernameHelp">يمكنك اختيار اسم مستخدم في <![CDATA[<b>]]>تيليجرام<![CDATA[</b>]]>. إذا قمت بذلك، سيستطيع الناس إيجادك باستخدام الاسم المستخدم والتواصل معك من دون معرفة رقمك.<![CDATA[<br><br>]]>يمكنك استخدام <![CDATA[<b>]]>حروف اللغة الإنجليزية<![CDATA[</b>]]>, <![CDATA[<b>]]>وأرقامها<![CDATA[</b>]]> و كذلك الخط. لا بد من استخدام <![CDATA[<b>]]>٥<![CDATA[</b>]]> حروف على الأقل.</string>
<string name="UsernameChecking">جاري مراجعة اسم المستخدم...</string>
<string name="UsernameAvailable">%1$s متاح.</string>
<string name="UsernameEmpty">None</string>
<string name="ErrorOccurred">An error occurred</string>
<string name="UsernameEmpty">لا يوجد</string>
<string name="ErrorOccurred">حدث خطأ.</string>
<!--settings view-->
<string name="ResetNotificationsText">تم تعيين كافة الإشعارات افتراضيا</string>
<string name="TextSize">حجم نص الرسائل</string>
@ -384,6 +386,7 @@
<string name="ForwardFromMyName">أعد الإرسال باستخدام اسمي</string>
<string name="SendMessagesToGroup">هل ترغب في إرسال رسالة إلى %1$s؟</string>
<string name="ForwardMessagesToGroup">؟%1$s هل تريد إعادة توجيه الرسائل إلى</string>
<string name="FeatureUnavailable">.Sorry, this feature is currently not available in your country</string>
<!--Intro view-->
<string name="Page1Title">تيليجرام</string>
<string name="Page2Title">سريع</string>

View file

@ -51,6 +51,7 @@
<string name="DeleteChat">Löschen und beenden</string>
<string name="HiddenName">Versteckter Name</string>
<string name="SelectChat">Chat auswählen</string>
<string name="PhotoTip">Tippen und Halten</string>
<string name="CompatibilityChat">%1$s benutzt eine ältere Version von Telegram, sodass Fotos in Geheimen Chats im Kompatibilitätsmodus angezeigt werden.\n\nSobald %2$s Telegram aktualisiert, werden Fotos mit Timern von 1 Minute und kürzer per \"Tippen und Halten\" angezeigt. Du wirst benachrichtigt, sobald dein Chatpartner ein Bildschirmfoto macht.</string>
<!--broadcasts-->
<string name="BroadcastList">Broadcast Liste</string>
@ -201,6 +202,7 @@
<string name="NumberUnknown">Unbekannt</string>
<string name="Info">INFO</string>
<string name="Phone">Telefon</string>
<!--usernames-->
<string name="Username">Benutzername</string>
<string name="UsernamePlaceholder">Dein Benutzername</string>
<string name="UsernameInUse">Leider ist dieser Benutzername vergeben.</string>
@ -208,11 +210,11 @@
<string name="UsernameInvalidShort">Ein Benutzername benötigt mindestens 5 Zeichen.</string>
<string name="UsernameInvalidLong">Ein Benutzername darf maximal 32 Zeichen haben.</string>
<string name="UsernameInvalidStartNumber">Benutzernamen dürfen leider nicht mit einer Zahl anfangen.</string>
<string name="UsernameHelp">Wähle einen Benutzernamen, wenn du von anderen bei<![CDATA[<b>]]>Telegram<![CDATA[</b>]]>gefunden werden willst ohne, dass sie deine Nummer kennen müssen.<![CDATA[<br><br>]]>Erlaubt sind <![CDATA[<b>]]>az<![CDATA[<b>]]>, <![CDATA[<b>]]>09<![CDATA[<b>]]> und Unterstriche. Die Mindestlänge beträgt <![CDATA[<b>]]>5<![CDATA[<b>]]> Zeichen.</string>
<string name="UsernameHelp">Wähle einen Benutzernamen, wenn du von anderen bei<![CDATA[<b>]]>Telegram<![CDATA[</b>]]>gefunden werden willst ohne, dass sie deine Nummer kennen müssen.<![CDATA[<br><br>]]>Erlaubt sind <![CDATA[<b>]]>a-z<![CDATA[<b>]]>, <![CDATA[<b>]]>0-9<![CDATA[<b>]]> und Unterstriche. Die Mindestlänge beträgt <![CDATA[<b>]]>5<![CDATA[<b>]]> Zeichen.</string>
<string name="UsernameChecking">Prüfe Benutzername...</string>
<string name="UsernameAvailable">%1$s ist verfügbar.</string>
<string name="UsernameEmpty">None</string>
<string name="ErrorOccurred">An error occurred</string>
<string name="UsernameEmpty">Keiner</string>
<string name="ErrorOccurred">Es ist ein Fehler aufgetreten.</string>
<!--settings view-->
<string name="ResetNotificationsText">Alle Einstellungen für Mitteilungen zurücksetzen</string>
<string name="TextSize">Textgröße für Nachrichten</string>
@ -384,6 +386,7 @@
<string name="ForwardFromMyName">mit meinem Namen weiterleiten</string>
<string name="SendMessagesToGroup">Nachricht an %1$s senden?</string>
<string name="ForwardMessagesToGroup">Weiterleiten an %1$s?</string>
<string name="FeatureUnavailable">Sorry, this feature is currently not available in your country.</string>
<!--Intro view-->
<string name="Page1Title">Telegram</string>
<string name="Page2Title">Schnell</string>

View file

@ -22,10 +22,10 @@
<string name="DidNotGetTheCode">¿No recibiste el código?</string>
<!--signup view-->
<string name="YourName">Tu nombre</string>
<string name="RegisterText">Ingresa tu nombre y apellido</string>
<string name="RegisterText">Ingresa tu nombre y apellidos</string>
<!--<string name="RegisterText">Set up your name and picture</string>-->
<string name="FirstName">Nombre (requerido)</string>
<string name="LastName">Apellido (opcional)</string>
<string name="LastName">Apellidos (opcional)</string>
<string name="CancelRegistration">Cancelar registro</string>
<!--chats view-->
<string name="Chats">Chats</string>
@ -51,6 +51,7 @@
<string name="DeleteChat">Eliminar y salir</string>
<string name="HiddenName">Nombre oculto</string>
<string name="SelectChat">Elige el chat</string>
<string name="PhotoTip">Mantén pulsado para ver</string>
<string name="CompatibilityChat">%1$s usa una versión antigua de Telegram, así que las fotos secretas serán mostradas en un modo de compatibilidad.\n\nCuando %2$s actualice Telegram, las fotos con autodestrucción de 1 minuto o menos funcionarán con el modo \'Mantén pulsado para ver\', y te notificaremos siempre que la otra parte haga una captura de pantalla.</string>
<!--broadcasts-->
<string name="BroadcastList">Lista de difusión</string>
@ -201,6 +202,7 @@
<string name="NumberUnknown">Desconocido</string>
<string name="Info">INFORMACIÓN</string>
<string name="Phone">Teléfono</string>
<!--usernames-->
<string name="Username">Apodo</string>
<string name="UsernamePlaceholder">Tu apodo</string>
<string name="UsernameInUse">Lo siento, este apodo ya está ocupado.</string>
@ -211,8 +213,8 @@
<string name="UsernameHelp">Puedes elegir un apodo en <![CDATA[<b>]]>Telegram<![CDATA[</b>]]>. Si lo haces, otras personas te podrán encontrar por ese apodo y contactarte sin saber tu número de teléfono.<![CDATA[<br><br>]]>Puedes usar <![CDATA[<b>]]>az<![CDATA[</b>]]>, <![CDATA[<b>]]>09<![CDATA[</b>]]> y guiones bajos. La longitud mínima es de <![CDATA[<b>]]>5<![CDATA[</b>]]> caracteres.</string>
<string name="UsernameChecking">Verificando apodo...</string>
<string name="UsernameAvailable">%1$s está disponible.</string>
<string name="UsernameEmpty">None</string>
<string name="ErrorOccurred">An error occurred</string>
<string name="UsernameEmpty">Ninguno</string>
<string name="ErrorOccurred">Ocurrió un error.</string>
<!--settings view-->
<string name="ResetNotificationsText">Restablecer las notificaciones</string>
<string name="TextSize">Tamaño del texto</string>
@ -238,7 +240,7 @@
<string name="BlockedUsers">Usuarios bloqueados</string>
<string name="SaveIncomingPhotos">Guardar fotos entrantes</string>
<string name="LogOut">Cerrar sesión</string>
<string name="YourFirstNameAndLastName">TU NOMBRE Y APELLIDO</string>
<string name="YourFirstNameAndLastName">TU NOMBRE Y APELLIDOS</string>
<string name="NoSound">Sin sonido</string>
<string name="Default">Por defecto</string>
<string name="Support">SOPORTE</string>
@ -264,7 +266,7 @@
<string name="ImportContacts">Importar contactos</string>
<string name="WiFiOnly">Sólo vía Wi-Fi</string>
<string name="SortFirstName">Nombre</string>
<string name="SortLastName">Apellido</string>
<string name="SortLastName">Apellidos</string>
<string name="LedColor">Color del LED</string>
<string name="PopupNotification">Notificaciones emergentes</string>
<string name="NoPopup">Desactivadas</string>
@ -360,7 +362,7 @@
<string name="FloodWait">Muchos intentos. Por favor, inténtalo más tarde.</string>
<string name="InvalidCode">Código inválido</string>
<string name="InvalidFirstName">Nombre inválido</string>
<string name="InvalidLastName">Apellido inválido</string>
<string name="InvalidLastName">Apellidos inválidos</string>
<string name="Loading">Cargando...</string>
<string name="NoPlayerInstalled">No tienes reproductor de vídeo. Por favor, instala uno para continuar.</string>
<string name="NoMailInstalled">Por favor, envíanos un correo electrónico a sms@telegram.org y cuéntanos tu problema.</string>
@ -384,6 +386,7 @@
<string name="ForwardFromMyName">reenviar desde mi nombre</string>
<string name="SendMessagesToGroup">¿Enviar mensajes a %1$s?</string>
<string name="ForwardMessagesToGroup">¿Reenviar mensajes a %1$s?</string>
<string name="FeatureUnavailable">Sorry, this feature is currently not available in your country.</string>
<!--Intro view-->
<string name="Page1Title">Telegram</string>
<string name="Page2Title">Rápida</string>

View file

@ -51,6 +51,7 @@
<string name="DeleteChat">Elimina ed esci</string>
<string name="HiddenName">Nome nascosto</string>
<string name="SelectChat">Seleziona chat</string>
<string name="PhotoTip">Tieni premuto per vedere</string>
<string name="CompatibilityChat">%1$s sta usando una versione vecchia di Telegram, quindi le foto segrete verranno visualizzate in modalità di compatibilità.\n\nUna volta che %2$s avrà aggiornato Telegram, le foto con il timer minore di 1 minuto funzioneranno in modalità \'Tieni premuto per vedere\' , e verrai notificato ogni volta che l\'altro esegue uno screenshot.</string>
<!--broadcasts-->
<string name="BroadcastList">Lista broadcast</string>
@ -201,6 +202,7 @@
<string name="NumberUnknown">Sconosciuto</string>
<string name="Info">INFO</string>
<string name="Phone">Telefono</string>
<!--usernames-->
<string name="Username">Nome utente</string>
<string name="UsernamePlaceholder">Il tuo Nome Utente</string>
<string name="UsernameInUse">Nome utente già preso.</string>
@ -211,8 +213,8 @@
<string name="UsernameHelp">Puoi scegliere un nome utente su <![CDATA[<b>]]>Telegram<![CDATA[</b>]]>. Se lo fai, le altre persone potranno trovarti tramite questo nome utente e contattarti senza conoscere il tuo numero di telefono.<![CDATA[<br><br>]]>Puoi usare <![CDATA[<b>]]>az<![CDATA[</b>]]>, <![CDATA[<b>]]>09<![CDATA[</b>]]> e underscore. La lunghezza minima è di <![CDATA[<b>]]>5<![CDATA[</b>]]> caratteri.</string>
<string name="UsernameChecking">Controllando il nome utente...</string>
<string name="UsernameAvailable">%1$s è disponibile.</string>
<string name="UsernameEmpty">None</string>
<string name="ErrorOccurred">An error occurred</string>
<string name="UsernameEmpty">Nessuno</string>
<string name="ErrorOccurred">Si è verificato un errore.</string>
<!--settings view-->
<string name="ResetNotificationsText">Ripristina tutte le impostazioni di notifica predefinite</string>
<string name="TextSize">Dimensione testo messaggi</string>
@ -384,6 +386,7 @@
<string name="ForwardFromMyName">inoltra dal mio nome</string>
<string name="SendMessagesToGroup">Inviare messaggi a %1$s?</string>
<string name="ForwardMessagesToGroup">Inoltra messaggi a %1$s?</string>
<string name="FeatureUnavailable">Ci spiace, questa funzione non è disponibile nel tuo paese.</string>
<!--Intro view-->
<string name="Page1Title">Telegram</string>
<string name="Page2Title">Veloce</string>

View file

@ -38,7 +38,7 @@
<string name="NoResult">결과 없음</string>
<string name="NoChats">채팅방이 없습니다...</string>
<string name="NoChatsHelp">대화를 시작하려면 우측 상단의\n초대하기 버튼을 누르거나\n메뉴 버튼을 눌러 보세요.</string>
<string name="WaitingForNetwork">네트워크 연결을 기다리는 중...</string>
<string name="WaitingForNetwork">대기 중...</string>
<string name="Connecting">연결 중...</string>
<string name="Updating">업데이트 중...</string>
<string name="NewSecretChat">비밀대화 시작</string>
@ -51,6 +51,8 @@
<string name="DeleteChat">채팅방 나가기</string>
<string name="HiddenName">숨긴 이름</string>
<string name="SelectChat">채팅방 선택</string>
<string name="PhotoTip">꾹 눌러서 보기</string>
<string name="CompatibilityChat">%1$s님의 텔레그램 버전이 낮아 비밀 사진을 호환성 모드로 표시합니다.\n\n%2$s님이 텔레그램을 업데이트하고 나면, 자동삭제 시간이 1분 이하인 사진은 \"탭하고 누르고 있어야 보임\" 상태가 되며, 상대방이 화면을 캡처할 때 마다 알림을 받습니다.</string>
<!--broadcasts-->
<string name="BroadcastList">단체 메시지 리스트</string>
<string name="NewBroadcastList">새 단체 메시지 리스트</string>
@ -160,7 +162,7 @@
<string name="LastSeen">마지막 접속: </string>
<string name="LastSeenDate">마지막 접속: </string>
<string name="InviteFriends">친구 초대</string>
<string name="GlobalSearch">GLOBAL SEARCH</string>
<string name="GlobalSearch">전체 검색</string>
<!--group create view-->
<string name="SendMessageTo">메시지 보내기...</string>
<string name="EnterGroupNamePlaceholder">그룹 이름 입력</string>
@ -197,21 +199,22 @@
<string name="MessageLifetime">자동삭제 타이머</string>
<string name="ShortMessageLifetimeForever">해제</string>
<string name="EncryptionKeyDescription">이 이미지는 <![CDATA[<b>]]>%1$s<![CDATA[</b>]]>님과의 비밀대화에 사용 중인 암호화 키의 모습입니다.<![CDATA[<br><br>]]>이 이미지가 <![CDATA[<b>]]>%2$s<![CDATA[</b>]]>님의 암호화 키와 똑같다면 대화는 200%% 안전합니다.<![CDATA[<br><br>]]>더 자세한 사항은 telegram.org 를 참고해 주세요.</string>
<string name="NumberUnknown">Unknown</string>
<string name="Info">INFO</string>
<string name="NumberUnknown">알 수 없음</string>
<string name="Info">정보</string>
<string name="Phone">전화번호</string>
<string name="Username">Username</string>
<string name="UsernamePlaceholder">Your Username</string>
<string name="UsernameInUse">Sorry, this username is already taken.</string>
<string name="UsernameInvalid">Sorry, this username is invalid.</string>
<string name="UsernameInvalidShort">A username must have at least 5 characters.</string>
<string name="UsernameInvalidLong">A username must have maximum 32 characters.</string>
<string name="UsernameInvalidStartNumber">Sorry, a username can\'t start with a number.</string>
<string name="UsernameHelp">You can choose a username on <![CDATA[<b>]]>Telegram<![CDATA[</b>]]>. If you do, other people will be able to find you by this username and contact you without knowing your phone number.<![CDATA[<br><br>]]>You can use <![CDATA[<b>]]>az<![CDATA[</b>]]>, <![CDATA[<b>]]>09<![CDATA[</b>]]> and underscores. Minimum length is <![CDATA[<b>]]>5<![CDATA[</b>]]> characters.</string>
<string name="UsernameChecking">Checking username...</string>
<string name="UsernameAvailable">%1$s is available.</string>
<string name="UsernameEmpty">None</string>
<string name="ErrorOccurred">An error occurred</string>
<!--usernames-->
<string name="Username">아이디</string>
<string name="UsernamePlaceholder">아이디</string>
<string name="UsernameInUse">이미 사용 중인 아이디입니다.</string>
<string name="UsernameInvalid">올바른 아이디를 입력하세요.</string>
<string name="UsernameInvalidShort">아이디는 최소 다섯 글자 이상 입력해야 합니다.</string>
<string name="UsernameInvalidLong">아이디는 최대 32자까지만 가능합니다.</string>
<string name="UsernameInvalidStartNumber">아이디는 숫자로 시작할 수 없습니다.</string>
<string name="UsernameHelp">텔레그램 아이디를 설정할 수 있습니다. 아이디를 설정하면 회원님의 전화번호를 몰라도 아이디로 회원님을 찾아 대화를 나눌 수 있습니다.<![CDATA[<br><br>]]>아이디는 영문, 밑줄, 숫자로 (<![CDATA[<b>]]>a~z<![CDATA[</b>]]>, <![CDATA[<b>]]>_<![CDATA[</b>]]>, <![CDATA[<b>]]>0~9<![CDATA[</b>]]>) <![CDATA[<b>]]>다섯 글자<![CDATA[</b>]]> 이상으로 설정해 주세요.</string>
<string name="UsernameChecking">아이디 확인 중...</string>
<string name="UsernameAvailable">%1$s: 사용 가능합니다.</string>
<string name="UsernameEmpty">없음</string>
<string name="ErrorOccurred">오류가 발생했습니다.</string>
<!--settings view-->
<string name="ResetNotificationsText">모든 알림 설정이 초기화되었습니다</string>
<string name="TextSize">채팅 글자 크기</string>
@ -383,6 +386,7 @@
<string name="ForwardFromMyName">내 이름으로 전달</string>
<string name="SendMessagesToGroup">%1$s 그룹에 메시지를 보낼까요?</string>
<string name="ForwardMessagesToGroup">%1$s 그룹에 메시지를 전달할까요?</string>
<string name="FeatureUnavailable">이 기능은 회원님의 국가에서는 사용할 수 없습니다.</string>
<!--Intro view-->
<string name="Page1Title">텔레그램</string>
<string name="Page2Title">눈부신 속도</string>
@ -436,36 +440,36 @@
<string name="FromContacts_few">채팅방 %1$d개에서</string>
<string name="FromContacts_many">채팅방 %1$d개에서</string>
<string name="FromContacts_other">채팅방 %1$d개에서</string>
<string name="Seconds_zero">%1$d seconds</string>
<string name="Seconds_one">%1$d second</string>
<string name="Seconds_two">%1$d seconds</string>
<string name="Seconds_few">%1$d seconds</string>
<string name="Seconds_many">%1$d seconds</string>
<string name="Seconds_other">%1$d seconds</string>
<string name="Minutes_zero">%1$d minutes</string>
<string name="Minutes_one">%1$d minute</string>
<string name="Minutes_two">%1$d minutes</string>
<string name="Minutes_few">%1$d minutes</string>
<string name="Minutes_many">%1$d minutes</string>
<string name="Minutes_other">%1$d minutes</string>
<string name="Hours_zero">%1$d hours</string>
<string name="Hours_one">%1$d hour</string>
<string name="Hours_two">%1$d hours</string>
<string name="Hours_few">%1$d hours</string>
<string name="Hours_many">%1$d hours</string>
<string name="Hours_other">%1$d hours</string>
<string name="Days_zero">%1$d days</string>
<string name="Days_one">%1$d day</string>
<string name="Days_two">%1$d days</string>
<string name="Days_few">%1$d days</string>
<string name="Days_many">%1$d days</string>
<string name="Days_other">%1$d days</string>
<string name="Weeks_zero">%1$d weeks</string>
<string name="Weeks_one">%1$d week</string>
<string name="Weeks_two">%1$d weeks</string>
<string name="Weeks_few">%1$d weeks</string>
<string name="Weeks_many">%1$d weeks</string>
<string name="Weeks_other">%1$d weeks</string>
<string name="Seconds_zero">%1$d</string>
<string name="Seconds_one">%1$d</string>
<string name="Seconds_two">%1$d</string>
<string name="Seconds_few">%1$d</string>
<string name="Seconds_many">%1$d</string>
<string name="Seconds_other">%1$d</string>
<string name="Minutes_zero">%1$d</string>
<string name="Minutes_one">%1$d</string>
<string name="Minutes_two">%1$d</string>
<string name="Minutes_few">%1$d</string>
<string name="Minutes_many">%1$d</string>
<string name="Minutes_other">%1$d</string>
<string name="Hours_zero">%1$d시간</string>
<string name="Hours_one">%1$d시간</string>
<string name="Hours_two">%1$d시간</string>
<string name="Hours_few">%1$d시간</string>
<string name="Hours_many">%1$d시간</string>
<string name="Hours_other">%1$d시간</string>
<string name="Days_zero">%1$d</string>
<string name="Days_one">%1$d</string>
<string name="Days_two">%1$d</string>
<string name="Days_few">%1$d</string>
<string name="Days_many">%1$d</string>
<string name="Days_other">%1$d</string>
<string name="Weeks_zero">%1$d</string>
<string name="Weeks_one">%1$d</string>
<string name="Weeks_two">%1$d</string>
<string name="Weeks_few">%1$d</string>
<string name="Weeks_many">%1$d</string>
<string name="Weeks_other">%1$d</string>
<!--date formatters-->
<string name="formatterMonth">M\'월\' d\'일\'</string>
<string name="formatterYear">yyyy.MM.dd.</string>

View file

@ -51,7 +51,8 @@
<string name="DeleteChat">Verwijderen en verlaten</string>
<string name="HiddenName">Verborgen naam</string>
<string name="SelectChat">Kies een gesprek</string>
<string name="CompatibilityChat">%1$s gebruikt een oudere versie van Telegram, dus worden geheime foto\'s weergegeven in de compatibiliteitsmodus.\n\nZodra %2$s Telegram update werken foto\'s met timers voor 1 minuut of minder in de \'Houd ingedrukt om te bekijken\'-modus en krijg je een bericht wanneer de andere partij een schermafbeelding maakt.</string>
<string name="PhotoTip">Druk en houd ingedrukt</string>
<string name="CompatibilityChat">%1$s gebruikt een oudere versie van Telegram, dus worden geheime foto\'s weergegeven in de compatibiliteitsmodus.\n\nZodra %2$s Telegram updatet werken foto\'s met timers voor 1 minuut of minder in de \'Druk en houd ingedrukt\'-modus en krijg je een bericht wanneer de andere partij een schermafbeelding maakt.</string>
<!--broadcasts-->
<string name="BroadcastList">Verzendlijst</string>
<string name="NewBroadcastList">Nieuwe verzendlijst</string>
@ -201,6 +202,7 @@
<string name="NumberUnknown">Onbekend</string>
<string name="Info">INFORMATIE</string>
<string name="Phone">Telefoon</string>
<!--usernames-->
<string name="Username">Gebruikersnaam</string>
<string name="UsernamePlaceholder">Kies een naam</string>
<string name="UsernameInUse">Sorry, deze gebruikersnaam is al bezet.</string>
@ -211,8 +213,8 @@
<string name="UsernameHelp">Je kan een gebruikersnaam kiezen voor <![CDATA[<b>]]>Telegram<![CDATA[</b>]]>. Hiermee kunnen anderen je vinden en contact met je opnemen zonder je telefoonnummer te weten.<![CDATA[<br><br>]]>Je mag <![CDATA[<b>]]>az<![CDATA[</b>]]>, <![CDATA[<b>]]>09<![CDATA[</b>]]> en liggend streepje gebruiken. De minimale lengte is <![CDATA[<b>]]>5<![CDATA[</b>]]> tekens.</string>
<string name="UsernameChecking">Gebruikersnaam controleren.</string>
<string name="UsernameAvailable">%1$s is beschikbaar.</string>
<string name="UsernameEmpty">None</string>
<string name="ErrorOccurred">An error occurred</string>
<string name="UsernameEmpty">Geen</string>
<string name="ErrorOccurred">Er is een fout opgetreden.</string>
<!--settings view-->
<string name="ResetNotificationsText">Alle meldingsinstellingen herstellen</string>
<string name="TextSize">Tekstgrootte berichten</string>
@ -384,6 +386,7 @@
<string name="ForwardFromMyName">doorsturen via mijn eigen naam</string>
<string name="SendMessagesToGroup">Berichten naar %1$s verzenden?</string>
<string name="ForwardMessagesToGroup">Berichten naar %1$s doorsturen?</string>
<string name="FeatureUnavailable">Sorry, deze functie is momenteel niet beschikbaar in jouw land.</string>
<!--Intro view-->
<string name="Page1Title">Telegram</string>
<string name="Page2Title">Snel</string>

View file

@ -51,6 +51,7 @@
<string name="DeleteChat">Apagar e sair</string>
<string name="HiddenName">Nome oculto</string>
<string name="SelectChat">Selecione uma Conversa</string>
<string name="PhotoTip">Toque e segure para ver</string>
<string name="CompatibilityChat">%1$s está usando uma versão mais antiga do Telegram, por isso fotos secretas serão mostradas em modo de compatibilidade.\n\nAssim que %2$s atualize o Telegram, fotos com timers de 1 minuto ou menos passarão a funcionar no modo Toque e segure para ver, e você será notificado caso a outra pessoa salve a tela.</string>
<!--broadcasts-->
<string name="BroadcastList">Lista de Broadcast</string>
@ -201,6 +202,7 @@
<string name="NumberUnknown">Desconhecido</string>
<string name="Info">INFO</string>
<string name="Phone">Telefone</string>
<!--usernames-->
<string name="Username">Nome de Usuário</string>
<string name="UsernamePlaceholder">Seu nome de usuário</string>
<string name="UsernameInUse">Desculpe, este usuário já existe.</string>
@ -211,8 +213,8 @@
<string name="UsernameHelp">Você pode escolher um nome de usuário no <![CDATA[<b>]]>Telegram<![CDATA[</b>]]>. Assim, outras pessoas poderão te encontrar pelo nome de usuário e entrar em contato sem precisar saber seu telefone. <![CDATA[<br><br>]]>Você pode usar <![CDATA[<b>]]>az<![CDATA[</b>]]>, <![CDATA[<b>]]>09<![CDATA[</b>]]> e underline. O tamanho mínimo é <![CDATA[<b>]]>5<![CDATA[</b>]]> caracteres.</string>
<string name="UsernameChecking">Verificando nome de usuário...</string>
<string name="UsernameAvailable">%1$s está disponível.</string>
<string name="UsernameEmpty">None</string>
<string name="ErrorOccurred">An error occurred</string>
<string name="UsernameEmpty">Nenhum</string>
<string name="ErrorOccurred">Ocorreu um erro.</string>
<!--settings view-->
<string name="ResetNotificationsText">Restaurar todas as configurações de notificação</string>
<string name="TextSize">Tamanho do texto nas mensagens</string>
@ -384,6 +386,7 @@
<string name="ForwardFromMyName">encaminhar pelo meu nome</string>
<string name="SendMessagesToGroup">Enviar mensagens para %1$s?</string>
<string name="ForwardMessagesToGroup">Encaminhar mensagem para %1$s?</string>
<string name="FeatureUnavailable">Sorry, this feature is currently not available in your country.</string>
<!--Intro view-->
<string name="Page1Title">Telegram</string>
<string name="Page2Title">Rápido</string>

View file

@ -51,6 +51,7 @@
<string name="DeleteChat">Apagar e sair</string>
<string name="HiddenName">Nome oculto</string>
<string name="SelectChat">Selecione uma Conversa</string>
<string name="PhotoTip">Toque e segure para ver</string>
<string name="CompatibilityChat">%1$s está usando uma versão mais antiga do Telegram, por isso fotos secretas serão mostradas em modo de compatibilidade.\n\nAssim que %2$s atualize o Telegram, fotos com timers de 1 minuto ou menos passarão a funcionar no modo Toque e segure para ver, e você será notificado caso a outra pessoa salve a tela.</string>
<!--broadcasts-->
<string name="BroadcastList">Lista de Broadcast</string>
@ -201,6 +202,7 @@
<string name="NumberUnknown">Desconhecido</string>
<string name="Info">INFO</string>
<string name="Phone">Telefone</string>
<!--usernames-->
<string name="Username">Nome de Usuário</string>
<string name="UsernamePlaceholder">Seu nome de usuário</string>
<string name="UsernameInUse">Desculpe, este usuário já existe.</string>
@ -211,8 +213,8 @@
<string name="UsernameHelp">Você pode escolher um nome de usuário no <![CDATA[<b>]]>Telegram<![CDATA[</b>]]>. Assim, outras pessoas poderão te encontrar pelo nome de usuário e entrar em contato sem precisar saber seu telefone. <![CDATA[<br><br>]]>Você pode usar <![CDATA[<b>]]>az<![CDATA[</b>]]>, <![CDATA[<b>]]>09<![CDATA[</b>]]> e underline. O tamanho mínimo é <![CDATA[<b>]]>5<![CDATA[</b>]]> caracteres.</string>
<string name="UsernameChecking">Verificando nome de usuário...</string>
<string name="UsernameAvailable">%1$s está disponível.</string>
<string name="UsernameEmpty">None</string>
<string name="ErrorOccurred">An error occurred</string>
<string name="UsernameEmpty">Nenhum</string>
<string name="ErrorOccurred">Ocorreu um erro.</string>
<!--settings view-->
<string name="ResetNotificationsText">Restaurar todas as configurações de notificação</string>
<string name="TextSize">Tamanho do texto nas mensagens</string>
@ -384,6 +386,7 @@
<string name="ForwardFromMyName">encaminhar pelo meu nome</string>
<string name="SendMessagesToGroup">Enviar mensagens para %1$s?</string>
<string name="ForwardMessagesToGroup">Encaminhar mensagem para %1$s?</string>
<string name="FeatureUnavailable">Sorry, this feature is currently not available in your country.</string>
<!--Intro view-->
<string name="Page1Title">Telegram</string>
<string name="Page2Title">Rápido</string>