mirror of
https://github.com/MGislv/NekoX.git
synced 2024-07-02 10:33:36 +00:00
Database & Configure
This commit is contained in:
parent
9196691935
commit
54ba1537ee
|
@ -0,0 +1,993 @@
|
|||
/*
|
||||
* This is the source code of Telegram for Android v. 5.x.x.
|
||||
* It is licensed under GNU GPL v. 2 or later.
|
||||
* You should have received a copy of the license in this archive (see LICENSE).
|
||||
*
|
||||
* Copyright Nikolai Kudashov, 2013-2018.
|
||||
*/
|
||||
|
||||
package org.telegram.messenger;
|
||||
|
||||
import android.os.SystemClock;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.google.firebase.messaging.FirebaseMessagingService;
|
||||
import com.google.firebase.messaging.RemoteMessage;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.telegram.tgnet.ConnectionsManager;
|
||||
import org.telegram.tgnet.NativeByteBuffer;
|
||||
import org.telegram.tgnet.TLRPC;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
public class GcmPushListenerService extends FirebaseMessagingService {
|
||||
|
||||
public static final int NOTIFICATION_ID = 1;
|
||||
private CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
|
||||
@Override
|
||||
public void onMessageReceived(RemoteMessage message) {
|
||||
String from = message.getFrom();
|
||||
final Map data = message.getData();
|
||||
final long time = message.getSentTime();
|
||||
final long receiveTime = SystemClock.elapsedRealtime();
|
||||
if (BuildVars.LOGS_ENABLED) {
|
||||
FileLog.d("GCM received data: " + data + " from: " + from);
|
||||
}
|
||||
AndroidUtilities.runOnUIThread(() -> {
|
||||
ApplicationLoader.postInitApplication();
|
||||
Utilities.stageQueue.postRunnable(() -> {
|
||||
if (BuildVars.LOGS_ENABLED) {
|
||||
FileLog.d("GCM START PROCESSING");
|
||||
}
|
||||
int currentAccount = -1;
|
||||
String loc_key = null;
|
||||
String jsonString = null;
|
||||
try {
|
||||
Object value = data.get("p");
|
||||
if (!(value instanceof String)) {
|
||||
if (BuildVars.LOGS_ENABLED) {
|
||||
FileLog.d("GCM DECRYPT ERROR 1");
|
||||
}
|
||||
onDecryptError();
|
||||
return;
|
||||
}
|
||||
byte[] bytes = Base64.decode((String) value, Base64.URL_SAFE);
|
||||
NativeByteBuffer buffer = new NativeByteBuffer(bytes.length);
|
||||
buffer.writeBytes(bytes);
|
||||
buffer.position(0);
|
||||
|
||||
if (SharedConfig.pushAuthKeyId == null) {
|
||||
SharedConfig.pushAuthKeyId = new byte[8];
|
||||
byte[] authKeyHash = Utilities.computeSHA1(SharedConfig.pushAuthKey);
|
||||
System.arraycopy(authKeyHash, authKeyHash.length - 8, SharedConfig.pushAuthKeyId, 0, 8);
|
||||
}
|
||||
byte[] inAuthKeyId = new byte[8];
|
||||
buffer.readBytes(inAuthKeyId, true);
|
||||
if (!Arrays.equals(SharedConfig.pushAuthKeyId, inAuthKeyId)) {
|
||||
onDecryptError();
|
||||
if (BuildVars.LOGS_ENABLED) {
|
||||
FileLog.d(String.format(Locale.US, "GCM DECRYPT ERROR 2 k1=%s k2=%s, key=%s", Utilities.bytesToHex(SharedConfig.pushAuthKeyId), Utilities.bytesToHex(inAuthKeyId), Utilities.bytesToHex(SharedConfig.pushAuthKey)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] messageKey = new byte[16];
|
||||
buffer.readBytes(messageKey, true);
|
||||
|
||||
MessageKeyData messageKeyData = MessageKeyData.generateMessageKeyData(SharedConfig.pushAuthKey, messageKey, true, 2);
|
||||
Utilities.aesIgeEncryption(buffer.buffer, messageKeyData.aesKey, messageKeyData.aesIv, false, false, 24, bytes.length - 24);
|
||||
|
||||
byte[] messageKeyFull = Utilities.computeSHA256(SharedConfig.pushAuthKey, 88 + 8, 32, buffer.buffer, 24, buffer.buffer.limit());
|
||||
if (!Utilities.arraysEquals(messageKey, 0, messageKeyFull, 8)) {
|
||||
onDecryptError();
|
||||
if (BuildVars.LOGS_ENABLED) {
|
||||
FileLog.d(String.format("GCM DECRYPT ERROR 3, key = %s", Utilities.bytesToHex(SharedConfig.pushAuthKey)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int len = buffer.readInt32(true);
|
||||
byte[] strBytes = new byte[len];
|
||||
buffer.readBytes(strBytes, true);
|
||||
jsonString = new String(strBytes);
|
||||
JSONObject json = new JSONObject(jsonString);
|
||||
|
||||
if (json.has("loc_key")) {
|
||||
loc_key = json.getString("loc_key");
|
||||
} else {
|
||||
loc_key = "";
|
||||
}
|
||||
|
||||
JSONObject custom;
|
||||
Object object = json.get("custom");
|
||||
if (object instanceof JSONObject) {
|
||||
custom = json.getJSONObject("custom");
|
||||
} else {
|
||||
custom = new JSONObject();
|
||||
}
|
||||
|
||||
Object userIdObject;
|
||||
if (json.has("user_id")) {
|
||||
userIdObject = json.get("user_id");
|
||||
} else {
|
||||
userIdObject = null;
|
||||
}
|
||||
int accountUserId;
|
||||
if (userIdObject == null) {
|
||||
accountUserId = UserConfig.getInstance(UserConfig.selectedAccount).getClientUserId();
|
||||
} else {
|
||||
if (userIdObject instanceof Integer) {
|
||||
accountUserId = (Integer) userIdObject;
|
||||
} else if (userIdObject instanceof String) {
|
||||
accountUserId = Utilities.parseInt((String) userIdObject);
|
||||
} else {
|
||||
accountUserId = UserConfig.getInstance(UserConfig.selectedAccount).getClientUserId();
|
||||
}
|
||||
}
|
||||
int account = UserConfig.selectedAccount;
|
||||
for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) {
|
||||
if (UserConfig.getInstance(a).getClientUserId() == accountUserId) {
|
||||
account = a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
final int accountFinal = currentAccount = account;
|
||||
if (!UserConfig.getInstance(currentAccount).isClientActivated()) {
|
||||
if (BuildVars.LOGS_ENABLED) {
|
||||
FileLog.d("GCM ACCOUNT NOT ACTIVATED");
|
||||
}
|
||||
countDownLatch.countDown();
|
||||
return;
|
||||
}
|
||||
Object obj = data.get("google.sent_time");
|
||||
switch (loc_key) {
|
||||
case "DC_UPDATE": {
|
||||
int dc = custom.getInt("dc");
|
||||
String addr = custom.getString("addr");
|
||||
String[] parts = addr.split(":");
|
||||
if (parts.length != 2) {
|
||||
countDownLatch.countDown();
|
||||
return;
|
||||
}
|
||||
String ip = parts[0];
|
||||
int port = Integer.parseInt(parts[1]);
|
||||
ConnectionsManager.getInstance(currentAccount).applyDatacenterAddress(dc, ip, port);
|
||||
ConnectionsManager.getInstance(currentAccount).resumeNetworkMaybe();
|
||||
countDownLatch.countDown();
|
||||
return;
|
||||
}
|
||||
case "MESSAGE_ANNOUNCEMENT": {
|
||||
TLRPC.TL_updateServiceNotification update = new TLRPC.TL_updateServiceNotification();
|
||||
update.popup = false;
|
||||
update.flags = 2;
|
||||
update.inbox_date = (int) (time / 1000);
|
||||
update.message = json.getString("message");
|
||||
update.type = "announcement";
|
||||
update.media = new TLRPC.TL_messageMediaEmpty();
|
||||
final TLRPC.TL_updates updates = new TLRPC.TL_updates();
|
||||
updates.updates.add(update);
|
||||
Utilities.stageQueue.postRunnable(() -> MessagesController.getInstance(accountFinal).processUpdates(updates, false));
|
||||
ConnectionsManager.getInstance(currentAccount).resumeNetworkMaybe();
|
||||
countDownLatch.countDown();
|
||||
return;
|
||||
}
|
||||
case "SESSION_REVOKE": {
|
||||
AndroidUtilities.runOnUIThread(() -> {
|
||||
if (UserConfig.getInstance(accountFinal).getClientUserId() != 0) {
|
||||
UserConfig.getInstance(accountFinal).clearConfig();
|
||||
MessagesController.getInstance(accountFinal).performLogout(0);
|
||||
}
|
||||
});
|
||||
countDownLatch.countDown();
|
||||
return;
|
||||
}
|
||||
case "GEO_LIVE_PENDING": {
|
||||
//Utilities.stageQueue.postRunnable(() -> LocationController.getInstance(accountFinal).setNewLocationEndWatchTime());
|
||||
countDownLatch.countDown();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int channel_id;
|
||||
int chat_id;
|
||||
int user_id;
|
||||
long dialog_id = 0;
|
||||
boolean scheduled;
|
||||
if (custom.has("channel_id")) {
|
||||
channel_id = custom.getInt("channel_id");
|
||||
dialog_id = -channel_id;
|
||||
} else {
|
||||
channel_id = 0;
|
||||
}
|
||||
if (custom.has("from_id")) {
|
||||
user_id = custom.getInt("from_id");
|
||||
dialog_id = user_id;
|
||||
} else {
|
||||
user_id = 0;
|
||||
}
|
||||
if (custom.has("chat_id")) {
|
||||
chat_id = custom.getInt("chat_id");
|
||||
dialog_id = -chat_id;
|
||||
} else {
|
||||
chat_id = 0;
|
||||
}
|
||||
if (custom.has("encryption_id")) {
|
||||
dialog_id = ((long) custom.getInt("encryption_id")) << 32;
|
||||
}
|
||||
if (custom.has("schedule")) {
|
||||
scheduled = custom.getInt("schedule") == 1;
|
||||
} else {
|
||||
scheduled = false;
|
||||
}
|
||||
if (dialog_id == 0 && "ENCRYPTED_MESSAGE".equals(loc_key)) {
|
||||
dialog_id = -(1L << 32);
|
||||
}
|
||||
boolean canRelease = true;
|
||||
if (dialog_id != 0) {
|
||||
if ("READ_HISTORY".equals(loc_key)) {
|
||||
int max_id = custom.getInt("max_id");
|
||||
final ArrayList<TLRPC.Update> updates = new ArrayList<>();
|
||||
if (BuildVars.LOGS_ENABLED) {
|
||||
FileLog.d("GCM received read notification max_id = " + max_id + " for dialogId = " + dialog_id);
|
||||
}
|
||||
if (channel_id != 0) {
|
||||
TLRPC.TL_updateReadChannelInbox update = new TLRPC.TL_updateReadChannelInbox();
|
||||
update.channel_id = channel_id;
|
||||
update.max_id = max_id;
|
||||
updates.add(update);
|
||||
} else {
|
||||
TLRPC.TL_updateReadHistoryInbox update = new TLRPC.TL_updateReadHistoryInbox();
|
||||
if (user_id != 0) {
|
||||
update.peer = new TLRPC.TL_peerUser();
|
||||
update.peer.user_id = user_id;
|
||||
} else {
|
||||
update.peer = new TLRPC.TL_peerChat();
|
||||
update.peer.chat_id = chat_id;
|
||||
}
|
||||
update.max_id = max_id;
|
||||
updates.add(update);
|
||||
}
|
||||
MessagesController.getInstance(accountFinal).processUpdateArray(updates, null, null, false, 0);
|
||||
} else if ("MESSAGE_DELETED".equals(loc_key)) {
|
||||
String messages = custom.getString("messages");
|
||||
String[] messagesArgs = messages.split(",");
|
||||
SparseArray<ArrayList<Integer>> deletedMessages = new SparseArray<>();
|
||||
ArrayList<Integer> ids = new ArrayList<>();
|
||||
for (int a = 0; a < messagesArgs.length; a++) {
|
||||
ids.add(Utilities.parseInt(messagesArgs[a]));
|
||||
}
|
||||
deletedMessages.put(channel_id, ids);
|
||||
NotificationsController.getInstance(currentAccount).removeDeletedMessagesFromNotifications(deletedMessages);
|
||||
|
||||
MessagesController.getInstance(currentAccount).deleteMessagesByPush(dialog_id, ids, channel_id);
|
||||
if (BuildVars.LOGS_ENABLED) {
|
||||
FileLog.d("GCM received " + loc_key + " for dialogId = " + dialog_id + " mids = " + TextUtils.join(",", ids));
|
||||
}
|
||||
} else if (!TextUtils.isEmpty(loc_key)) {
|
||||
int msg_id;
|
||||
if (custom.has("msg_id")) {
|
||||
msg_id = custom.getInt("msg_id");
|
||||
} else {
|
||||
msg_id = 0;
|
||||
}
|
||||
|
||||
long random_id;
|
||||
if (custom.has("random_id")) {
|
||||
random_id = Utilities.parseLong(custom.getString("random_id"));
|
||||
} else {
|
||||
random_id = 0;
|
||||
}
|
||||
|
||||
boolean processNotification = false;
|
||||
if (msg_id != 0) {
|
||||
Integer currentReadValue = MessagesController.getInstance(currentAccount).dialogs_read_inbox_max.get(dialog_id);
|
||||
if (currentReadValue == null) {
|
||||
currentReadValue = MessagesStorage.getInstance(currentAccount).getDialogReadMax(false, dialog_id);
|
||||
MessagesController.getInstance(accountFinal).dialogs_read_inbox_max.put(dialog_id, currentReadValue);
|
||||
}
|
||||
if (msg_id > currentReadValue) {
|
||||
processNotification = true;
|
||||
}
|
||||
} else if (random_id != 0) {
|
||||
if (!MessagesStorage.getInstance(account).checkMessageByRandomId(random_id)) {
|
||||
processNotification = true;
|
||||
}
|
||||
}
|
||||
if (processNotification) {
|
||||
int chat_from_id;
|
||||
|
||||
if (custom.has("chat_from_id")) {
|
||||
chat_from_id = custom.getInt("chat_from_id");
|
||||
} else {
|
||||
chat_from_id = 0;
|
||||
}
|
||||
boolean mention = custom.has("mention") && custom.getInt("mention") != 0;
|
||||
boolean silent = custom.has("silent") && custom.getInt("silent") != 0;
|
||||
|
||||
String[] args;
|
||||
if (json.has("loc_args")) {
|
||||
JSONArray loc_args = json.getJSONArray("loc_args");
|
||||
args = new String[loc_args.length()];
|
||||
for (int a = 0; a < args.length; a++) {
|
||||
args[a] = loc_args.getString(a);
|
||||
}
|
||||
} else {
|
||||
args = null;
|
||||
}
|
||||
String messageText = null;
|
||||
String message1 = null;
|
||||
String name = args[0];
|
||||
String userName = null;
|
||||
boolean localMessage = false;
|
||||
boolean supergroup = false;
|
||||
boolean pinned = false;
|
||||
boolean channel = false;
|
||||
boolean edited = custom.has("edit_date");
|
||||
if (loc_key.startsWith("CHAT_")) {
|
||||
supergroup = channel_id != 0;
|
||||
userName = name;
|
||||
name = args[1];
|
||||
} else if (loc_key.startsWith("PINNED_")) {
|
||||
supergroup = chat_from_id != 0;
|
||||
pinned = true;
|
||||
} else if (loc_key.startsWith("CHANNEL_")) {
|
||||
channel = true;
|
||||
}
|
||||
|
||||
if (BuildVars.LOGS_ENABLED) {
|
||||
FileLog.d("GCM received message notification " + loc_key + " for dialogId = " + dialog_id + " mid = " + msg_id);
|
||||
}
|
||||
switch (loc_key) {
|
||||
case "MESSAGE_TEXT":
|
||||
case "CHANNEL_MESSAGE_TEXT": {
|
||||
messageText = LocaleController.formatString("NotificationMessageText", R.string.NotificationMessageText, args[0], args[1]);
|
||||
message1 = args[1];
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_NOTEXT": {
|
||||
messageText = LocaleController.formatString("NotificationMessageNoText", R.string.NotificationMessageNoText, args[0]);
|
||||
message1 = LocaleController.getString("Message", R.string.Message);
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_PHOTO": {
|
||||
messageText = LocaleController.formatString("NotificationMessagePhoto", R.string.NotificationMessagePhoto, args[0]);
|
||||
message1 = LocaleController.getString("AttachPhoto", R.string.AttachPhoto);
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_PHOTO_SECRET": {
|
||||
messageText = LocaleController.formatString("NotificationMessageSDPhoto", R.string.NotificationMessageSDPhoto, args[0]);
|
||||
message1 = LocaleController.getString("AttachDestructingPhoto", R.string.AttachDestructingPhoto);
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_VIDEO": {
|
||||
messageText = LocaleController.formatString("NotificationMessageVideo", R.string.NotificationMessageVideo, args[0]);
|
||||
message1 = LocaleController.getString("AttachVideo", R.string.AttachVideo);
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_VIDEO_SECRET": {
|
||||
messageText = LocaleController.formatString("NotificationMessageSDVideo", R.string.NotificationMessageSDVideo, args[0]);
|
||||
message1 = LocaleController.getString("AttachDestructingVideo", R.string.AttachDestructingVideo);
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_SCREENSHOT": {
|
||||
messageText = LocaleController.getString("ActionTakeScreenshoot", R.string.ActionTakeScreenshoot).replace("un1", args[0]);
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_ROUND": {
|
||||
messageText = LocaleController.formatString("NotificationMessageRound", R.string.NotificationMessageRound, args[0]);
|
||||
message1 = LocaleController.getString("AttachRound", R.string.AttachRound);
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_DOC": {
|
||||
messageText = LocaleController.formatString("NotificationMessageDocument", R.string.NotificationMessageDocument, args[0]);
|
||||
message1 = LocaleController.getString("AttachDocument", R.string.AttachDocument);
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_STICKER": {
|
||||
if (args.length > 1 && !TextUtils.isEmpty(args[1])) {
|
||||
messageText = LocaleController.formatString("NotificationMessageStickerEmoji", R.string.NotificationMessageStickerEmoji, args[0], args[1]);
|
||||
message1 = args[1] + " " + LocaleController.getString("AttachSticker", R.string.AttachSticker);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationMessageSticker", R.string.NotificationMessageSticker, args[0]);
|
||||
message1 = LocaleController.getString("AttachSticker", R.string.AttachSticker);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_AUDIO": {
|
||||
messageText = LocaleController.formatString("NotificationMessageAudio", R.string.NotificationMessageAudio, args[0]);
|
||||
message1 = LocaleController.getString("AttachAudio", R.string.AttachAudio);
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_CONTACT": {
|
||||
messageText = LocaleController.formatString("NotificationMessageContact2", R.string.NotificationMessageContact2, args[0], args[1]);
|
||||
message1 = LocaleController.getString("AttachContact", R.string.AttachContact);
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_QUIZ": {
|
||||
messageText = LocaleController.formatString("NotificationMessageQuiz2", R.string.NotificationMessageQuiz2, args[0], args[1]);
|
||||
message1 = LocaleController.getString("QuizPoll", R.string.QuizPoll);
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_POLL": {
|
||||
messageText = LocaleController.formatString("NotificationMessagePoll2", R.string.NotificationMessagePoll2, args[0], args[1]);
|
||||
message1 = LocaleController.getString("Poll", R.string.Poll);
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_GEO": {
|
||||
messageText = LocaleController.formatString("NotificationMessageMap", R.string.NotificationMessageMap, args[0]);
|
||||
message1 = LocaleController.getString("AttachLocation", R.string.AttachLocation);
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_GEOLIVE": {
|
||||
messageText = LocaleController.formatString("NotificationMessageLiveLocation", R.string.NotificationMessageLiveLocation, args[0]);
|
||||
message1 = LocaleController.getString("AttachLiveLocation", R.string.AttachLiveLocation);
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_GIF": {
|
||||
messageText = LocaleController.formatString("NotificationMessageGif", R.string.NotificationMessageGif, args[0]);
|
||||
message1 = LocaleController.getString("AttachGif", R.string.AttachGif);
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_GAME": {
|
||||
messageText = LocaleController.formatString("NotificationMessageGame", R.string.NotificationMessageGame, args[0], args[1]);
|
||||
message1 = LocaleController.getString("AttachGame", R.string.AttachGame);
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_GAME_SCORE":
|
||||
case "CHANNEL_MESSAGE_GAME_SCORE": {
|
||||
messageText = LocaleController.formatString("NotificationMessageGameScored", R.string.NotificationMessageGameScored, args[0], args[1], args[2]);
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_INVOICE": {
|
||||
messageText = LocaleController.formatString("NotificationMessageInvoice", R.string.NotificationMessageInvoice, args[0], args[1]);
|
||||
message1 = LocaleController.getString("PaymentInvoice", R.string.PaymentInvoice);
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_FWDS": {
|
||||
messageText = LocaleController.formatString("NotificationMessageForwardFew", R.string.NotificationMessageForwardFew, args[0], LocaleController.formatPluralString("messages", Utilities.parseInt(args[1])));
|
||||
localMessage = true;
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_PHOTOS": {
|
||||
messageText = LocaleController.formatString("NotificationMessageFew", R.string.NotificationMessageFew, args[0], LocaleController.formatPluralString("Photos", Utilities.parseInt(args[1])));
|
||||
localMessage = true;
|
||||
break;
|
||||
}
|
||||
case "MESSAGE_VIDEOS": {
|
||||
messageText = LocaleController.formatString("NotificationMessageFew", R.string.NotificationMessageFew, args[0], LocaleController.formatPluralString("Videos", Utilities.parseInt(args[1])));
|
||||
localMessage = true;
|
||||
break;
|
||||
}
|
||||
case "MESSAGES": {
|
||||
messageText = LocaleController.formatString("NotificationMessageAlbum", R.string.NotificationMessageAlbum, args[0]);
|
||||
localMessage = true;
|
||||
break;
|
||||
}
|
||||
case "CHANNEL_MESSAGE_NOTEXT": {
|
||||
messageText = LocaleController.formatString("ChannelMessageNoText", R.string.ChannelMessageNoText, args[0]);
|
||||
message1 = LocaleController.getString("Message", R.string.Message);
|
||||
break;
|
||||
}
|
||||
case "CHANNEL_MESSAGE_PHOTO": {
|
||||
messageText = LocaleController.formatString("ChannelMessagePhoto", R.string.ChannelMessagePhoto, args[0]);
|
||||
message1 = LocaleController.getString("AttachPhoto", R.string.AttachPhoto);
|
||||
break;
|
||||
}
|
||||
case "CHANNEL_MESSAGE_VIDEO": {
|
||||
messageText = LocaleController.formatString("ChannelMessageVideo", R.string.ChannelMessageVideo, args[0]);
|
||||
message1 = LocaleController.getString("AttachVideo", R.string.AttachVideo);
|
||||
break;
|
||||
}
|
||||
case "CHANNEL_MESSAGE_ROUND": {
|
||||
messageText = LocaleController.formatString("ChannelMessageRound", R.string.ChannelMessageRound, args[0]);
|
||||
message1 = LocaleController.getString("AttachRound", R.string.AttachRound);
|
||||
break;
|
||||
}
|
||||
case "CHANNEL_MESSAGE_DOC": {
|
||||
messageText = LocaleController.formatString("ChannelMessageDocument", R.string.ChannelMessageDocument, args[0]);
|
||||
message1 = LocaleController.getString("AttachDocument", R.string.AttachDocument);
|
||||
break;
|
||||
}
|
||||
case "CHANNEL_MESSAGE_STICKER": {
|
||||
if (args.length > 1 && !TextUtils.isEmpty(args[1])) {
|
||||
messageText = LocaleController.formatString("ChannelMessageStickerEmoji", R.string.ChannelMessageStickerEmoji, args[0], args[1]);
|
||||
message1 = args[1] + " " + LocaleController.getString("AttachSticker", R.string.AttachSticker);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("ChannelMessageSticker", R.string.ChannelMessageSticker, args[0]);
|
||||
message1 = LocaleController.getString("AttachSticker", R.string.AttachSticker);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "CHANNEL_MESSAGE_AUDIO": {
|
||||
messageText = LocaleController.formatString("ChannelMessageAudio", R.string.ChannelMessageAudio, args[0]);
|
||||
message1 = LocaleController.getString("AttachAudio", R.string.AttachAudio);
|
||||
break;
|
||||
}
|
||||
case "CHANNEL_MESSAGE_CONTACT": {
|
||||
messageText = LocaleController.formatString("ChannelMessageContact2", R.string.ChannelMessageContact2, args[0], args[1]);
|
||||
message1 = LocaleController.getString("AttachContact", R.string.AttachContact);
|
||||
break;
|
||||
}
|
||||
case "CHANNEL_MESSAGE_QUIZ": {
|
||||
messageText = LocaleController.formatString("ChannelMessageQuiz2", R.string.ChannelMessageQuiz2, args[0], args[1]);
|
||||
message1 = LocaleController.getString("QuizPoll", R.string.QuizPoll);
|
||||
break;
|
||||
}
|
||||
case "CHANNEL_MESSAGE_POLL": {
|
||||
messageText = LocaleController.formatString("ChannelMessagePoll2", R.string.ChannelMessagePoll2, args[0], args[1]);
|
||||
message1 = LocaleController.getString("Poll", R.string.Poll);
|
||||
break;
|
||||
}
|
||||
case "CHANNEL_MESSAGE_GEO": {
|
||||
messageText = LocaleController.formatString("ChannelMessageMap", R.string.ChannelMessageMap, args[0]);
|
||||
message1 = LocaleController.getString("AttachLocation", R.string.AttachLocation);
|
||||
break;
|
||||
}
|
||||
case "CHANNEL_MESSAGE_GEOLIVE": {
|
||||
messageText = LocaleController.formatString("ChannelMessageLiveLocation", R.string.ChannelMessageLiveLocation, args[0]);
|
||||
message1 = LocaleController.getString("AttachLiveLocation", R.string.AttachLiveLocation);
|
||||
break;
|
||||
}
|
||||
case "CHANNEL_MESSAGE_GIF": {
|
||||
messageText = LocaleController.formatString("ChannelMessageGIF", R.string.ChannelMessageGIF, args[0]);
|
||||
message1 = LocaleController.getString("AttachGif", R.string.AttachGif);
|
||||
break;
|
||||
}
|
||||
case "CHANNEL_MESSAGE_GAME": {
|
||||
messageText = LocaleController.formatString("NotificationMessageGame", R.string.NotificationMessageGame, args[0]);
|
||||
message1 = LocaleController.getString("AttachGame", R.string.AttachGame);
|
||||
break;
|
||||
}
|
||||
case "CHANNEL_MESSAGE_FWDS": {
|
||||
messageText = LocaleController.formatString("ChannelMessageFew", R.string.ChannelMessageFew, args[0], LocaleController.formatPluralString("ForwardedMessageCount", Utilities.parseInt(args[1])).toLowerCase());
|
||||
localMessage = true;
|
||||
break;
|
||||
}
|
||||
case "CHANNEL_MESSAGE_PHOTOS": {
|
||||
messageText = LocaleController.formatString("ChannelMessageFew", R.string.ChannelMessageFew, args[0], LocaleController.formatPluralString("Photos", Utilities.parseInt(args[1])));
|
||||
localMessage = true;
|
||||
break;
|
||||
}
|
||||
case "CHANNEL_MESSAGE_VIDEOS": {
|
||||
messageText = LocaleController.formatString("ChannelMessageFew", R.string.ChannelMessageFew, args[0], LocaleController.formatPluralString("Videos", Utilities.parseInt(args[1])));
|
||||
localMessage = true;
|
||||
break;
|
||||
}
|
||||
case "CHANNEL_MESSAGES": {
|
||||
messageText = LocaleController.formatString("ChannelMessageAlbum", R.string.ChannelMessageAlbum, args[0]);
|
||||
localMessage = true;
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGE_TEXT": {
|
||||
messageText = LocaleController.formatString("NotificationMessageGroupText", R.string.NotificationMessageGroupText, args[0], args[1], args[2]);
|
||||
message1 = args[2];
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGE_NOTEXT": {
|
||||
messageText = LocaleController.formatString("NotificationMessageGroupNoText", R.string.NotificationMessageGroupNoText, args[0], args[1]);
|
||||
message1 = LocaleController.getString("Message", R.string.Message);
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGE_PHOTO": {
|
||||
messageText = LocaleController.formatString("NotificationMessageGroupPhoto", R.string.NotificationMessageGroupPhoto, args[0], args[1]);
|
||||
message1 = LocaleController.getString("AttachPhoto", R.string.AttachPhoto);
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGE_VIDEO": {
|
||||
messageText = LocaleController.formatString("NotificationMessageGroupVideo", R.string.NotificationMessageGroupVideo, args[0], args[1]);
|
||||
message1 = LocaleController.getString("AttachVideo", R.string.AttachVideo);
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGE_ROUND": {
|
||||
messageText = LocaleController.formatString("NotificationMessageGroupRound", R.string.NotificationMessageGroupRound, args[0], args[1]);
|
||||
message1 = LocaleController.getString("AttachRound", R.string.AttachRound);
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGE_DOC": {
|
||||
messageText = LocaleController.formatString("NotificationMessageGroupDocument", R.string.NotificationMessageGroupDocument, args[0], args[1]);
|
||||
message1 = LocaleController.getString("AttachDocument", R.string.AttachDocument);
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGE_STICKER": {
|
||||
if (args.length > 2 && !TextUtils.isEmpty(args[2])) {
|
||||
messageText = LocaleController.formatString("NotificationMessageGroupStickerEmoji", R.string.NotificationMessageGroupStickerEmoji, args[0], args[1], args[2]);
|
||||
message1 = args[2] + " " + LocaleController.getString("AttachSticker", R.string.AttachSticker);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationMessageGroupSticker", R.string.NotificationMessageGroupSticker, args[0], args[1]);
|
||||
message1 = args[1] + " " + LocaleController.getString("AttachSticker", R.string.AttachSticker);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGE_AUDIO": {
|
||||
messageText = LocaleController.formatString("NotificationMessageGroupAudio", R.string.NotificationMessageGroupAudio, args[0], args[1]);
|
||||
message1 = LocaleController.getString("AttachAudio", R.string.AttachAudio);
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGE_CONTACT": {
|
||||
messageText = LocaleController.formatString("NotificationMessageGroupContact2", R.string.NotificationMessageGroupContact2, args[0], args[1], args[2]);
|
||||
message1 = LocaleController.getString("AttachContact", R.string.AttachContact);
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGE_QUIZ": {
|
||||
messageText = LocaleController.formatString("NotificationMessageGroupQuiz2", R.string.NotificationMessageGroupQuiz2, args[0], args[1], args[2]);
|
||||
message1 = LocaleController.getString("PollQuiz", R.string.PollQuiz);
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGE_POLL": {
|
||||
messageText = LocaleController.formatString("NotificationMessageGroupPoll2", R.string.NotificationMessageGroupPoll2, args[0], args[1], args[2]);
|
||||
message1 = LocaleController.getString("Poll", R.string.Poll);
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGE_GEO": {
|
||||
messageText = LocaleController.formatString("NotificationMessageGroupMap", R.string.NotificationMessageGroupMap, args[0], args[1]);
|
||||
message1 = LocaleController.getString("AttachLocation", R.string.AttachLocation);
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGE_GEOLIVE": {
|
||||
messageText = LocaleController.formatString("NotificationMessageGroupLiveLocation", R.string.NotificationMessageGroupLiveLocation, args[0], args[1]);
|
||||
message1 = LocaleController.getString("AttachLiveLocation", R.string.AttachLiveLocation);
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGE_GIF": {
|
||||
messageText = LocaleController.formatString("NotificationMessageGroupGif", R.string.NotificationMessageGroupGif, args[0], args[1]);
|
||||
message1 = LocaleController.getString("AttachGif", R.string.AttachGif);
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGE_GAME": {
|
||||
messageText = LocaleController.formatString("NotificationMessageGroupGame", R.string.NotificationMessageGroupGame, args[0], args[1], args[2]);
|
||||
message1 = LocaleController.getString("AttachGame", R.string.AttachGame);
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGE_GAME_SCORE": {
|
||||
messageText = LocaleController.formatString("NotificationMessageGroupGameScored", R.string.NotificationMessageGroupGameScored, args[0], args[1], args[2], args[3]);
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGE_INVOICE": {
|
||||
messageText = LocaleController.formatString("NotificationMessageGroupInvoice", R.string.NotificationMessageGroupInvoice, args[0], args[1], args[2]);
|
||||
message1 = LocaleController.getString("PaymentInvoice", R.string.PaymentInvoice);
|
||||
break;
|
||||
}
|
||||
case "CHAT_CREATED":
|
||||
case "CHAT_ADD_YOU": {
|
||||
messageText = LocaleController.formatString("NotificationInvitedToGroup", R.string.NotificationInvitedToGroup, args[0], args[1]);
|
||||
break;
|
||||
}
|
||||
case "CHAT_TITLE_EDITED": {
|
||||
messageText = LocaleController.formatString("NotificationEditedGroupName", R.string.NotificationEditedGroupName, args[0], args[1]);
|
||||
break;
|
||||
}
|
||||
case "CHAT_PHOTO_EDITED": {
|
||||
messageText = LocaleController.formatString("NotificationEditedGroupPhoto", R.string.NotificationEditedGroupPhoto, args[0], args[1]);
|
||||
break;
|
||||
}
|
||||
case "CHAT_ADD_MEMBER": {
|
||||
messageText = LocaleController.formatString("NotificationGroupAddMember", R.string.NotificationGroupAddMember, args[0], args[1], args[2]);
|
||||
break;
|
||||
}
|
||||
case "CHAT_DELETE_MEMBER": {
|
||||
messageText = LocaleController.formatString("NotificationGroupKickMember", R.string.NotificationGroupKickMember, args[0], args[1]);
|
||||
break;
|
||||
}
|
||||
case "CHAT_DELETE_YOU": {
|
||||
messageText = LocaleController.formatString("NotificationGroupKickYou", R.string.NotificationGroupKickYou, args[0], args[1]);
|
||||
break;
|
||||
}
|
||||
case "CHAT_LEFT": {
|
||||
messageText = LocaleController.formatString("NotificationGroupLeftMember", R.string.NotificationGroupLeftMember, args[0], args[1]);
|
||||
break;
|
||||
}
|
||||
case "CHAT_RETURNED": {
|
||||
messageText = LocaleController.formatString("NotificationGroupAddSelf", R.string.NotificationGroupAddSelf, args[0], args[1]);
|
||||
break;
|
||||
}
|
||||
case "CHAT_JOINED": {
|
||||
messageText = LocaleController.formatString("NotificationGroupAddSelfMega", R.string.NotificationGroupAddSelfMega, args[0], args[1]);
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGE_FWDS": {
|
||||
messageText = LocaleController.formatString("NotificationGroupForwardedFew", R.string.NotificationGroupForwardedFew, args[0], args[1], LocaleController.formatPluralString("messages", Utilities.parseInt(args[2])));
|
||||
localMessage = true;
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGE_PHOTOS": {
|
||||
messageText = LocaleController.formatString("NotificationGroupFew", R.string.NotificationGroupFew, args[0], args[1], LocaleController.formatPluralString("Photos", Utilities.parseInt(args[2])));
|
||||
localMessage = true;
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGE_VIDEOS": {
|
||||
messageText = LocaleController.formatString("NotificationGroupFew", R.string.NotificationGroupFew, args[0], args[1], LocaleController.formatPluralString("Videos", Utilities.parseInt(args[2])));
|
||||
localMessage = true;
|
||||
break;
|
||||
}
|
||||
case "CHAT_MESSAGES": {
|
||||
messageText = LocaleController.formatString("NotificationGroupAlbum", R.string.NotificationGroupAlbum, args[0], args[1]);
|
||||
localMessage = true;
|
||||
break;
|
||||
}
|
||||
case "PINNED_TEXT": {
|
||||
if (chat_from_id != 0) {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedText", R.string.NotificationActionPinnedText, args[0], args[1], args[2]);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedTextChannel", R.string.NotificationActionPinnedTextChannel, args[0], args[1]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PINNED_NOTEXT": {
|
||||
if (chat_from_id != 0) {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedNoText", R.string.NotificationActionPinnedNoText, args[0], args[1]);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedNoTextChannel", R.string.NotificationActionPinnedNoTextChannel, args[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PINNED_PHOTO": {
|
||||
if (chat_from_id != 0) {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedPhoto", R.string.NotificationActionPinnedPhoto, args[0], args[1]);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedPhotoChannel", R.string.NotificationActionPinnedPhotoChannel, args[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PINNED_VIDEO": {
|
||||
if (chat_from_id != 0) {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedVideo", R.string.NotificationActionPinnedVideo, args[0], args[1]);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedVideoChannel", R.string.NotificationActionPinnedVideoChannel, args[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PINNED_ROUND": {
|
||||
if (chat_from_id != 0) {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedRound", R.string.NotificationActionPinnedRound, args[0], args[1]);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedRoundChannel", R.string.NotificationActionPinnedRoundChannel, args[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PINNED_DOC": {
|
||||
if (chat_from_id != 0) {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedFile", R.string.NotificationActionPinnedFile, args[0], args[1]);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedFileChannel", R.string.NotificationActionPinnedFileChannel, args[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PINNED_STICKER": {
|
||||
if (chat_from_id != 0) {
|
||||
if (args.length > 2 && !TextUtils.isEmpty(args[2])) {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedStickerEmoji", R.string.NotificationActionPinnedStickerEmoji, args[0], args[2], args[1]);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedSticker", R.string.NotificationActionPinnedSticker, args[0], args[1]);
|
||||
}
|
||||
} else {
|
||||
if (args.length > 1 && !TextUtils.isEmpty(args[1])) {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedStickerEmojiChannel", R.string.NotificationActionPinnedStickerEmojiChannel, args[0], args[1]);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedStickerChannel", R.string.NotificationActionPinnedStickerChannel, args[0]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PINNED_AUDIO": {
|
||||
if (chat_from_id != 0) {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedVoice", R.string.NotificationActionPinnedVoice, args[0], args[1]);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedVoiceChannel", R.string.NotificationActionPinnedVoiceChannel, args[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PINNED_CONTACT": {
|
||||
if (chat_from_id != 0) {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedContact2", R.string.NotificationActionPinnedContact2, args[0], args[2], args[1]);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedContactChannel2", R.string.NotificationActionPinnedContactChannel2, args[0], args[1]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PINNED_QUIZ": {
|
||||
if (chat_from_id != 0) {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedQuiz2", R.string.NotificationActionPinnedQuiz2, args[0], args[2], args[1]);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedQuizChannel2", R.string.NotificationActionPinnedQuizChannel2, args[0], args[1]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PINNED_POLL": {
|
||||
if (chat_from_id != 0) {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedPoll2", R.string.NotificationActionPinnedPoll2, args[0], args[2], args[1]);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedPollChannel2", R.string.NotificationActionPinnedPollChannel2, args[0], args[1]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PINNED_GEO": {
|
||||
if (chat_from_id != 0) {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedGeo", R.string.NotificationActionPinnedGeo, args[0], args[1]);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedGeoChannel", R.string.NotificationActionPinnedGeoChannel, args[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PINNED_GEOLIVE": {
|
||||
if (chat_from_id != 0) {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedGeoLive", R.string.NotificationActionPinnedGeoLive, args[0], args[1]);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedGeoLiveChannel", R.string.NotificationActionPinnedGeoLiveChannel, args[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PINNED_GAME": {
|
||||
if (chat_from_id != 0) {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedGame", R.string.NotificationActionPinnedGame, args[0], args[1]);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedGameChannel", R.string.NotificationActionPinnedGameChannel, args[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PINNED_GAME_SCORE": {
|
||||
if (chat_from_id != 0) {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedGameScore", R.string.NotificationActionPinnedGameScore, args[0], args[1]);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedGameScoreChannel", R.string.NotificationActionPinnedGameScoreChannel, args[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PINNED_INVOICE": {
|
||||
if (chat_from_id != 0) {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedInvoice", R.string.NotificationActionPinnedInvoice, args[0], args[1]);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedInvoiceChannel", R.string.NotificationActionPinnedInvoiceChannel, args[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PINNED_GIF": {
|
||||
if (chat_from_id != 0) {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedGif", R.string.NotificationActionPinnedGif, args[0], args[1]);
|
||||
} else {
|
||||
messageText = LocaleController.formatString("NotificationActionPinnedGifChannel", R.string.NotificationActionPinnedGifChannel, args[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "ENCRYPTED_MESSAGE": {
|
||||
messageText = LocaleController.getString("YouHaveNewMessage", R.string.YouHaveNewMessage);
|
||||
name = LocaleController.getString("SecretChatName", R.string.SecretChatName);
|
||||
localMessage = true;
|
||||
break;
|
||||
}
|
||||
case "CONTACT_JOINED":
|
||||
case "AUTH_UNKNOWN":
|
||||
case "AUTH_REGION":
|
||||
case "LOCKED_MESSAGE":
|
||||
case "ENCRYPTION_REQUEST":
|
||||
case "ENCRYPTION_ACCEPT":
|
||||
case "PHONE_CALL_REQUEST":
|
||||
case "MESSAGE_MUTED":
|
||||
case "PHONE_CALL_MISSED": {
|
||||
//ignored
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (BuildVars.LOGS_ENABLED) {
|
||||
FileLog.w("unhandled loc_key = " + loc_key);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (messageText != null) {
|
||||
TLRPC.TL_message messageOwner = new TLRPC.TL_message();
|
||||
messageOwner.id = msg_id;
|
||||
messageOwner.random_id = random_id;
|
||||
messageOwner.message = message1 != null ? message1 : messageText;
|
||||
messageOwner.date = (int) (time / 1000);
|
||||
if (pinned) {
|
||||
messageOwner.action = new TLRPC.TL_messageActionPinMessage();
|
||||
}
|
||||
if (supergroup) {
|
||||
messageOwner.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP;
|
||||
}
|
||||
messageOwner.dialog_id = dialog_id;
|
||||
if (channel_id != 0) {
|
||||
messageOwner.to_id = new TLRPC.TL_peerChannel();
|
||||
messageOwner.to_id.channel_id = channel_id;
|
||||
} else if (chat_id != 0) {
|
||||
messageOwner.to_id = new TLRPC.TL_peerChat();
|
||||
messageOwner.to_id.chat_id = chat_id;
|
||||
} else {
|
||||
messageOwner.to_id = new TLRPC.TL_peerUser();
|
||||
messageOwner.to_id.user_id = user_id;
|
||||
}
|
||||
messageOwner.flags |= 256;
|
||||
messageOwner.from_id = chat_from_id;
|
||||
messageOwner.mentioned = mention || pinned;
|
||||
messageOwner.silent = silent;
|
||||
messageOwner.from_scheduled = scheduled;
|
||||
|
||||
MessageObject messageObject = new MessageObject(currentAccount, messageOwner, messageText, name, userName, localMessage, channel, edited);
|
||||
ArrayList<MessageObject> arrayList = new ArrayList<>();
|
||||
arrayList.add(messageObject);
|
||||
canRelease = false;
|
||||
NotificationsController.getInstance(currentAccount).processNewMessages(arrayList, true, true, countDownLatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (canRelease) {
|
||||
countDownLatch.countDown();
|
||||
}
|
||||
|
||||
ConnectionsManager.onInternalPushReceived(currentAccount);
|
||||
ConnectionsManager.getInstance(currentAccount).resumeNetworkMaybe();
|
||||
} catch (Throwable e) {
|
||||
if (currentAccount != -1) {
|
||||
ConnectionsManager.onInternalPushReceived(currentAccount);
|
||||
ConnectionsManager.getInstance(currentAccount).resumeNetworkMaybe();
|
||||
countDownLatch.countDown();
|
||||
} else {
|
||||
onDecryptError();
|
||||
}
|
||||
if (BuildVars.LOGS_ENABLED) {
|
||||
FileLog.e("error in loc_key = " + loc_key + " json " + jsonString);
|
||||
}
|
||||
FileLog.e(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
try {
|
||||
countDownLatch.await();
|
||||
} catch (Throwable ignore) {
|
||||
|
||||
}
|
||||
if (BuildVars.DEBUG_VERSION) {
|
||||
FileLog.d("finished GCM service, time = " + (SystemClock.elapsedRealtime() - receiveTime));
|
||||
}
|
||||
}
|
||||
|
||||
private void onDecryptError() {
|
||||
for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) {
|
||||
if (UserConfig.getInstance(a).isClientActivated()) {
|
||||
ConnectionsManager.onInternalPushReceived(a);
|
||||
ConnectionsManager.getInstance(a).resumeNetworkMaybe();
|
||||
}
|
||||
}
|
||||
countDownLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewToken(String token) {
|
||||
AndroidUtilities.runOnUIThread(() -> {
|
||||
if (BuildVars.LOGS_ENABLED) {
|
||||
FileLog.d("Refreshed token: " + token);
|
||||
}
|
||||
ApplicationLoader.postInitApplication();
|
||||
sendRegistrationToServer(token);
|
||||
});
|
||||
}
|
||||
|
||||
public static void sendRegistrationToServer(final String token) {
|
||||
Utilities.stageQueue.postRunnable(() -> {
|
||||
ConnectionsManager.setRegId(token, SharedConfig.pushStringStatus);
|
||||
if (token == null) {
|
||||
return;
|
||||
}
|
||||
SharedConfig.pushString = token;
|
||||
for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) {
|
||||
UserConfig userConfig = UserConfig.getInstance(a);
|
||||
userConfig.registeredForPush = false;
|
||||
userConfig.saveConfig(false);
|
||||
if (userConfig.getClientUserId() != 0) {
|
||||
final int currentAccount = a;
|
||||
AndroidUtilities.runOnUIThread(() -> MessagesController.getInstance(currentAccount).registerForPush(token));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
package org.telegram.ui.Cells;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.Property;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.telegram.messenger.AndroidUtilities;
|
||||
import org.telegram.messenger.LocaleController;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.ui.ActionBar.Theme;
|
||||
import org.telegram.ui.Components.AnimationProperties;
|
||||
import org.telegram.ui.Components.CubicBezierInterpolator;
|
||||
import org.telegram.ui.Components.LayoutHelper;
|
||||
import org.telegram.ui.Components.Switch;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class DrawerActionCheckCell extends FrameLayout {
|
||||
|
||||
private TextView textView;
|
||||
public Switch checkBox;
|
||||
private int height = 48;
|
||||
private int animatedColorBackground;
|
||||
private float animationProgress;
|
||||
private Paint animationPaint;
|
||||
private float lastTouchX;
|
||||
private ObjectAnimator animator;
|
||||
private boolean drawCheckRipple;
|
||||
|
||||
public static final Property<DrawerActionCheckCell, Float> ANIMATION_PROGRESS = new AnimationProperties.FloatProperty<DrawerActionCheckCell>("animationProgress") {
|
||||
@Override
|
||||
public void setValue(DrawerActionCheckCell object, float value) {
|
||||
object.setAnimationProgress(value);
|
||||
object.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(DrawerActionCheckCell object) {
|
||||
return object.animationProgress;
|
||||
}
|
||||
};
|
||||
|
||||
public DrawerActionCheckCell(Context context) {
|
||||
this(context, 21);
|
||||
}
|
||||
|
||||
public DrawerActionCheckCell(Context context, int padding) {
|
||||
super(context);
|
||||
|
||||
textView = new TextView(context);
|
||||
textView.setTextColor(Theme.getColor(Theme.key_chats_menuItemText));
|
||||
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
|
||||
textView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
|
||||
textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
|
||||
textView.setLines(1);
|
||||
textView.setMaxLines(1);
|
||||
textView.setSingleLine(true);
|
||||
|
||||
addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, padding, 0, 70, 0));
|
||||
|
||||
checkBox = new Switch(context);
|
||||
checkBox.setColors(Theme.key_switchTrack, Theme.key_switchTrackChecked, Theme.key_windowBackgroundWhite, Theme.key_windowBackgroundWhite);
|
||||
addView(checkBox, LayoutHelper.createFrame(37, 20, Gravity.RIGHT | Gravity.CENTER_VERTICAL, 22, 0, 22, 0));
|
||||
|
||||
setClipChildren(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(height), MeasureSpec.EXACTLY));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
lastTouchX = event.getX();
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
public void setTextAndCheck(String text, boolean checked, boolean divider) {
|
||||
textView.setText(text);
|
||||
checkBox.setChecked(checked, false);
|
||||
LayoutParams layoutParams = (LayoutParams) textView.getLayoutParams();
|
||||
layoutParams.height = LayoutParams.MATCH_PARENT;
|
||||
layoutParams.topMargin = 0;
|
||||
textView.setLayoutParams(layoutParams);
|
||||
setWillNotDraw(!divider);
|
||||
}
|
||||
|
||||
public void setColors(String key, String switchKey, String switchKeyChecked, String switchThumb, String switchThumbChecked) {
|
||||
textView.setTextColor(Theme.getColor(key));
|
||||
checkBox.setColors(switchKey, switchKeyChecked, switchThumb, switchThumbChecked);
|
||||
textView.setTag(key);
|
||||
}
|
||||
|
||||
public void setTypeface(Typeface typeface) {
|
||||
textView.setTypeface(typeface);
|
||||
}
|
||||
|
||||
public void setHeight(int value) {
|
||||
height = value;
|
||||
}
|
||||
|
||||
public void setDrawCheckRipple(boolean value) {
|
||||
drawCheckRipple = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPressed(boolean pressed) {
|
||||
if (drawCheckRipple) {
|
||||
checkBox.setDrawRipple(pressed);
|
||||
}
|
||||
super.setPressed(pressed);
|
||||
}
|
||||
|
||||
public void setOnCheckChangeListener(Switch.OnCheckedChangeListener listener) {
|
||||
checkBox.setOnCheckedChangeListener(listener);
|
||||
}
|
||||
|
||||
public void setOnCheckClickListener(View.OnClickListener listener) {
|
||||
checkBox.setOnClickListener(listener);
|
||||
}
|
||||
|
||||
public void setTextAndValueAndCheck(String text, int resId, String value, boolean checked, boolean multiline, boolean divider) {
|
||||
textView.setText(text);
|
||||
Drawable drawable = getResources().getDrawable(resId).mutate();
|
||||
drawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chats_menuItemIcon), PorterDuff.Mode.SRC_IN));
|
||||
textView.setCompoundDrawablePadding(AndroidUtilities.dp(29));
|
||||
textView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);
|
||||
checkBox.setChecked(checked, false);
|
||||
LayoutParams layoutParams = (LayoutParams) textView.getLayoutParams();
|
||||
layoutParams.height = LayoutParams.WRAP_CONTENT;
|
||||
layoutParams.topMargin = AndroidUtilities.dp(10);
|
||||
textView.setLayoutParams(layoutParams);
|
||||
setWillNotDraw(!divider);
|
||||
}
|
||||
|
||||
public void setEnabled(boolean value, ArrayList<Animator> animators) {
|
||||
super.setEnabled(value);
|
||||
if (animators != null) {
|
||||
animators.add(ObjectAnimator.ofFloat(textView, "alpha", value ? 1.0f : 0.5f));
|
||||
animators.add(ObjectAnimator.ofFloat(checkBox, "alpha", value ? 1.0f : 0.5f));
|
||||
} else {
|
||||
textView.setAlpha(value ? 1.0f : 0.5f);
|
||||
checkBox.setAlpha(value ? 1.0f : 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
public void setChecked(boolean checked) {
|
||||
checkBox.setChecked(checked, true);
|
||||
}
|
||||
|
||||
public boolean isChecked() {
|
||||
return checkBox.isChecked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackgroundColor(int color) {
|
||||
clearAnimation();
|
||||
animatedColorBackground = 0;
|
||||
super.setBackgroundColor(color);
|
||||
}
|
||||
|
||||
public void setBackgroundColorAnimated(boolean checked, int color) {
|
||||
if (animator != null) {
|
||||
animator.cancel();
|
||||
animator = null;
|
||||
}
|
||||
if (animatedColorBackground != 0) {
|
||||
setBackgroundColor(animatedColorBackground);
|
||||
}
|
||||
if (animationPaint == null) {
|
||||
animationPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
}
|
||||
checkBox.setOverrideColor(checked ? 1 : 2);
|
||||
animatedColorBackground = color;
|
||||
animationPaint.setColor(animatedColorBackground);
|
||||
animationProgress = 0.0f;
|
||||
animator = ObjectAnimator.ofFloat(this, ANIMATION_PROGRESS, 0.0f, 1.0f);
|
||||
animator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
setBackgroundColor(animatedColorBackground);
|
||||
animatedColorBackground = 0;
|
||||
invalidate();
|
||||
}
|
||||
});
|
||||
animator.setInterpolator(CubicBezierInterpolator.EASE_OUT);
|
||||
animator.setDuration(240).start();
|
||||
}
|
||||
|
||||
private void setAnimationProgress(float value) {
|
||||
animationProgress = value;
|
||||
float rad = Math.max(lastTouchX, getMeasuredWidth() - lastTouchX) + AndroidUtilities.dp(40);
|
||||
float cx = lastTouchX;
|
||||
int cy = getMeasuredHeight() / 2;
|
||||
float animatedRad = rad * animationProgress;
|
||||
checkBox.setOverrideColorProgress(cx, cy, animatedRad);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if (animatedColorBackground != 0) {
|
||||
float rad = Math.max(lastTouchX, getMeasuredWidth() - lastTouchX) + AndroidUtilities.dp(40);
|
||||
float cx = lastTouchX;
|
||||
int cy = getMeasuredHeight() / 2;
|
||||
float animatedRad = rad * animationProgress;
|
||||
canvas.drawCircle(cx, cy, animatedRad, animationPaint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
textView.setTextColor(Theme.getColor(Theme.key_chats_menuItemText));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
|
||||
super.onInitializeAccessibilityNodeInfo(info);
|
||||
info.setClassName("android.widget.Switch");
|
||||
info.setCheckable(true);
|
||||
info.setChecked(checkBox.isChecked());
|
||||
info.setContentDescription(checkBox.isChecked() ? LocaleController.getString("NotificationsOn", R.string.NotificationsOn) : LocaleController.getString("NotificationsOff", R.string.NotificationsOff));
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,349 @@
|
|||
package tw.nekomimi.nekogram
|
||||
|
||||
import android.content.Context
|
||||
import android.text.TextUtils
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.widget.*
|
||||
import org.telegram.messenger.AndroidUtilities
|
||||
import org.telegram.messenger.LocaleController
|
||||
import org.telegram.messenger.R
|
||||
import org.telegram.ui.ActionBar.BottomSheet
|
||||
import org.telegram.ui.ActionBar.Theme
|
||||
import org.telegram.ui.Cells.*
|
||||
import org.telegram.ui.Components.LayoutHelper
|
||||
import java.util.*
|
||||
|
||||
class BottomBuilder(val ctx: Context) {
|
||||
|
||||
val builder = BottomSheet.Builder(ctx, true)
|
||||
|
||||
private val rootView = LinearLayout(ctx).apply {
|
||||
|
||||
orientation = LinearLayout.VERTICAL
|
||||
|
||||
}
|
||||
|
||||
private val _root = LinearLayout(ctx).apply {
|
||||
|
||||
addView(ScrollView(ctx).apply {
|
||||
|
||||
addView(this@BottomBuilder.rootView)
|
||||
isFillViewport = true
|
||||
isVerticalScrollBarEnabled = false
|
||||
|
||||
}, LinearLayout.LayoutParams(-1, -1))
|
||||
|
||||
builder.setCustomView(this)
|
||||
|
||||
}
|
||||
|
||||
|
||||
private val buttonsView by lazy {
|
||||
|
||||
FrameLayout(ctx).apply {
|
||||
|
||||
setBackgroundColor(Theme.getColor(Theme.key_dialogBackground))
|
||||
|
||||
this@BottomBuilder.rootView.addView(this, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 50, Gravity.LEFT or Gravity.BOTTOM))
|
||||
|
||||
addView(rightButtonsView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP or Gravity.RIGHT));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private val rightButtonsView by lazy {
|
||||
|
||||
LinearLayout(ctx).apply {
|
||||
|
||||
orientation = LinearLayout.HORIZONTAL
|
||||
|
||||
weightSum = 1F
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun addTitle(title: CharSequence, bigTitle: Boolean = false): HeaderCell {
|
||||
|
||||
return addTitle(title, bigTitle, null)
|
||||
|
||||
}
|
||||
|
||||
fun addTitle(title: CharSequence, subTitle: CharSequence): HeaderCell {
|
||||
|
||||
return addTitle(title, true, subTitle)
|
||||
|
||||
}
|
||||
|
||||
fun addTitle(title: CharSequence, bigTitle: Boolean, subTitle: CharSequence?): HeaderCell {
|
||||
|
||||
val headerCell = HeaderCell(ctx)
|
||||
|
||||
headerCell.setText(if (title is String) AndroidUtilities.replaceTags(title) else title)
|
||||
|
||||
subTitle?.also {
|
||||
|
||||
headerCell.setText2(it)
|
||||
|
||||
}
|
||||
|
||||
rootView.addView(headerCell, LayoutHelper.createLinear(-1, -2).apply {
|
||||
|
||||
bottomMargin = AndroidUtilities.dp(12F)
|
||||
|
||||
})
|
||||
|
||||
rootView.addView(ShadowSectionCell(ctx, 3))
|
||||
|
||||
return headerCell
|
||||
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun addCheckItem(text: String, value: Boolean, switch: Boolean = false, valueText: String? = null, listener: (cell: TextCheckCell) -> Unit): TextCheckCell {
|
||||
|
||||
val checkBoxCell = TextCheckCell(ctx, 21, !switch)
|
||||
checkBoxCell.setBackgroundDrawable(Theme.getSelectorDrawable(false))
|
||||
checkBoxCell.minimumHeight = AndroidUtilities.dp(50F)
|
||||
rootView.addView(checkBoxCell, LayoutHelper.createLinear(-1, -2))
|
||||
|
||||
if (valueText == null) {
|
||||
|
||||
checkBoxCell.setTextAndCheck(text, value, true)
|
||||
|
||||
} else {
|
||||
|
||||
checkBoxCell.setTextAndValueAndCheck(text, valueText, value, true, true)
|
||||
|
||||
}
|
||||
|
||||
checkBoxCell.setOnClickListener {
|
||||
|
||||
listener.invoke(checkBoxCell)
|
||||
|
||||
}
|
||||
|
||||
return checkBoxCell
|
||||
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun addCheckItems(text: Array<String>, value: (Int) -> Boolean, switch: Boolean = false, valueText: ((Int) -> String)? = null, listener: (index: Int, text: String, cell: TextCheckCell) -> Unit): List<TextCheckCell> {
|
||||
|
||||
val list = mutableListOf<TextCheckCell>()
|
||||
|
||||
text.forEachIndexed { index, textI ->
|
||||
|
||||
list.add(addCheckItem(textI, value(index), switch, valueText?.invoke(index)) { cell ->
|
||||
|
||||
listener(index, textI, cell)
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
return list
|
||||
|
||||
}
|
||||
|
||||
private val radioButtonGroup by lazy { LinkedList<RadioButtonCell>() }
|
||||
|
||||
fun doRadioCheck(cell: RadioButtonCell) {
|
||||
|
||||
if (!cell.isChecked) {
|
||||
|
||||
radioButtonGroup.forEach {
|
||||
|
||||
if (it.isChecked) {
|
||||
|
||||
it.setChecked(false, true)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cell.setChecked(true, true)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun addRadioItem(text: String, value: Boolean, valueText: String? = null, listener: (cell: RadioButtonCell) -> Unit): RadioButtonCell {
|
||||
|
||||
val checkBoxCell = RadioButtonCell(ctx, true)
|
||||
checkBoxCell.setBackgroundDrawable(Theme.getSelectorDrawable(false))
|
||||
checkBoxCell.minimumHeight = AndroidUtilities.dp(50F)
|
||||
rootView.addView(checkBoxCell, LayoutHelper.createLinear(-1, -2))
|
||||
|
||||
if (valueText == null) {
|
||||
|
||||
checkBoxCell.setTextAndValue(text, true, value)
|
||||
|
||||
} else {
|
||||
|
||||
checkBoxCell.setTextAndValueAndCheck(text, valueText, true, value)
|
||||
|
||||
}
|
||||
|
||||
radioButtonGroup.add(checkBoxCell)
|
||||
|
||||
checkBoxCell.setOnClickListener {
|
||||
|
||||
listener(checkBoxCell)
|
||||
|
||||
}
|
||||
|
||||
return checkBoxCell
|
||||
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun addRadioItems(text: Array<String>, value: (Int, String) -> Boolean, valueText: ((Int, String) -> String)? = null, listener: (index: Int, text: String, cell: RadioButtonCell) -> Unit): List<RadioButtonCell> {
|
||||
|
||||
val list = mutableListOf<RadioButtonCell>()
|
||||
|
||||
text.forEachIndexed { index, textI ->
|
||||
|
||||
list.add(addRadioItem(textI, value(index, textI), valueText?.invoke(index, textI)) { cell ->
|
||||
|
||||
listener(index, textI, cell)
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
return list
|
||||
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun addCancelItem() {
|
||||
|
||||
addItem(LocaleController.getString("Cancel", R.string.Cancel), R.drawable.baseline_cancel_24) { dismiss() }
|
||||
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun addCancelButton(left: Boolean = true) {
|
||||
|
||||
addButton(LocaleController.getString("Cancel", R.string.Cancel), left = left) { dismiss() }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@JvmOverloads
|
||||
fun addOkButton(listener: ((TextView) -> Unit)) {
|
||||
|
||||
addButton(LocaleController.getString("OK", R.string.OK)) { listener(it); }
|
||||
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun addButton(text: String, red: Boolean = false, left: Boolean = false, listener: ((TextView) -> Unit)): TextView {
|
||||
|
||||
return TextView(ctx).apply {
|
||||
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14f)
|
||||
setTextColor(Theme.getColor(Theme.key_dialogTextBlue4))
|
||||
gravity = Gravity.CENTER
|
||||
isSingleLine = true
|
||||
ellipsize = TextUtils.TruncateAt.END
|
||||
setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(Theme.key_dialogButtonSelector), 0))
|
||||
setPadding(AndroidUtilities.dp(18f), 0, AndroidUtilities.dp(18f), 0)
|
||||
setText(text)
|
||||
typeface = AndroidUtilities.getTypeface("fonts/rmedium.ttf")
|
||||
(if (left) buttonsView else rightButtonsView).addView(this, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP or Gravity.LEFT))
|
||||
setOnClickListener { listener(this) }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun addItem(): TextCell {
|
||||
|
||||
return TextCell(ctx).apply {
|
||||
|
||||
this@BottomBuilder.rootView.addView(this, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT or Gravity.TOP))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun addItem(text: String, icon: Int = 0, red: Boolean = false, listener: ((cell: TextCell) -> Unit)?): TextCell {
|
||||
|
||||
return TextCell(ctx).apply {
|
||||
|
||||
textView.setGravity(Gravity.LEFT)
|
||||
|
||||
background = Theme.getSelectorDrawable(false)
|
||||
|
||||
setTextAndIcon(text, icon, true)
|
||||
|
||||
setOnClickListener {
|
||||
|
||||
if (listener == null) dismiss() else listener(this)
|
||||
|
||||
}
|
||||
|
||||
if (red) {
|
||||
|
||||
setColors("key_dialogTextRed2", "key_dialogTextRed2")
|
||||
|
||||
}
|
||||
|
||||
this@BottomBuilder.rootView.addView(this, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT or Gravity.TOP))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun addItems(text: Array<String>, icon: (Int) -> Int = { 0 }, listener: (index: Int, text: String, cell: TextCell) -> Unit): List<TextCell> {
|
||||
|
||||
val list = mutableListOf<TextCell>()
|
||||
|
||||
text.forEachIndexed { index, textI ->
|
||||
|
||||
list.add(addItem(textI, icon(index)) { cell ->
|
||||
|
||||
listener(index, textI, cell)
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
return list
|
||||
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun addEditText(hintText: String? = null): EditText {
|
||||
|
||||
return EditText(ctx).apply {
|
||||
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14f)
|
||||
setTextColor(Theme.getColor(Theme.key_dialogTextBlack))
|
||||
setHintTextColor(Theme.getColor(Theme.key_dialogTextBlue4))
|
||||
hintText?.also { hint = it }
|
||||
isSingleLine = true
|
||||
isFocusable = true
|
||||
setBackgroundDrawable(null)
|
||||
|
||||
this@BottomBuilder.rootView.addView(this, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, -2, if (LocaleController.isRTL) Gravity.RIGHT else Gravity.LEFT, AndroidUtilities.dp(8F), 0, 0, 0))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun create() = builder.create()
|
||||
fun show() = builder.show()
|
||||
fun dismiss() {
|
||||
builder.dismissRunnable.run()
|
||||
}
|
||||
|
||||
}
|
109
TMessagesProj/src/main/java/tw/nekomimi/nekogram/DataCenter.kt
Normal file
109
TMessagesProj/src/main/java/tw/nekomimi/nekogram/DataCenter.kt
Normal file
|
@ -0,0 +1,109 @@
|
|||
package tw.nekomimi.nekogram
|
||||
|
||||
import cn.hutool.crypto.digest.DigestUtil
|
||||
import org.telegram.messenger.MessagesController
|
||||
import org.telegram.tgnet.ConnectionsManager
|
||||
import org.telegram.tgnet.SerializedData
|
||||
import org.telegram.tgnet.TLRPC
|
||||
import java.math.BigInteger
|
||||
import java.nio.ByteBuffer
|
||||
import java.security.interfaces.RSAPublicKey
|
||||
|
||||
object DataCenter {
|
||||
|
||||
// func calcAuthKeyId(keyData []byte) int64 {
|
||||
// sha1 := Sha1Digest(keyData)
|
||||
// // Lower 64 bits = 8 bytes of 20 byte SHA1 hash.
|
||||
// return int64(binary.LittleEndian.Uint64(sha1[12:]))
|
||||
// }
|
||||
@JvmStatic
|
||||
fun calcAuthKeyId(publicKey: RSAPublicKey): Long {
|
||||
|
||||
val key = SerializedData()
|
||||
|
||||
key.writeByteArray(publicKey.modulus.toByteArray())
|
||||
key.writeByteArray(publicKey.publicExponent.toByteArray())
|
||||
|
||||
return BigInteger(DigestUtil.sha1(key.toByteArray()).slice(12 until 20).toByteArray()).toLong()
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun applyOfficalDataCanter(account: Int) {
|
||||
|
||||
MessagesController.getMainSettings(account).edit().remove("layer").remove("custom_dc").apply()
|
||||
|
||||
if (ConnectionsManager.native_isTestBackend(account) != 0) {
|
||||
|
||||
ConnectionsManager.getInstance(account).switchBackend()
|
||||
|
||||
}
|
||||
|
||||
applyDataCanter(account, 1, "149.154.175.50", "2001:b28:f23d:f001:0000:0000:0000:000a")
|
||||
applyDataCanter(account, 2, "149.154.167.51", "2001:67c:4e8:f002:0000:0000:0000:000a")
|
||||
applyDataCanter(account, 3, "149.154.175.100", "2001:b28:f23d:f003:0000:0000:0000:000a")
|
||||
applyDataCanter(account, 4, "149.154.167.91", "2001:67c:4e8:f004:0000:0000:0000:000a")
|
||||
applyDataCanter(account, 5, "149.154.171.5", "2001:67c:4e8:f005:0000:0000:0000:000a")
|
||||
|
||||
ConnectionsManager.native_cleanUp(account, true)
|
||||
ConnectionsManager.native_setLayer(account, TLRPC.LAYER)
|
||||
|
||||
repeat(5) {
|
||||
|
||||
ConnectionsManager.native_setDatacenterPublicKey(account, it + 1, "", 0)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun applyTestDataCenter(account: Int) {
|
||||
|
||||
MessagesController.getMainSettings(account).edit().remove("layer").remove("custom_dc").apply()
|
||||
|
||||
if (ConnectionsManager.native_isTestBackend(account) == 0) {
|
||||
|
||||
ConnectionsManager.getInstance(account).switchBackend()
|
||||
|
||||
}
|
||||
|
||||
ConnectionsManager.native_setLayer(account, TLRPC.LAYER)
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun applyCustomDataCenter(account: Int, ipv4Address: String = "", ipv6Address: String = "", port: Int, layer: Int, publicKey: String, fingerprint: Long) {
|
||||
|
||||
MessagesController.getMainSettings(account).edit().putInt("layer", layer).putBoolean("custom_dc", true).apply()
|
||||
|
||||
if (ConnectionsManager.native_isTestBackend(account) != 0) {
|
||||
|
||||
ConnectionsManager.getInstance(account).switchBackend()
|
||||
|
||||
}
|
||||
|
||||
repeat(5) {
|
||||
|
||||
ConnectionsManager.native_setDatacenterAddress(account, it + 1, ipv4Address, ipv6Address, port)
|
||||
|
||||
}
|
||||
|
||||
ConnectionsManager.native_saveDatacenters(account)
|
||||
ConnectionsManager.native_setLayer(account, layer)
|
||||
|
||||
repeat(5) {
|
||||
|
||||
ConnectionsManager.native_setDatacenterPublicKey(account, it + 1, publicKey, fingerprint);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private fun applyDataCanter(account: Int, dataCenterId: Int, ipv4Address: String, ipv6Address: String, port: Int = 443) {
|
||||
|
||||
ConnectionsManager.native_setDatacenterAddress(account, dataCenterId, ipv4Address, ipv4Address, port)
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
package tw.nekomimi.nekogram;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.IntentSender;
|
||||
import android.text.TextUtils;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.GoogleApiAvailability;
|
||||
import com.google.android.play.core.appupdate.AppUpdateManager;
|
||||
import com.google.android.play.core.appupdate.AppUpdateManagerFactory;
|
||||
import com.google.android.play.core.install.InstallStateUpdatedListener;
|
||||
import com.google.android.play.core.install.model.AppUpdateType;
|
||||
import com.google.android.play.core.install.model.InstallStatus;
|
||||
import com.google.android.play.core.install.model.UpdateAvailability;
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics;
|
||||
import com.google.firebase.iid.FirebaseInstanceId;
|
||||
|
||||
import org.telegram.messenger.AndroidUtilities;
|
||||
import org.telegram.messenger.ApplicationLoader;
|
||||
import org.telegram.messenger.BuildConfig;
|
||||
import org.telegram.messenger.BuildVars;
|
||||
import org.telegram.messenger.FileLog;
|
||||
import org.telegram.messenger.GcmPushListenerService;
|
||||
import org.telegram.messenger.LocaleController;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.messenger.SharedConfig;
|
||||
import org.telegram.messenger.Utilities;
|
||||
import org.telegram.tgnet.ConnectionsManager;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import kotlin.Unit;
|
||||
import tw.nekomimi.nekogram.utils.UIUtil;
|
||||
|
||||
public class ExternalGcm {
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private static boolean noGcm = !"release".equals(BuildConfig.BUILD_TYPE);
|
||||
|
||||
private static Boolean hasPlayServices;
|
||||
|
||||
public static void initPlayServices() {
|
||||
|
||||
AndroidUtilities.runOnUIThread(() -> {
|
||||
if (hasPlayServices = checkPlayServices()) {
|
||||
final String currentPushString = SharedConfig.pushString;
|
||||
if (!TextUtils.isEmpty(currentPushString)) {
|
||||
if (BuildVars.DEBUG_PRIVATE_VERSION && BuildVars.LOGS_ENABLED) {
|
||||
FileLog.d("GCM regId = " + currentPushString);
|
||||
}
|
||||
} else {
|
||||
if (BuildVars.LOGS_ENABLED) {
|
||||
FileLog.d("GCM Registration not found.");
|
||||
}
|
||||
}
|
||||
Utilities.globalQueue.postRunnable(() -> {
|
||||
try {
|
||||
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(instanceIdResult -> {
|
||||
String token = instanceIdResult.getToken();
|
||||
if (!TextUtils.isEmpty(token)) {
|
||||
GcmPushListenerService.sendRegistrationToServer(token);
|
||||
}
|
||||
}).addOnFailureListener(e -> {
|
||||
if (BuildVars.LOGS_ENABLED) {
|
||||
FileLog.d("Failed to get regid");
|
||||
}
|
||||
SharedConfig.pushStringStatus = "__FIREBASE_FAILED__";
|
||||
GcmPushListenerService.sendRegistrationToServer(null);
|
||||
});
|
||||
} catch (Throwable e) {
|
||||
FileLog.e(e);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (BuildVars.LOGS_ENABLED) {
|
||||
FileLog.d("No valid Google Play Services APK found.");
|
||||
}
|
||||
SharedConfig.pushStringStatus = "__NO_GOOGLE_PLAY_SERVICES__";
|
||||
ConnectionsManager.setRegId(null, SharedConfig.pushStringStatus);
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
}
|
||||
|
||||
public static boolean checkPlayServices() {
|
||||
if (noGcm) return false;
|
||||
if (hasPlayServices != null) return hasPlayServices;
|
||||
try {
|
||||
int resultCode = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(ApplicationLoader.applicationContext);
|
||||
hasPlayServices = resultCode == ConnectionResult.SUCCESS;
|
||||
} catch (Exception e) {
|
||||
hasPlayServices = false;
|
||||
FileLog.e(e);
|
||||
}
|
||||
return hasPlayServices;
|
||||
}
|
||||
|
||||
public static void sendRegistrationToServer() {
|
||||
if (!checkPlayServices()) return;
|
||||
GcmPushListenerService.sendRegistrationToServer(SharedConfig.pushString);
|
||||
}
|
||||
|
||||
public static void reportLog(@NotNull String report) {
|
||||
if (!checkPlayServices()) return;
|
||||
UIUtil.runOnIoDispatcher(() -> FirebaseCrashlytics.getInstance().log(report));
|
||||
}
|
||||
|
||||
public static void recordException(@NotNull Throwable throwable) {
|
||||
if (!checkPlayServices()) return;
|
||||
UIUtil.runOnIoDispatcher(() -> FirebaseCrashlytics.getInstance().recordException(throwable));
|
||||
}
|
||||
|
||||
public static void checkUpdate(Activity ctx) {
|
||||
if (!checkPlayServices()) return;
|
||||
|
||||
AppUpdateManager manager = AppUpdateManagerFactory.create(ctx);
|
||||
|
||||
InstallStateUpdatedListener listener = (installState) -> {
|
||||
|
||||
if (installState.installStatus() == InstallStatus.DOWNLOADED) {
|
||||
|
||||
BottomBuilder builder = new BottomBuilder(ctx);
|
||||
|
||||
builder.addTitle(LocaleController.getString("UpdateDownloaded", R.string.UpdateDownloaded), false);
|
||||
|
||||
builder.addItem(LocaleController.getString("UpdateUpdate", R.string.UpdateUpdate), R.drawable.baseline_system_update_24, false, (it) -> {
|
||||
|
||||
manager.completeUpdate();
|
||||
|
||||
return Unit.INSTANCE;
|
||||
|
||||
});
|
||||
|
||||
builder.addItem(LocaleController.getString("UpdateLater", R.string.UpdateLater), R.drawable.baseline_watch_later_24, false, null);
|
||||
|
||||
try {
|
||||
|
||||
builder.show();
|
||||
|
||||
} catch (WindowManager.BadTokenException e) {
|
||||
|
||||
manager.completeUpdate();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
manager.registerListener(listener);
|
||||
|
||||
manager.getAppUpdateInfo().addOnSuccessListener((appUpdateInfo) -> {
|
||||
|
||||
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE && appUpdateInfo.availableVersionCode() <= BuildConfig.VERSION_CODE) {
|
||||
|
||||
FileLog.d("update available");
|
||||
|
||||
try {
|
||||
|
||||
manager.startUpdateFlowForResult(appUpdateInfo, AppUpdateType.FLEXIBLE, ctx, 114514);
|
||||
|
||||
} catch (IntentSender.SendIntentException ignored) {
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
FileLog.d("no updates");
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
package tw.nekomimi.nekogram;
|
||||
|
||||
import org.telegram.messenger.LocaleController;
|
||||
import org.telegram.messenger.MessagesController;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.tgnet.TLRPC;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class InternalFilters {
|
||||
|
||||
public static LinkedList<TLRPC.TL_dialogFilterSuggested> internalFilters = new LinkedList<>();
|
||||
|
||||
public static final TLRPC.TL_dialogFilter usersFilter;
|
||||
|
||||
public static final TLRPC.TL_dialogFilter contactsFilter;
|
||||
|
||||
public static final TLRPC.TL_dialogFilter groupsFilter;
|
||||
|
||||
public static final TLRPC.TL_dialogFilter channelsFilter;
|
||||
|
||||
public static final TLRPC.TL_dialogFilter botsFilter;
|
||||
|
||||
public static final TLRPC.TL_dialogFilter unmutedFilter;
|
||||
|
||||
public static final TLRPC.TL_dialogFilter unreadFilter;
|
||||
|
||||
public static final TLRPC.TL_dialogFilter unmutedAndUnreadFilter;
|
||||
|
||||
static {
|
||||
|
||||
usersFilter = mkFilter(LocaleController.getString("NotificationsUsers", R.string.FilterNameUsers),
|
||||
LocaleController.getString("FilterNameUsersDescription", R.string.FilterNameUsersDescription),
|
||||
MessagesController.DIALOG_FILTER_FLAG_CONTACTS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_NON_CONTACTS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_ARCHIVED,
|
||||
(it) -> {
|
||||
|
||||
it.contacts = true;
|
||||
it.non_contacts = true;
|
||||
it.exclude_archived = true;
|
||||
|
||||
});
|
||||
|
||||
contactsFilter = mkFilter(LocaleController.getString("FilterNameContacts", R.string.FilterNameContacts),
|
||||
LocaleController.getString("FilterNameContactsDescription", R.string.FilterNameContactsDescription),
|
||||
MessagesController.DIALOG_FILTER_FLAG_CONTACTS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_ARCHIVED,
|
||||
(it) -> {
|
||||
|
||||
it.contacts = true;
|
||||
it.exclude_archived = true;
|
||||
|
||||
});
|
||||
|
||||
groupsFilter = mkFilter(LocaleController.getString("FilterNameGroups", R.string.FilterNameGroups),
|
||||
LocaleController.getString("FilterNameContactsDescription", R.string.FilterNameGroupsDescription),
|
||||
MessagesController.DIALOG_FILTER_FLAG_GROUPS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_ARCHIVED,
|
||||
(it) -> {
|
||||
|
||||
it.groups = true;
|
||||
it.exclude_archived = true;
|
||||
|
||||
});
|
||||
|
||||
channelsFilter = mkFilter(LocaleController.getString("FilterNameChannels", R.string.FilterNameChannels),
|
||||
LocaleController.getString("FilterNameChannelsDescription", R.string.FilterNameChannelsDescription),
|
||||
MessagesController.DIALOG_FILTER_FLAG_CHANNELS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_ARCHIVED,
|
||||
(it) -> {
|
||||
|
||||
it.broadcasts = true;
|
||||
it.exclude_archived = true;
|
||||
|
||||
});
|
||||
|
||||
botsFilter = mkFilter(LocaleController.getString("FilterNameBots", R.string.FilterNameBots),
|
||||
LocaleController.getString("FilterNameBotsDescription", R.string.FilterNameBotsDescription),
|
||||
MessagesController.DIALOG_FILTER_FLAG_BOTS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_ARCHIVED,
|
||||
(it) -> {
|
||||
|
||||
it.bots = true;
|
||||
it.exclude_archived = true;
|
||||
|
||||
});
|
||||
|
||||
unmutedFilter = mkFilter(LocaleController.getString("FilterNameUnmuted", R.string.FilterNameUnmuted),
|
||||
LocaleController.getString("FilterNameUnmutedDescription", R.string.FilterNameUnmutedDescription),
|
||||
MessagesController.DIALOG_FILTER_FLAG_CONTACTS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_NON_CONTACTS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_GROUPS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_CHANNELS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_BOTS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_MUTED |
|
||||
MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_ARCHIVED,
|
||||
(it) -> {
|
||||
|
||||
it.contacts = true;
|
||||
it.non_contacts = true;
|
||||
it.groups = true;
|
||||
it.broadcasts = true;
|
||||
it.bots = true;
|
||||
it.exclude_muted = true;
|
||||
it.exclude_archived = true;
|
||||
|
||||
});
|
||||
|
||||
unreadFilter = mkFilter(LocaleController.getString("FilterNameUnread2", R.string.FilterNameUnread2),
|
||||
LocaleController.getString("FilterNameUnreadDescription", R.string.FilterNameUnreadDescription),
|
||||
MessagesController.DIALOG_FILTER_FLAG_CONTACTS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_NON_CONTACTS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_GROUPS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_CHANNELS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_BOTS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_READ |
|
||||
MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_ARCHIVED,
|
||||
(it) -> {
|
||||
|
||||
it.contacts = true;
|
||||
it.non_contacts = true;
|
||||
it.groups = true;
|
||||
it.broadcasts = true;
|
||||
it.bots = true;
|
||||
it.exclude_read = true;
|
||||
it.exclude_archived = true;
|
||||
|
||||
});
|
||||
|
||||
unmutedAndUnreadFilter = mkFilter(LocaleController.getString("FilterNameUnmutedAndUnread", R.string.FilterNameUnmutedAndUnread),
|
||||
LocaleController.getString("FilterNameUnmutedAndUnreadDescription", R.string.FilterNameUnmutedAndUnreadDescription),
|
||||
MessagesController.DIALOG_FILTER_FLAG_CONTACTS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_NON_CONTACTS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_GROUPS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_CHANNELS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_BOTS |
|
||||
MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_MUTED |
|
||||
MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_READ |
|
||||
MessagesController.DIALOG_FILTER_FLAG_EXCLUDE_ARCHIVED,
|
||||
(it) -> {
|
||||
|
||||
it.contacts = true;
|
||||
it.non_contacts = true;
|
||||
it.groups = true;
|
||||
it.broadcasts = true;
|
||||
it.bots = true;
|
||||
it.exclude_muted = true;
|
||||
it.exclude_read = true;
|
||||
it.exclude_archived = true;
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface FilterBuilder {
|
||||
|
||||
void apply(TLRPC.TL_dialogFilter filter);
|
||||
|
||||
}
|
||||
|
||||
private static int currId = 10;
|
||||
|
||||
private static TLRPC.TL_dialogFilter mkFilter(String name, String description, int flag, FilterBuilder builder) {
|
||||
|
||||
TLRPC.TL_dialogFilterSuggested suggestedFilter = new TLRPC.TL_dialogFilterSuggested();
|
||||
|
||||
suggestedFilter.description = description != null ? description : "Nya ~";
|
||||
|
||||
suggestedFilter.filter = new TLRPC.TL_dialogFilter();
|
||||
|
||||
suggestedFilter.filter.id = currId;
|
||||
|
||||
suggestedFilter.filter.title = name;
|
||||
suggestedFilter.filter.flags = flag;
|
||||
|
||||
builder.apply(suggestedFilter.filter);
|
||||
|
||||
internalFilters.add(suggestedFilter);
|
||||
|
||||
currId++;
|
||||
|
||||
return suggestedFilter.filter;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,101 +1,41 @@
|
|||
package tw.nekomimi.nekogram;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
|
||||
import org.telegram.messenger.AndroidUtilities;
|
||||
import org.telegram.messenger.BaseController;
|
||||
import org.telegram.messenger.LocaleController;
|
||||
import org.telegram.messenger.MessageObject;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.messenger.UserConfig;
|
||||
import org.telegram.tgnet.ConnectionsManager;
|
||||
import org.telegram.tgnet.TLRPC;
|
||||
import org.telegram.ui.ActionBar.AlertDialog;
|
||||
import org.telegram.ui.Cells.ChatMessageCell;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
|
||||
import tw.nekomimi.nekogram.settings.NekoGeneralSettingsActivity;
|
||||
import tw.nekomimi.nekogram.translator.TranslateBottomSheet;
|
||||
import tw.nekomimi.nekogram.translator.Translator;
|
||||
import tw.nekomimi.nekogram.utils.AlertUtil;
|
||||
|
||||
public class MessageHelper extends BaseController {
|
||||
|
||||
private static volatile MessageHelper[] Instance = new MessageHelper[UserConfig.MAX_ACCOUNT_COUNT];
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static AlertDialog progressDialog;
|
||||
private int lastReqId;
|
||||
|
||||
public MessageHelper(int num) {
|
||||
super(num);
|
||||
}
|
||||
|
||||
public static void resetMessageContent(MessageObject messageObject, ChatMessageCell chatMessageCell) {
|
||||
messageObject.forceUpdate = true;
|
||||
public static void resetMessageContent(MessageObject messageObject) {
|
||||
if (messageObject.caption != null) {
|
||||
messageObject.caption = null;
|
||||
messageObject.generateCaption();
|
||||
messageObject.forceUpdate = true;
|
||||
}
|
||||
messageObject.applyNewText();
|
||||
messageObject.resetLayout();
|
||||
chatMessageCell.requestLayout();
|
||||
chatMessageCell.invalidate();
|
||||
}
|
||||
|
||||
public static void showTranslateDialog(Context context, String query) {
|
||||
if (NekoConfig.translationProvider < 0) {
|
||||
TranslateBottomSheet.show(context, query);
|
||||
} else {
|
||||
if (progressDialog != null) {
|
||||
progressDialog.dismiss();
|
||||
}
|
||||
progressDialog = new AlertDialog(context, 3);
|
||||
progressDialog.showDelayed(400);
|
||||
Translator.translate(query, new Translator.TranslateCallBack() {
|
||||
@Override
|
||||
public void onSuccess(Object translation) {
|
||||
if (progressDialog != null) {
|
||||
progressDialog.dismiss();
|
||||
}
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setMessage((String) translation);
|
||||
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null);
|
||||
builder.setNeutralButton(LocaleController.getString("Copy", R.string.Copy), (dialog, which) -> AndroidUtilities.addToClipboard((String) translation));
|
||||
builder.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
if (progressDialog != null) {
|
||||
progressDialog.dismiss();
|
||||
}
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
if (e != null && e.getLocalizedMessage() != null) {
|
||||
builder.setTitle(LocaleController.getString("TranslateFailed", R.string.TranslateFailed));
|
||||
builder.setMessage(e.getLocalizedMessage());
|
||||
} else {
|
||||
builder.setMessage(LocaleController.getString("TranslateFailed", R.string.TranslateFailed));
|
||||
}
|
||||
builder.setNeutralButton(LocaleController.getString("TranslationProvider", R.string.TranslationProvider), (dialog, which) -> NekoGeneralSettingsActivity.getTranslationProviderAlert(context).show());
|
||||
builder.setPositiveButton(LocaleController.getString("Retry", R.string.Retry), (dialog, which) -> showTranslateDialog(context, query));
|
||||
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null);
|
||||
builder.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnsupported() {
|
||||
if (progressDialog != null) {
|
||||
progressDialog.dismiss();
|
||||
}
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setMessage(LocaleController.getString("TranslateApiUnsupported", R.string.TranslateApiUnsupported));
|
||||
builder.setPositiveButton(LocaleController.getString("TranslationProvider", R.string.TranslationProvider), (dialog, which) -> NekoGeneralSettingsActivity.getTranslationProviderAlert(context).show());
|
||||
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null);
|
||||
builder.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
public static void resetMessageContent(ChatMessageCell chatMessageCell) {
|
||||
chatMessageCell.onAttachedToWindow();
|
||||
chatMessageCell.requestLayout();
|
||||
chatMessageCell.invalidate();
|
||||
}
|
||||
|
||||
public static MessageHelper getInstance(int num) {
|
||||
|
@ -163,4 +103,97 @@ public class MessageHelper extends BaseController {
|
|||
}
|
||||
}), ConnectionsManager.RequestFlagFailOnServerErrors);
|
||||
}
|
||||
|
||||
public void deleteChannelHistory(final long dialog_id, TLRPC.Chat chat, final int offset_id) {
|
||||
|
||||
final TLRPC.TL_messages_getHistory req = new TLRPC.TL_messages_getHistory();
|
||||
req.peer = getMessagesController().getInputPeer((int) dialog_id);
|
||||
if (req.peer == null) {
|
||||
return;
|
||||
}
|
||||
req.limit = 100;
|
||||
req.offset_id = offset_id;
|
||||
final int currentReqId = ++lastReqId;
|
||||
getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> {
|
||||
if (error == null) {
|
||||
int lastMessageId = offset_id;
|
||||
if (currentReqId == lastReqId) {
|
||||
if (response != null) {
|
||||
TLRPC.messages_Messages res = (TLRPC.messages_Messages) response;
|
||||
int size = res.messages.size();
|
||||
if (size == 0) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
ArrayList<Integer> ids = new ArrayList<>();
|
||||
ArrayList<Long> random_ids = new ArrayList<>();
|
||||
int channelId = 0;
|
||||
for (int a = 0; a < res.messages.size(); a++) {
|
||||
TLRPC.Message message = res.messages.get(a);
|
||||
ids.add(message.id);
|
||||
if (message.random_id != 0) {
|
||||
random_ids.add(message.random_id);
|
||||
}
|
||||
if (message.to_id.channel_id != 0) {
|
||||
channelId = message.to_id.channel_id;
|
||||
}
|
||||
if (message.id > lastMessageId) {
|
||||
lastMessageId = message.id;
|
||||
}
|
||||
}
|
||||
getMessagesController().deleteMessages(ids, random_ids, null, dialog_id, channelId, true, false);
|
||||
*/
|
||||
HashSet<Integer> ids = new HashSet<>();
|
||||
ArrayList<Integer> msgIds = new ArrayList<>();
|
||||
ArrayList<Long> random_ids = new ArrayList<>();
|
||||
int channelId = 0;
|
||||
for (int a = 0; a < res.messages.size(); a++) {
|
||||
TLRPC.Message message = res.messages.get(a);
|
||||
ids.add(message.id);
|
||||
if (message.from_id > 0) {
|
||||
ids.add(message.from_id);
|
||||
} else {
|
||||
msgIds.add(message.id);
|
||||
if (message.random_id != 0) {
|
||||
random_ids.add(message.random_id);
|
||||
}
|
||||
}
|
||||
if (message.id > lastMessageId) {
|
||||
lastMessageId = message.id;
|
||||
}
|
||||
}
|
||||
for (int userId : ids) {
|
||||
deleteUserChannelHistory(chat, userId, 0);
|
||||
}
|
||||
if (!msgIds.isEmpty()) {
|
||||
getMessagesController().deleteMessages(msgIds, random_ids, null, dialog_id, channelId, true, false);
|
||||
}
|
||||
deleteChannelHistory(dialog_id, chat, lastMessageId);
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
AlertUtil.showToast(error.code + ": " + error.text);
|
||||
}
|
||||
}), ConnectionsManager.RequestFlagFailOnServerErrors);
|
||||
}
|
||||
|
||||
public void deleteUserChannelHistory(final TLRPC.Chat chat, int userId, int offset) {
|
||||
if (offset == 0) {
|
||||
getMessagesStorage().deleteUserChannelHistory(chat.id, userId);
|
||||
}
|
||||
TLRPC.TL_channels_deleteUserHistory req = new TLRPC.TL_channels_deleteUserHistory();
|
||||
req.channel = getMessagesController().getInputChannel(chat.id);
|
||||
req.user_id = getMessagesController().getInputUser(userId);
|
||||
getConnectionsManager().sendRequest(req, (response, error) -> {
|
||||
if (error == null) {
|
||||
TLRPC.TL_messages_affectedHistory res = (TLRPC.TL_messages_affectedHistory) response;
|
||||
if (res.offset > 0) {
|
||||
deleteUserChannelHistory(chat, userId, res.offset);
|
||||
}
|
||||
getMessagesController().processNewChannelDifferenceParams(res.pts, res.pts_count, chat.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,190 +1,215 @@
|
|||
package tw.nekomimi.nekogram;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
|
||||
import org.telegram.messenger.ApplicationLoader;
|
||||
import org.telegram.messenger.FileLog;
|
||||
import org.telegram.messenger.BuildVars;
|
||||
import org.telegram.messenger.LocaleController;
|
||||
import org.telegram.messenger.NotificationCenter;
|
||||
import org.telegram.messenger.NotificationsService;
|
||||
import org.telegram.messenger.SharedConfig;
|
||||
import org.telegram.messenger.R;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
public class NekoConfig {
|
||||
|
||||
public static final int TITLE_TYPE_TEXT = 0;
|
||||
public static final int TITLE_TYPE_ICON = 1;
|
||||
public static final int TITLE_TYPE_MIX = 2;
|
||||
|
||||
private static final Object sync = new Object();
|
||||
public static boolean useIPv6 = false;
|
||||
public static boolean showHiddenFeature = false;
|
||||
private static SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
|
||||
public static boolean useSystemEmoji = SharedConfig.useSystemEmoji;
|
||||
public static boolean ignoreBlocked = false;
|
||||
public static boolean hideProxySponsorChannel = false;
|
||||
public static boolean saveCacheToPrivateDirectory = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
|
||||
public static boolean disablePhotoSideAction = true;
|
||||
public static boolean hideKeyboardOnChatScroll = false;
|
||||
public static boolean rearVideoMessages = false;
|
||||
public static boolean hideAllTab = false;
|
||||
public static boolean confirmAVMessage = true;
|
||||
public static boolean askBeforeCall = true;
|
||||
public static boolean disableNumberRounding = false;
|
||||
public static int mapPreviewProvider = 0;
|
||||
public static float stickerSize = 14.0f;
|
||||
public static int translationProvider = 1;
|
||||
public static int tabsTitleType = TITLE_TYPE_TEXT;
|
||||
public static boolean useIPv6;
|
||||
|
||||
public static boolean showAddToSavedMessages = true;
|
||||
public static boolean showReport = false;
|
||||
public static boolean showPrPr = false;
|
||||
public static boolean showViewHistory = true;
|
||||
public static boolean showAdminActions = true;
|
||||
public static boolean showChangePermissions = true;
|
||||
public static boolean showDeleteDownloadedFile = true;
|
||||
public static boolean showMessageDetails = false;
|
||||
public static boolean showTranslate = true;
|
||||
public static boolean showRepeat = true;
|
||||
public static boolean useSystemEmoji;
|
||||
public static boolean ignoreBlocked;
|
||||
public static boolean hideProxySponsorChannel;
|
||||
public static boolean disablePhotoSideAction;
|
||||
public static boolean hideKeyboardOnChatScroll;
|
||||
public static boolean rearVideoMessages;
|
||||
public static boolean hideAllTab;
|
||||
public static boolean confirmAVMessage;
|
||||
public static boolean askBeforeCall;
|
||||
public static boolean disableNumberRounding;
|
||||
public static int mapPreviewProvider;
|
||||
public static float stickerSize;
|
||||
public static int translationProvider;
|
||||
public static int tabsTitleType;
|
||||
|
||||
public static boolean hidePhone = true;
|
||||
public static int typeface = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? 1 : 0;
|
||||
public static boolean transparentStatusBar = false;
|
||||
public static boolean forceTablet = false;
|
||||
public static boolean openArchiveOnPull = false;
|
||||
public static boolean avatarAsDrawerBackground = false;
|
||||
public static boolean showTabsOnForward = false;
|
||||
public static int nameOrder = 1;
|
||||
public static int eventType = 0;
|
||||
public static boolean newYear = false;
|
||||
public static int actionBarDecoration = 0;
|
||||
public static boolean unlimitedFavedStickers = false;
|
||||
public static boolean unlimitedPinnedDialogs = false;
|
||||
public static boolean disableAppBarShadow = false;
|
||||
public static boolean mediaPreview = false;
|
||||
public static boolean showAddToSavedMessages;
|
||||
public static boolean showReport;
|
||||
public static boolean showViewHistory;
|
||||
public static boolean showAdminActions;
|
||||
public static boolean showChangePermissions;
|
||||
public static boolean showDeleteDownloadedFile;
|
||||
public static boolean showMessageDetails;
|
||||
public static boolean showTranslate;
|
||||
public static boolean showRepeat;
|
||||
|
||||
public static boolean residentNotification = false;
|
||||
public static boolean hidePhone;
|
||||
public static int typeface;
|
||||
public static boolean transparentStatusBar;
|
||||
public static boolean forceTablet;
|
||||
public static boolean openArchiveOnPull;
|
||||
public static boolean avatarAsDrawerBackground;
|
||||
public static boolean showTabsOnForward;
|
||||
public static int nameOrder;
|
||||
public static int eventType;
|
||||
public static boolean newYear;
|
||||
public static int actionBarDecoration;
|
||||
public static boolean unlimitedFavedStickers;
|
||||
public static boolean unlimitedPinnedDialogs;
|
||||
public static boolean residentNotification;
|
||||
|
||||
public static boolean shouldNOTTrustMe = false;
|
||||
public static boolean disableChatAction;
|
||||
public static boolean sortByUnread;
|
||||
public static boolean sortByUnmuted;
|
||||
public static boolean sortByUser;
|
||||
public static boolean sortByContacts;
|
||||
|
||||
private static boolean configLoaded;
|
||||
public static boolean disableUndo;
|
||||
|
||||
public static boolean filterUsers;
|
||||
public static boolean filterContacts;
|
||||
public static boolean filterGroups;
|
||||
public static boolean filterChannels;
|
||||
public static boolean filterBots;
|
||||
public static boolean filterAdmins;
|
||||
public static boolean filterUnmuted;
|
||||
public static boolean filterUnread;
|
||||
public static boolean filterUnmutedAndUnread;
|
||||
|
||||
public static boolean ignoreMutedCount;
|
||||
|
||||
public static boolean disableSystemAccount;
|
||||
public static boolean disableProxyWhenVpnEnabled;
|
||||
public static boolean skipOpenLinkConfirm;
|
||||
|
||||
public static boolean removeTitleEmoji;
|
||||
public static boolean useDefaultTheme;
|
||||
public static boolean showIdAndDc;
|
||||
|
||||
public static String googleCloudTranslateKey;
|
||||
|
||||
public static String cachePath;
|
||||
|
||||
public static String translateToLang;
|
||||
public static String translateInputLang;
|
||||
|
||||
public static boolean hideProxyByDefault;
|
||||
public static boolean useProxyItem;
|
||||
|
||||
public static boolean disableAppBarShadow;
|
||||
public static boolean mediaPreview;
|
||||
|
||||
public static String formatLang(String name) {
|
||||
|
||||
if (name == null) {
|
||||
|
||||
return LocaleController.getString("Default", R.string.Default);
|
||||
|
||||
} else {
|
||||
|
||||
if (name.contains("-")) {
|
||||
|
||||
return new Locale(StrUtil.subBefore(name, "-", false), StrUtil.subAfter(name, "-", false)).getDisplayName(LocaleController.getInstance().currentLocale);
|
||||
|
||||
} else {
|
||||
|
||||
return new Locale(name).getDisplayName(LocaleController.getInstance().currentLocale);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static {
|
||||
loadConfig();
|
||||
}
|
||||
|
||||
public static void saveConfig() {
|
||||
synchronized (sync) {
|
||||
try {
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfing", Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("useIPv6", useIPv6);
|
||||
editor.putBoolean("hidePhone", hidePhone);
|
||||
editor.putBoolean("ignoreBlocked", ignoreBlocked);
|
||||
editor.putBoolean("forceTablet", forceTablet);
|
||||
editor.putBoolean("transparentStatusBar", transparentStatusBar);
|
||||
editor.putBoolean("residentNotification", residentNotification);
|
||||
editor.putBoolean("hideProxySponsorChannel", hideProxySponsorChannel);
|
||||
editor.putBoolean("saveCacheToPrivateDirectory", saveCacheToPrivateDirectory);
|
||||
editor.putBoolean("showAddToSavedMessages", showAddToSavedMessages);
|
||||
editor.putBoolean("showReport", showReport);
|
||||
editor.putBoolean("showPrPr", showPrPr);
|
||||
editor.putBoolean("showViewHistory", showViewHistory);
|
||||
editor.putBoolean("showAdminActions", showAdminActions);
|
||||
editor.putBoolean("showChangePermissions", showChangePermissions);
|
||||
editor.putBoolean("showDeleteDownloadedFile", showDeleteDownloadedFile);
|
||||
editor.putBoolean("showMessageDetails", showMessageDetails);
|
||||
editor.putBoolean("showTranslate", showTranslate);
|
||||
editor.putBoolean("showRepeat", showRepeat);
|
||||
editor.putBoolean("newYear", newYear);
|
||||
editor.putBoolean("unlimitedFavedStickers", unlimitedFavedStickers);
|
||||
editor.putBoolean("unlimitedPinnedDialogs", unlimitedPinnedDialogs);
|
||||
editor.putBoolean("disablePhotoSideAction", disablePhotoSideAction);
|
||||
editor.putBoolean("hideKeyboardOnChatScroll", hideKeyboardOnChatScroll);
|
||||
editor.putBoolean("openArchiveOnPull", openArchiveOnPull);
|
||||
editor.putBoolean("showHiddenFeature2", showHiddenFeature);
|
||||
editor.putBoolean("avatarAsDrawerBackground", avatarAsDrawerBackground);
|
||||
editor.putBoolean("useSystemEmoji", useSystemEmoji);
|
||||
editor.putBoolean("showTabsOnForward", showTabsOnForward);
|
||||
editor.putBoolean("rearVideoMessages", rearVideoMessages);
|
||||
editor.putBoolean("hideAllTab", hideAllTab);
|
||||
editor.putBoolean("confirmAVMessage", confirmAVMessage);
|
||||
editor.putBoolean("askBeforeCall", askBeforeCall);
|
||||
editor.putBoolean("shouldNOTTrustMe", shouldNOTTrustMe);
|
||||
editor.putBoolean("disableNumberRounding", disableNumberRounding);
|
||||
editor.putBoolean("disableAppBarShadow", disableAppBarShadow);
|
||||
editor.putBoolean("mediaPreview", mediaPreview);
|
||||
editor.putFloat("stickerSize", stickerSize);
|
||||
editor.putInt("typeface", typeface);
|
||||
editor.putInt("nameOrder", nameOrder);
|
||||
editor.putInt("mapPreviewProvider", mapPreviewProvider);
|
||||
editor.putInt("translationProvider", translationProvider);
|
||||
editor.putInt("eventType", eventType);
|
||||
editor.putInt("actionBarDecoration", actionBarDecoration);
|
||||
editor.putInt("tabsTitleType", tabsTitleType);
|
||||
editor.commit();
|
||||
} catch (Exception e) {
|
||||
FileLog.e(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
useIPv6 = preferences.getBoolean("useIPv6", false);
|
||||
hidePhone = preferences.getBoolean("hidePhone", true);
|
||||
ignoreBlocked = preferences.getBoolean("ignoreBlocked", false);
|
||||
forceTablet = preferences.getBoolean("forceTablet", false);
|
||||
typeface = preferences.getInt("typeface", 0);
|
||||
nameOrder = preferences.getInt("nameOrder", 1);
|
||||
mapPreviewProvider = preferences.getInt("mapPreviewProvider", 0);
|
||||
transparentStatusBar = preferences.getBoolean("transparentStatusBar", false);
|
||||
residentNotification = preferences.getBoolean("residentNotification", false);
|
||||
hideProxySponsorChannel = preferences.getBoolean("hideProxySponsorChannel", false);
|
||||
showAddToSavedMessages = preferences.getBoolean("showAddToSavedMessages", true);
|
||||
showReport = preferences.getBoolean("showReport", false);
|
||||
showViewHistory = preferences.getBoolean("showViewHistory", true);
|
||||
showAdminActions = preferences.getBoolean("showAdminActions", true);
|
||||
showChangePermissions = preferences.getBoolean("showChangePermissions", true);
|
||||
showDeleteDownloadedFile = preferences.getBoolean("showDeleteDownloadedFile", true);
|
||||
showMessageDetails = preferences.getBoolean("showMessageDetails", false);
|
||||
showTranslate = preferences.getBoolean("showTranslate", true);
|
||||
showRepeat = preferences.getBoolean("showRepeat", true);
|
||||
eventType = preferences.getInt("eventType", 0);
|
||||
actionBarDecoration = preferences.getInt("actionBarDecoration", 0);
|
||||
newYear = preferences.getBoolean("newYear", false);
|
||||
stickerSize = preferences.getFloat("stickerSize", 14.0f);
|
||||
unlimitedFavedStickers = preferences.getBoolean("unlimitedFavedStickers", false);
|
||||
unlimitedPinnedDialogs = preferences.getBoolean("unlimitedPinnedDialogs", false);
|
||||
translationProvider = preferences.getInt("translationProvider", 1);
|
||||
disablePhotoSideAction = preferences.getBoolean("disablePhotoSideAction", true);
|
||||
openArchiveOnPull = preferences.getBoolean("openArchiveOnPull", false);
|
||||
//showHiddenFeature = preferences.getBoolean("showHiddenFeature", false);
|
||||
hideKeyboardOnChatScroll = preferences.getBoolean("hideKeyboardOnChatScroll", false);
|
||||
avatarAsDrawerBackground = preferences.getBoolean("avatarAsDrawerBackground", true);
|
||||
useSystemEmoji = preferences.getBoolean("useSystemEmoji", false);
|
||||
showTabsOnForward = preferences.getBoolean("showTabsOnForward", showTabsOnForward);
|
||||
rearVideoMessages = preferences.getBoolean("rearVideoMessages", false);
|
||||
hideAllTab = preferences.getBoolean("hideAllTab", false);
|
||||
|
||||
public static void loadConfig() {
|
||||
synchronized (sync) {
|
||||
if (configLoaded) {
|
||||
return;
|
||||
}
|
||||
disableChatAction = preferences.getBoolean("disable_chat_action", false);
|
||||
sortByUnread = preferences.getBoolean("sort_by_unread", false);
|
||||
sortByUnmuted = preferences.getBoolean("sort_by_unmuted", true);
|
||||
sortByUser = preferences.getBoolean("sort_by_user", true);
|
||||
sortByContacts = preferences.getBoolean("sort_by_contacts", true);
|
||||
|
||||
disableUndo = preferences.getBoolean("disable_undo", false);
|
||||
|
||||
filterUsers = preferences.getBoolean("filter_users", true);
|
||||
filterContacts = preferences.getBoolean("filter_contacts", true);
|
||||
filterGroups = preferences.getBoolean("filter_groups", true);
|
||||
filterChannels = preferences.getBoolean("filter_channels", true);
|
||||
filterBots = preferences.getBoolean("filter_bots", true);
|
||||
filterAdmins = preferences.getBoolean("filter_admins", true);
|
||||
filterUnmuted = preferences.getBoolean("filter_unmuted", true);
|
||||
filterUnread = preferences.getBoolean("filter_unread", true);
|
||||
filterUnmutedAndUnread = preferences.getBoolean("filter_unmuted_and_unread", true);
|
||||
|
||||
disableSystemAccount = preferences.getBoolean("disable_system_account", false);
|
||||
disableProxyWhenVpnEnabled = preferences.getBoolean("disable_proxy_when_vpn_enabled", false);
|
||||
skipOpenLinkConfirm = preferences.getBoolean("skip_open_link_confirm", false);
|
||||
|
||||
removeTitleEmoji = preferences.getBoolean("remove_title_emoji", true);
|
||||
ignoreMutedCount = preferences.getBoolean("ignore_muted_count", true);
|
||||
useDefaultTheme = preferences.getBoolean("use_default_theme", false);
|
||||
showIdAndDc = preferences.getBoolean("show_id_and_dc", false);
|
||||
|
||||
googleCloudTranslateKey = preferences.getString("google_cloud_translate_key", null);
|
||||
cachePath = preferences.getString("cache_path", null);
|
||||
|
||||
translateToLang = preferences.getString("trans_to_lang", null);
|
||||
translateInputLang = preferences.getString("trans_input_to_lang", "en");
|
||||
|
||||
tabsTitleType = preferences.getInt("tabsTitleType", TITLE_TYPE_TEXT);
|
||||
confirmAVMessage = preferences.getBoolean("confirmAVMessage", false);
|
||||
askBeforeCall = preferences.getBoolean("askBeforeCall", false);
|
||||
disableNumberRounding = preferences.getBoolean("disableNumberRounding", false);
|
||||
|
||||
hideProxyByDefault = preferences.getBoolean("hide_proxy_by_default", BuildVars.isMini);
|
||||
useProxyItem = preferences.getBoolean("use_proxy_item",false);
|
||||
|
||||
disableAppBarShadow = preferences.getBoolean("disableAppBarShadow", false);
|
||||
mediaPreview = preferences.getBoolean("mediaPreview", false);
|
||||
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
useIPv6 = preferences.getBoolean("useIPv6", false);
|
||||
hidePhone = preferences.getBoolean("hidePhone", true);
|
||||
ignoreBlocked = preferences.getBoolean("ignoreBlocked", false);
|
||||
forceTablet = preferences.getBoolean("forceTablet", false);
|
||||
typeface = preferences.getInt("typeface", Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? 1 : 0);
|
||||
nameOrder = preferences.getInt("nameOrder", 1);
|
||||
mapPreviewProvider = preferences.getInt("mapPreviewProvider", 0);
|
||||
transparentStatusBar = preferences.getBoolean("transparentStatusBar", false);
|
||||
residentNotification = preferences.getBoolean("residentNotification", false);
|
||||
hideProxySponsorChannel = preferences.getBoolean("hideProxySponsorChannel", false);
|
||||
saveCacheToPrivateDirectory = preferences.getBoolean("saveCacheToPrivateDirectory", Build.VERSION.SDK_INT >= Build.VERSION_CODES.N);
|
||||
showAddToSavedMessages = preferences.getBoolean("showAddToSavedMessages", true);
|
||||
showReport = preferences.getBoolean("showReport", false);
|
||||
showPrPr = preferences.getBoolean("showPrPr", false);
|
||||
showViewHistory = preferences.getBoolean("showViewHistory", true);
|
||||
showAdminActions = preferences.getBoolean("showAdminActions", true);
|
||||
showChangePermissions = preferences.getBoolean("showChangePermissions", true);
|
||||
showDeleteDownloadedFile = preferences.getBoolean("showDeleteDownloadedFile", true);
|
||||
showMessageDetails = preferences.getBoolean("showMessageDetails", false);
|
||||
showTranslate = preferences.getBoolean("showTranslate", true);
|
||||
showRepeat = preferences.getBoolean("showRepeat", true);
|
||||
eventType = preferences.getInt("eventType", 0);
|
||||
actionBarDecoration = preferences.getInt("actionBarDecoration", 0);
|
||||
newYear = preferences.getBoolean("newYear", false);
|
||||
stickerSize = preferences.getFloat("stickerSize", 14.0f);
|
||||
unlimitedFavedStickers = preferences.getBoolean("unlimitedFavedStickers", false);
|
||||
unlimitedPinnedDialogs = preferences.getBoolean("unlimitedPinnedDialogs", false);
|
||||
translationProvider = preferences.getInt("translationProvider", 1);
|
||||
disablePhotoSideAction = preferences.getBoolean("disablePhotoSideAction", true);
|
||||
openArchiveOnPull = preferences.getBoolean("openArchiveOnPull", false);
|
||||
showHiddenFeature = preferences.getBoolean("showHiddenFeature2", false);
|
||||
hideKeyboardOnChatScroll = preferences.getBoolean("hideKeyboardOnChatScroll", false);
|
||||
avatarAsDrawerBackground = preferences.getBoolean("avatarAsDrawerBackground", false);
|
||||
useSystemEmoji = preferences.getBoolean("useSystemEmoji", SharedConfig.useSystemEmoji);
|
||||
showTabsOnForward = preferences.getBoolean("showTabsOnForward", false);
|
||||
rearVideoMessages = preferences.getBoolean("rearVideoMessages", false);
|
||||
hideAllTab = preferences.getBoolean("hideAllTab", false);
|
||||
tabsTitleType = preferences.getInt("tabsTitleType", TITLE_TYPE_TEXT);
|
||||
confirmAVMessage = preferences.getBoolean("confirmAVMessage", true);
|
||||
askBeforeCall = preferences.getBoolean("askBeforeCall", true);
|
||||
shouldNOTTrustMe = preferences.getBoolean("shouldNOTTrustMe", false);
|
||||
disableNumberRounding = preferences.getBoolean("disableNumberRounding", false);
|
||||
disableAppBarShadow = preferences.getBoolean("disableAppBarShadow", false);
|
||||
mediaPreview = preferences.getBoolean("mediaPreview", false);
|
||||
configLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void toggleShowAddToSavedMessages() {
|
||||
|
@ -192,7 +217,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("showAddToSavedMessages", showAddToSavedMessages);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleShowReport() {
|
||||
|
@ -200,24 +225,15 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("showReport", showReport);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
|
||||
public static void toggleShowViewHistory() {
|
||||
showViewHistory = !showViewHistory;
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("showViewHistory", showViewHistory);
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
public static void toggleShowPrPr() {
|
||||
showPrPr = !showPrPr;
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("showPrPr", showPrPr);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleShowAdminActions() {
|
||||
|
@ -225,7 +241,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("showAdminActions", showAdminActions);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleShowChangePermissions() {
|
||||
|
@ -233,7 +249,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("showChangePermissions", showChangePermissions);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleShowDeleteDownloadedFile() {
|
||||
|
@ -241,7 +257,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("showDeleteDownloadedFile", showDeleteDownloadedFile);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleShowMessageDetails() {
|
||||
|
@ -249,7 +265,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("showMessageDetails", showMessageDetails);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleShowRepeat() {
|
||||
|
@ -257,7 +273,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("showRepeat", showRepeat);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleIPv6() {
|
||||
|
@ -265,7 +281,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("useIPv6", useIPv6);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleHidePhone() {
|
||||
|
@ -273,7 +289,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("hidePhone", hidePhone);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleIgnoreBlocked() {
|
||||
|
@ -281,7 +297,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("ignoreBlocked", ignoreBlocked);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleForceTablet() {
|
||||
|
@ -289,7 +305,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("forceTablet", forceTablet);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleTypeface() {
|
||||
|
@ -297,7 +313,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putInt("typeface", typeface);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void setNameOrder(int order) {
|
||||
|
@ -305,7 +321,9 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putInt("nameOrder", nameOrder);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
|
||||
LocaleController.getInstance().recreateFormatters();
|
||||
}
|
||||
|
||||
public static void setMapPreviewProvider(int provider) {
|
||||
|
@ -313,7 +331,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putInt("mapPreviewProvider", mapPreviewProvider);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleTransparentStatusBar() {
|
||||
|
@ -321,7 +339,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("transparentStatusBar", transparentStatusBar);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleResidentNotification() {
|
||||
|
@ -329,7 +347,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("residentNotification", residentNotification);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
ApplicationLoader.applicationContext.stopService(new Intent(ApplicationLoader.applicationContext, NotificationsService.class));
|
||||
ApplicationLoader.startPushService();
|
||||
}
|
||||
|
@ -339,15 +357,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("hideProxySponsorChannel", hideProxySponsorChannel);
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
public static void toggleSaveCacheToPrivateDirectory() {
|
||||
saveCacheToPrivateDirectory = !saveCacheToPrivateDirectory;
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("saveCacheToPrivateDirectory", saveCacheToPrivateDirectory);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void setEventType(int type) {
|
||||
|
@ -355,7 +365,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putInt("eventType", eventType);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void setActionBarDecoration(int decoration) {
|
||||
|
@ -363,7 +373,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putInt("actionBarDecoration", actionBarDecoration);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleNewYear() {
|
||||
|
@ -371,7 +381,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("newYear", newYear);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleUnlimitedFavedStickers() {
|
||||
|
@ -379,7 +389,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("unlimitedFavedStickers", unlimitedFavedStickers);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleUnlimitedPinnedDialogs() {
|
||||
|
@ -387,7 +397,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("unlimitedPinnedDialogs", unlimitedPinnedDialogs);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleShowTranslate() {
|
||||
|
@ -395,7 +405,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("showTranslate", showTranslate);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void setStickerSize(float size) {
|
||||
|
@ -403,7 +413,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putFloat("stickerSize", stickerSize);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void setTranslationProvider(int provider) {
|
||||
|
@ -411,7 +421,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putInt("translationProvider", translationProvider);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleDisablePhotoSideAction() {
|
||||
|
@ -419,7 +429,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("disablePhotoSideAction", disablePhotoSideAction);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleOpenArchiveOnPull() {
|
||||
|
@ -427,23 +437,23 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("openArchiveOnPull", openArchiveOnPull);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleShowHiddenFeature() {
|
||||
/*public static void toggleShowHiddenFeature() {
|
||||
showHiddenFeature = !showHiddenFeature;
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("showHiddenFeature2", showHiddenFeature);
|
||||
editor.putBoolean("showHiddenFeature", showHiddenFeature);
|
||||
editor.commit();
|
||||
}
|
||||
} */
|
||||
|
||||
public static void toggleHideKeyboardOnChatScroll() {
|
||||
hideKeyboardOnChatScroll = !hideKeyboardOnChatScroll;
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("hideKeyboardOnChatScroll", hideKeyboardOnChatScroll);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleAvatarAsDrawerBackground() {
|
||||
|
@ -451,15 +461,21 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("avatarAsDrawerBackground", avatarAsDrawerBackground);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleUseSystemEmoji() {
|
||||
useSystemEmoji = !useSystemEmoji;
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("useSystemEmoji", useSystemEmoji);
|
||||
editor.commit();
|
||||
preferences.edit().putBoolean("useSystemEmoji", useSystemEmoji = !useSystemEmoji).apply();
|
||||
}
|
||||
|
||||
public static void toggleDisableChatAction() {
|
||||
preferences.edit().putBoolean("disable_chat_action", disableChatAction = !disableChatAction).apply();
|
||||
}
|
||||
|
||||
public static void toggleSortByUnread() {
|
||||
|
||||
preferences.edit().putBoolean("sort_by_unread", sortByUnread = !sortByUnread).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleShowTabsOnForward() {
|
||||
|
@ -467,7 +483,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("showTabsOnForward", showTabsOnForward);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleRearVideoMessages() {
|
||||
|
@ -475,7 +491,7 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("rearVideoMessages", rearVideoMessages);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleHideAllTab() {
|
||||
|
@ -483,62 +499,202 @@ public class NekoConfig {
|
|||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("hideAllTab", hideAllTab);
|
||||
editor.commit();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public static void toggleSortByUnmuted() {
|
||||
|
||||
preferences.edit().putBoolean("sort_by_unmuted", sortByUnmuted = !sortByUnmuted).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleSortByUser() {
|
||||
|
||||
preferences.edit().putBoolean("sort_by_user", sortByUser = !sortByUser).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleSortByContacts() {
|
||||
|
||||
preferences.edit().putBoolean("sort_by_contacts", sortByContacts = !sortByContacts).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleDisableUndo() {
|
||||
|
||||
preferences.edit().putBoolean("disable_undo", disableUndo = !disableUndo).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleFilterUsers() {
|
||||
|
||||
preferences.edit().putBoolean("filter_users", filterUsers = !filterUsers).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleFilterContacts() {
|
||||
|
||||
preferences.edit().putBoolean("filter_contacts", filterContacts = !filterContacts).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleFilterGroups() {
|
||||
|
||||
preferences.edit().putBoolean("filterGroups", filterGroups = !filterGroups).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleFilterChannels() {
|
||||
|
||||
preferences.edit().putBoolean("filter_channels", filterChannels = !filterChannels).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleFilterBots() {
|
||||
|
||||
preferences.edit().putBoolean("filter_bots", filterBots = !filterBots).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleFilterAdmins() {
|
||||
|
||||
preferences.edit().putBoolean("filter_admins", filterAdmins = !filterAdmins).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleFilterUnmuted() {
|
||||
|
||||
preferences.edit().putBoolean("filter_unmuted", filterUnmuted = !filterUnmuted).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleDisableFilterUnread() {
|
||||
|
||||
preferences.edit().putBoolean("filter_unread", filterUnread = !filterUnread).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleFilterUnmutedAndUnread() {
|
||||
|
||||
preferences.edit().putBoolean("filter_unmuted_and_unread", filterUnmutedAndUnread = !filterUnmutedAndUnread).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleDisableSystemAccount() {
|
||||
|
||||
preferences.edit().putBoolean("disable_system_account", disableSystemAccount = !disableSystemAccount).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleDisableProxyWhenVpnEnabled() {
|
||||
|
||||
preferences.edit().putBoolean("disable_proxy_when_vpn_enabled", disableProxyWhenVpnEnabled = !disableProxyWhenVpnEnabled).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleSkipOpenLinkConfirm() {
|
||||
|
||||
preferences.edit().putBoolean("skip_open_link_confirm", skipOpenLinkConfirm = !skipOpenLinkConfirm).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleRemoveTitleEmoji() {
|
||||
|
||||
preferences.edit().putBoolean("remove_title_emoji", removeTitleEmoji = !removeTitleEmoji).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleIgnoredMutedCount() {
|
||||
|
||||
preferences.edit().putBoolean("ignore_muted_count", ignoreMutedCount = !ignoreMutedCount).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleUseDefaultTheme() {
|
||||
|
||||
preferences.edit().putBoolean("use_default_theme", useDefaultTheme = !useDefaultTheme).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleShowIdAndDc() {
|
||||
|
||||
preferences.edit().putBoolean("show_id_and_dc", showIdAndDc = !showIdAndDc).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void setGoogleTranslateKey(String key) {
|
||||
|
||||
preferences.edit().putString("google_cloud_translate_key", googleCloudTranslateKey = key).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void setCachePath(String cachePath) {
|
||||
|
||||
preferences.edit().putString("cache_path", NekoConfig.cachePath = cachePath).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void setTranslateToLang(String toLang) {
|
||||
|
||||
preferences.edit().putString("trans_to_lang", translateToLang = toLang).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void setTranslateInputToLang(String toLang) {
|
||||
|
||||
preferences.edit().putString("trans_input_to_lang", translateInputLang = toLang).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void setTabsTitleType(int type) {
|
||||
tabsTitleType = type;
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putInt("tabsTitleType", tabsTitleType);
|
||||
editor.commit();
|
||||
|
||||
preferences.edit().putInt("tabsTitleType", tabsTitleType = type).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleConfirmAVMessage() {
|
||||
confirmAVMessage = !confirmAVMessage;
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("confirmAVMessage", confirmAVMessage);
|
||||
editor.commit();
|
||||
|
||||
preferences.edit().putBoolean("confirmAVMessage", confirmAVMessage = !confirmAVMessage).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleAskBeforeCall() {
|
||||
askBeforeCall = !askBeforeCall;
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("askBeforeCall", askBeforeCall);
|
||||
editor.commit();
|
||||
|
||||
preferences.edit().putBoolean("askBeforeCall", askBeforeCall = !askBeforeCall).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleShouldNOTTrustMe() {
|
||||
shouldNOTTrustMe = !shouldNOTTrustMe;
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("shouldNOTTrustMe", shouldNOTTrustMe);
|
||||
editor.commit();
|
||||
public static void toggleHideProxyByDefault() {
|
||||
|
||||
preferences.edit().putBoolean("hide_proxy_by_default", hideProxyByDefault = !hideProxyByDefault).apply();
|
||||
|
||||
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged);
|
||||
|
||||
}
|
||||
|
||||
public static void toggleUseProxyItem() {
|
||||
|
||||
preferences.edit().putBoolean("use_proxy_item",useProxyItem = !useProxyItem).apply();
|
||||
|
||||
NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged);
|
||||
|
||||
}
|
||||
|
||||
public static void toggleDisableNumberRounding() {
|
||||
disableNumberRounding = !disableNumberRounding;
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("disableNumberRounding", disableNumberRounding);
|
||||
editor.commit();
|
||||
|
||||
preferences.edit().putBoolean("disableNumberRounding",disableNumberRounding = !disableNumberRounding).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleDisableAppBarShadow() {
|
||||
disableAppBarShadow = !disableAppBarShadow;
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("disableAppBarShadow", disableAppBarShadow);
|
||||
editor.commit();
|
||||
|
||||
preferences.edit().putBoolean("disableAppBarShadow",disableAppBarShadow = !disableAppBarShadow).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleMediaPreview() {
|
||||
mediaPreview = !mediaPreview;
|
||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("nekoconfig", Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putBoolean("mediaPreview", mediaPreview);
|
||||
editor.commit();
|
||||
|
||||
preferences.edit().putBoolean("mediaPreview",mediaPreview = !mediaPreview).apply();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
package tw.nekomimi.nekogram;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import org.telegram.messenger.BuildConfig;
|
||||
import org.telegram.messenger.BuildVars;
|
||||
|
||||
import tw.nekomimi.nekogram.database.NitritesKt;
|
||||
|
||||
public class NekoXConfig {
|
||||
|
||||
public static String FAQ_URL = "https://telegra.ph/NekoX-FAQ-03-31";
|
||||
|
||||
public static SharedPreferences preferences = NitritesKt.openMainSharedPreference("nekox_config");
|
||||
|
||||
public static boolean developerModeEntrance;
|
||||
public static boolean developerMode = preferences.getBoolean("developer_mode", false);
|
||||
|
||||
public static boolean disableFlagSecure = preferences.getBoolean("disable_flag_secure", false);
|
||||
public static boolean disableScreenshotDetection = preferences.getBoolean("disable_screenshot_detection", false);
|
||||
|
||||
public static void toggleDeveloperMode() {
|
||||
|
||||
preferences.edit().putBoolean("developer_mode", developerMode = !developerMode).apply();
|
||||
|
||||
if (!developerMode) {
|
||||
|
||||
preferences.edit()
|
||||
.putBoolean("disable_flag_secure", disableFlagSecure = false)
|
||||
.putBoolean("disable_screenshot_detection", disableScreenshotDetection = false)
|
||||
.apply();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void toggleDisableFlagSecure() {
|
||||
|
||||
preferences.edit().putBoolean("disable_flag_secure", disableFlagSecure = !disableFlagSecure).apply();
|
||||
|
||||
}
|
||||
|
||||
public static void toggleDisableScreenshotDetection() {
|
||||
|
||||
preferences.edit().putBoolean("disable_screenshot_detection", disableScreenshotDetection = !disableScreenshotDetection).apply();
|
||||
|
||||
}
|
||||
|
||||
public static int customApi = preferences.getInt("custom_api", 0);
|
||||
public static int customAppId = preferences.getInt("custom_app_id", 0);
|
||||
public static String customAppHash = preferences.getString("custom_app_hash", "");
|
||||
|
||||
public static int currentAppId() {
|
||||
|
||||
switch (customApi) {
|
||||
|
||||
case 0:
|
||||
return BuildConfig.APP_ID;
|
||||
case 1:
|
||||
return BuildVars.OFFICAL_APP_ID;
|
||||
case 2:
|
||||
return BuildVars.TGX_APP_ID;
|
||||
default:
|
||||
return customAppId;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static String currentAppHash() {
|
||||
|
||||
switch (customApi) {
|
||||
|
||||
case 0:
|
||||
return BuildConfig.APP_HASH;
|
||||
case 1:
|
||||
return BuildVars.OFFICAL_APP_HASH;
|
||||
case 2:
|
||||
return BuildVars.TGX_APP_HASH;
|
||||
default:
|
||||
return customAppHash;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void saveCustomApi() {
|
||||
|
||||
preferences.edit()
|
||||
.putInt("custom_api", customApi)
|
||||
.putInt("custom_app_id", customAppId)
|
||||
.putString("custom_app_hash", customAppHash)
|
||||
.apply();
|
||||
|
||||
}
|
||||
|
||||
public static String customDcIpv4 = preferences.getString("custom_dc_v4", "");
|
||||
public static String customDcIpv6 = preferences.getString("custom_dc_v6", "");
|
||||
public static int customDcPort = preferences.getInt("custom_dc_port", 0);
|
||||
public static int customDcLayer = preferences.getInt("custom_dc_layer", 0);
|
||||
|
||||
public static String customDcPublicKey = preferences.getString("custom_dc_public_key", "");
|
||||
public static long customDcFingerprint = preferences.getLong("custom_dc_fingerprint", 0L);
|
||||
|
||||
public static void saveCustomDc() {
|
||||
|
||||
preferences.edit()
|
||||
.putString("custom_dc_v4", customDcIpv4)
|
||||
.putString("custom_dc_v6", customDcIpv6)
|
||||
.putInt("custom_dc_port", customDcPort)
|
||||
.putInt("custom_dc_layer", customDcLayer)
|
||||
.putString("custom_dc_public_key", customDcPublicKey)
|
||||
.putLong("custom_dc_fingerprint", customDcFingerprint)
|
||||
.apply();
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package tw.nekomimi.nekogram
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import android.service.notification.NotificationListenerService
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.app.NotificationCompat
|
||||
import org.telegram.messenger.ApplicationLoader
|
||||
import org.telegram.messenger.KeepAliveJob
|
||||
import org.telegram.messenger.LocaleController
|
||||
import org.telegram.messenger.R
|
||||
|
||||
@SuppressLint("OverrideAbstract")
|
||||
@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
|
||||
class NekoXPushService : NotificationListenerService() {
|
||||
|
||||
override fun onCreate() {
|
||||
|
||||
super.onCreate()
|
||||
|
||||
ApplicationLoader.postInitApplication()
|
||||
KeepAliveJob.startJob()
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,354 @@
|
|||
package tw.nekomimi.nekogram;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.telegram.messenger.AndroidUtilities;
|
||||
import org.telegram.messenger.ApplicationLoader;
|
||||
import org.telegram.messenger.LocaleController;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.ui.ActionBar.ActionBar;
|
||||
import org.telegram.ui.ActionBar.AlertDialog;
|
||||
import org.telegram.ui.ActionBar.BaseFragment;
|
||||
import org.telegram.ui.ActionBar.Theme;
|
||||
import org.telegram.ui.ActionBar.ThemeDescription;
|
||||
import org.telegram.ui.Cells.EmptyCell;
|
||||
import org.telegram.ui.Cells.HeaderCell;
|
||||
import org.telegram.ui.Cells.NotificationsCheckCell;
|
||||
import org.telegram.ui.Cells.ShadowSectionCell;
|
||||
import org.telegram.ui.Cells.TextCheckCell;
|
||||
import org.telegram.ui.Cells.TextDetailSettingsCell;
|
||||
import org.telegram.ui.Cells.TextSettingsCell;
|
||||
import org.telegram.ui.Components.LayoutHelper;
|
||||
import org.telegram.ui.Components.RecyclerListView;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import tw.nekomimi.nekogram.parts.UpdateChecksKt;
|
||||
import tw.nekomimi.nekogram.utils.AlertUtil;
|
||||
import tw.nekomimi.nekogram.utils.FileUtil;
|
||||
import tw.nekomimi.nekogram.utils.LocaleUtil;
|
||||
import tw.nekomimi.nekogram.utils.ShareUtil;
|
||||
import tw.nekomimi.nekogram.utils.UIUtil;
|
||||
import tw.nekomimi.nekogram.utils.ZipUtil;
|
||||
|
||||
public class NekoXSettingActivity extends BaseFragment {
|
||||
|
||||
private RecyclerListView listView;
|
||||
private ListAdapter listAdapter;
|
||||
|
||||
private int rowCount;
|
||||
|
||||
private int developerSettingsRow;
|
||||
|
||||
private int enableRow;
|
||||
private int disableFlagSecureRow;
|
||||
private int disableScreenshotDetectionRow;
|
||||
|
||||
private int fetchAndExportLangRow;
|
||||
private int checkUpdateRepoForceRow;
|
||||
|
||||
@Override
|
||||
public boolean onFragmentCreate() {
|
||||
super.onFragmentCreate();
|
||||
updateRows();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View createView(Context context) {
|
||||
actionBar.setBackButtonImage(R.drawable.ic_ab_back);
|
||||
actionBar.setTitle(LocaleController.getString("NekoSettings", R.string.NekoSettings));
|
||||
|
||||
if (AndroidUtilities.isTablet()) {
|
||||
actionBar.setOccupyStatusBar(false);
|
||||
}
|
||||
actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() {
|
||||
@Override
|
||||
public void onItemClick(int id) {
|
||||
if (id == -1) {
|
||||
finishFragment();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
listAdapter = new ListAdapter(context);
|
||||
|
||||
fragmentView = new FrameLayout(context);
|
||||
fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray));
|
||||
FrameLayout frameLayout = (FrameLayout) fragmentView;
|
||||
|
||||
listView = new RecyclerListView(context);
|
||||
listView.setVerticalScrollBarEnabled(false);
|
||||
listView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) {
|
||||
@Override
|
||||
public boolean supportsPredictiveItemAnimations() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
listView.setGlowColor(Theme.getColor(Theme.key_avatar_backgroundActionBarBlue));
|
||||
listView.setAdapter(listAdapter);
|
||||
listView.setItemAnimator(null);
|
||||
listView.setLayoutAnimation(null);
|
||||
frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT));
|
||||
listView.setOnItemClickListener((view, position, x, y) -> {
|
||||
|
||||
if (position == fetchAndExportLangRow) {
|
||||
fetchAndExportLang();
|
||||
} else if (position == checkUpdateRepoForceRow) {
|
||||
UpdateChecksKt.checkUpdate(getParentActivity(), true);
|
||||
}
|
||||
|
||||
if (position == enableRow) {
|
||||
NekoXConfig.toggleDeveloperMode();
|
||||
updateRows();
|
||||
} else if (position == disableFlagSecureRow) {
|
||||
NekoXConfig.toggleDisableFlagSecure();
|
||||
if (view instanceof TextCheckCell) {
|
||||
((TextCheckCell) view).setChecked(NekoXConfig.disableFlagSecure);
|
||||
}
|
||||
} else if (position == disableScreenshotDetectionRow) {
|
||||
NekoXConfig.toggleDisableScreenshotDetection();
|
||||
if (view instanceof TextCheckCell) {
|
||||
((TextCheckCell) view).setChecked(NekoXConfig.disableScreenshotDetection);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return fragmentView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
if (listAdapter != null) {
|
||||
listAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateRows() {
|
||||
rowCount = 0;
|
||||
|
||||
developerSettingsRow = rowCount++;
|
||||
|
||||
enableRow = rowCount++;
|
||||
|
||||
disableFlagSecureRow = rowCount++;
|
||||
disableScreenshotDetectionRow = rowCount++;
|
||||
|
||||
fetchAndExportLangRow = rowCount++;
|
||||
checkUpdateRepoForceRow = rowCount++;
|
||||
|
||||
if (listAdapter != null) {
|
||||
listAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public void fetchAndExportLang() {
|
||||
|
||||
AlertDialog pro = new AlertDialog(getParentActivity(), 3);
|
||||
|
||||
pro.show();
|
||||
|
||||
UIUtil.runOnIoDispatcher(() -> {
|
||||
|
||||
LocaleUtil.fetchAndExportLang();
|
||||
|
||||
File zipFile = new File(ApplicationLoader.applicationContext.getCacheDir(), "languages.zip");
|
||||
|
||||
FileUtil.delete(zipFile);
|
||||
|
||||
File[] files = LocaleUtil.cacheDir.listFiles();
|
||||
|
||||
if (files != null) {
|
||||
|
||||
try {
|
||||
|
||||
ZipUtil.makeZip(zipFile, LocaleUtil.cacheDir);
|
||||
|
||||
AndroidUtilities.runOnUIThread(() -> {
|
||||
|
||||
pro.dismiss();
|
||||
|
||||
ShareUtil.shareFile(getParentActivity(), zipFile);
|
||||
|
||||
});
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
AlertUtil.showToast(e);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
AlertUtil.showToast("No files");
|
||||
|
||||
AndroidUtilities.runOnUIThread(pro::dismiss);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<ThemeDescription> getThemeDescriptions() {
|
||||
ArrayList<ThemeDescription> themeDescriptions = new ArrayList<>();
|
||||
themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{EmptyCell.class, TextSettingsCell.class, TextCheckCell.class, HeaderCell.class, TextDetailSettingsCell.class, NotificationsCheckCell.class}, null, null, null, Theme.key_windowBackgroundWhite));
|
||||
themeDescriptions.add(new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundGray));
|
||||
|
||||
themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_avatar_backgroundActionBarBlue));
|
||||
themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_LISTGLOWCOLOR, null, null, null, null, Theme.key_avatar_backgroundActionBarBlue));
|
||||
themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_ITEMSCOLOR, null, null, null, null, Theme.key_avatar_actionBarIconBlue));
|
||||
themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_TITLECOLOR, null, null, null, null, Theme.key_actionBarDefaultTitle));
|
||||
themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SELECTORCOLOR, null, null, null, null, Theme.key_avatar_actionBarSelectorBlue));
|
||||
themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SUBMENUBACKGROUND, null, null, null, null, Theme.key_actionBarDefaultSubmenuBackground));
|
||||
themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SUBMENUITEM, null, null, null, null, Theme.key_actionBarDefaultSubmenuItem));
|
||||
|
||||
themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_SELECTOR, null, null, null, null, Theme.key_listSelector));
|
||||
|
||||
themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{View.class}, Theme.dividerPaint, null, null, Theme.key_divider));
|
||||
|
||||
themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{ShadowSectionCell.class}, null, null, null, Theme.key_windowBackgroundGrayShadow));
|
||||
|
||||
themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextSettingsCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
|
||||
themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextSettingsCell.class}, new String[]{"valueTextView"}, null, null, null, Theme.key_windowBackgroundWhiteValueText));
|
||||
|
||||
themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{NotificationsCheckCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
|
||||
themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{NotificationsCheckCell.class}, new String[]{"valueTextView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText2));
|
||||
themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{NotificationsCheckCell.class}, new String[]{"checkBox"}, null, null, null, Theme.key_switchTrack));
|
||||
themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{NotificationsCheckCell.class}, new String[]{"checkBox"}, null, null, null, Theme.key_switchTrackChecked));
|
||||
|
||||
themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCheckCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
|
||||
themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCheckCell.class}, new String[]{"valueTextView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText2));
|
||||
themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCheckCell.class}, new String[]{"checkBox"}, null, null, null, Theme.key_switchTrack));
|
||||
themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCheckCell.class}, new String[]{"checkBox"}, null, null, null, Theme.key_switchTrackChecked));
|
||||
|
||||
themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{HeaderCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueHeader));
|
||||
|
||||
themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextDetailSettingsCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText));
|
||||
themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextDetailSettingsCell.class}, new String[]{"valueTextView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText2));
|
||||
|
||||
return themeDescriptions;
|
||||
}
|
||||
|
||||
private class ListAdapter extends RecyclerListView.SelectionAdapter {
|
||||
|
||||
private Context mContext;
|
||||
|
||||
public ListAdapter(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return rowCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
|
||||
|
||||
// init
|
||||
|
||||
switch (holder.getItemViewType()) {
|
||||
|
||||
case 4: {
|
||||
HeaderCell headerCell = (HeaderCell) holder.itemView;
|
||||
if (position == developerSettingsRow) {
|
||||
headerCell.setText(LocaleController.getString("DeveloperSettings", R.string.DeveloperSettings));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: {
|
||||
TextCheckCell textCell = (TextCheckCell) holder.itemView;
|
||||
textCell.setEnabled(true, null);
|
||||
if (position == enableRow) {
|
||||
textCell.setTextAndCheck("Enable", NekoXConfig.developerMode, true);
|
||||
} else {
|
||||
if (!NekoXConfig.developerMode) {
|
||||
textCell.setEnabled(false);
|
||||
}
|
||||
if (position == disableFlagSecureRow) {
|
||||
textCell.setTextAndCheck("Disable Flag Secure", NekoXConfig.disableFlagSecure, true);
|
||||
} else if (position == disableScreenshotDetectionRow) {
|
||||
textCell.setTextAndCheck("Disable Screenshot Detection", NekoXConfig.disableScreenshotDetection, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
TextSettingsCell textCell = (TextSettingsCell) holder.itemView;
|
||||
if (!NekoXConfig.developerMode) {
|
||||
textCell.setEnabled(false);
|
||||
}
|
||||
if (position == fetchAndExportLangRow) {
|
||||
textCell.setText("Export Builtin Languages", true);
|
||||
} else if (position == checkUpdateRepoForceRow) {
|
||||
textCell.setText("Force Update (Repo)", false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(RecyclerView.ViewHolder holder) {
|
||||
int type = holder.getItemViewType();
|
||||
return (type == 2 || type == 3) && holder.itemView.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = null;
|
||||
switch (viewType) {
|
||||
case 1:
|
||||
view = new ShadowSectionCell(mContext);
|
||||
break;
|
||||
case 2:
|
||||
view = new TextSettingsCell(mContext);
|
||||
view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite));
|
||||
break;
|
||||
case 3:
|
||||
view = new TextCheckCell(mContext);
|
||||
view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite));
|
||||
break;
|
||||
case 4:
|
||||
view = new HeaderCell(mContext);
|
||||
view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite));
|
||||
break;
|
||||
case 5:
|
||||
view = new NotificationsCheckCell(mContext);
|
||||
view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite));
|
||||
break;
|
||||
case 6:
|
||||
view = new TextDetailSettingsCell(mContext);
|
||||
view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite));
|
||||
break;
|
||||
}
|
||||
view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT));
|
||||
return new RecyclerListView.Holder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
if (position == developerSettingsRow) {
|
||||
return 4;
|
||||
} else if (position == fetchAndExportLangRow || position == checkUpdateRepoForceRow) {
|
||||
return 2;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
package tw.nekomimi.nekogram.database
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import org.dizitart.no2.*
|
||||
import org.dizitart.no2.filters.Filters
|
||||
import org.telegram.messenger.FileLog
|
||||
import tw.nekomimi.nekogram.utils.UIUtil
|
||||
|
||||
class DbPref(val connection: NitriteCollection) : SharedPreferences {
|
||||
|
||||
init {
|
||||
if (!connection.hasIndex("key")) {
|
||||
connection.createIndex("key", IndexOptions.indexOptions(IndexType.Unique))
|
||||
}
|
||||
}
|
||||
|
||||
val listeners = LinkedHashSet<SharedPreferences.OnSharedPreferenceChangeListener>()
|
||||
|
||||
val isEmpty get() = connection.find(FindOptions.limit(0, 1)).count() == 0
|
||||
|
||||
private inline fun <reified T> getAs(key: String, defValue: T): T {
|
||||
connection.find(Filters.eq("key", key)).apply {
|
||||
runCatching {
|
||||
return first().get("value", T::class.java)
|
||||
}
|
||||
}
|
||||
return defValue
|
||||
}
|
||||
|
||||
override fun contains(key: String): Boolean {
|
||||
return connection.find(Filters.eq("key", key)).count() > 0
|
||||
}
|
||||
|
||||
override fun getBoolean(key: String, defValue: Boolean) = getAs(key, defValue)
|
||||
|
||||
override fun getInt(key: String, defValue: Int) = getAs(key, defValue)
|
||||
|
||||
override fun getAll(): MutableMap<String, *> {
|
||||
val allValues = HashMap<String, Any>()
|
||||
connection.find().forEach {
|
||||
allValues[it.get("key", String::class.java)] = it["value"]
|
||||
}
|
||||
return allValues
|
||||
}
|
||||
|
||||
override fun getLong(key: String, defValue: Long) = getAs(key, defValue)
|
||||
|
||||
override fun getFloat(key: String, defValue: Float) = getAs(key, defValue)
|
||||
|
||||
override fun getString(key: String, defValue: String?) = getAs(key, defValue)
|
||||
|
||||
override fun getStringSet(key: String, defValues: MutableSet<String>?) = getAs(key, defValues)
|
||||
|
||||
override fun unregisterOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) {
|
||||
listeners.remove(listener)
|
||||
}
|
||||
|
||||
override fun registerOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener?) {
|
||||
listener?.apply { listeners.add(this) }
|
||||
}
|
||||
|
||||
override fun edit(): PrefEditor {
|
||||
return PrefEditor()
|
||||
}
|
||||
|
||||
inner class PrefEditor : SharedPreferences.Editor {
|
||||
|
||||
private var clear = false
|
||||
private val toRemove = HashSet<String>()
|
||||
private val toApply = HashMap<String, Any?>()
|
||||
|
||||
override fun clear(): PrefEditor {
|
||||
clear = true
|
||||
return this
|
||||
}
|
||||
|
||||
override fun putLong(key: String, value: Long): PrefEditor {
|
||||
toApply[key] = value
|
||||
return this
|
||||
}
|
||||
|
||||
override fun putInt(key: String, value: Int): PrefEditor {
|
||||
toApply[key] = value
|
||||
return this
|
||||
}
|
||||
|
||||
override fun remove(key: String): PrefEditor {
|
||||
toApply.remove(key)
|
||||
toRemove.add(key)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun putBoolean(key: String, value: Boolean): PrefEditor {
|
||||
toApply[key] = value
|
||||
return this
|
||||
}
|
||||
|
||||
override fun putStringSet(key: String, values: MutableSet<String>?): PrefEditor {
|
||||
toApply[key] = values
|
||||
return this
|
||||
}
|
||||
|
||||
override fun putFloat(key: String, value: Float): PrefEditor {
|
||||
toApply[key] = value
|
||||
return this
|
||||
}
|
||||
|
||||
override fun putString(key: String, value: String?): PrefEditor {
|
||||
toApply[key] = value
|
||||
return this
|
||||
}
|
||||
|
||||
override fun commit(): Boolean {
|
||||
try {
|
||||
if (clear) {
|
||||
connection.remove(Filters.ALL)
|
||||
} else {
|
||||
toRemove.forEach {
|
||||
connection.remove(Filters.eq("key", it))
|
||||
}
|
||||
}
|
||||
toApply.forEach { (key, value) ->
|
||||
if (value == null) {
|
||||
connection.remove(Filters.eq("key", key))
|
||||
} else {
|
||||
connection.update(Filters.eq("key", key), Document().apply {
|
||||
put("key", key)
|
||||
put("value", value)
|
||||
}, UpdateOptions.updateOptions(true))
|
||||
}
|
||||
}
|
||||
return true
|
||||
} catch (ex: Exception) {
|
||||
FileLog.e(ex)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
override fun apply() {
|
||||
UIUtil.runOnIoDispatcher(Runnable { commit() } )
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package tw.nekomimi.nekogram.database
|
||||
|
||||
import org.dizitart.no2.Nitrite
|
||||
import org.telegram.messenger.ApplicationLoader
|
||||
import tw.nekomimi.nekogram.utils.FileUtil
|
||||
import java.io.File
|
||||
|
||||
fun mkDatabase(name: String): Nitrite {
|
||||
|
||||
File("${ApplicationLoader.getDataDirFixed()}/database").apply {
|
||||
|
||||
if (exists()) deleteRecursively()
|
||||
|
||||
}
|
||||
|
||||
val file = File("${ApplicationLoader.getDataDirFixed()}/databases/$name.db")
|
||||
|
||||
FileUtil.initDir(file.parentFile!!)
|
||||
|
||||
runCatching {
|
||||
|
||||
return Nitrite.builder().compressed()
|
||||
.filePath(file.path)
|
||||
.openOrCreate()!!
|
||||
|
||||
}
|
||||
|
||||
file.deleteRecursively()
|
||||
|
||||
return Nitrite.builder().compressed()
|
||||
.filePath(file.path)
|
||||
.openOrCreate()!!
|
||||
|
||||
}
|
||||
|
||||
fun mkCacheDatabase(name: String): Nitrite {
|
||||
|
||||
val file = File("${ApplicationLoader.getDataDirFixed()}/cache/$name.db")
|
||||
|
||||
FileUtil.initDir(file.parentFile!!)
|
||||
|
||||
runCatching {
|
||||
|
||||
return Nitrite.builder().compressed()
|
||||
.filePath(file.path)
|
||||
.openOrCreate()!!
|
||||
|
||||
}
|
||||
|
||||
file.deleteRecursively()
|
||||
|
||||
return Nitrite.builder().compressed()
|
||||
.filePath(file.path)
|
||||
.openOrCreate()!!
|
||||
|
||||
}
|
||||
|
||||
fun Nitrite.openSharedPreference(name: String) = DbPref(getCollection(name))
|
||||
|
||||
private lateinit var mainSharedPreferencesDatabase: Nitrite
|
||||
|
||||
fun openMainSharedPreference(name: String): DbPref {
|
||||
|
||||
if (!::mainSharedPreferencesDatabase.isInitialized) {
|
||||
|
||||
mainSharedPreferencesDatabase = mkDatabase("shared_preferences")
|
||||
|
||||
}
|
||||
|
||||
return mainSharedPreferencesDatabase.openSharedPreference(name)
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package tw.nekomimi.nekogram.database
|
||||
|
||||
import android.content.SharedPreferences
|
||||
|
||||
class WarppedPref(val origin: SharedPreferences) : SharedPreferences by origin {
|
||||
|
||||
override fun getBoolean(key: String, defValue: Boolean): Boolean {
|
||||
return try {
|
||||
origin.getBoolean(key, defValue)
|
||||
} catch (e: ClassCastException) {
|
||||
edit().remove(key).apply()
|
||||
defValue
|
||||
}
|
||||
}
|
||||
|
||||
override fun getInt(key: String, defValue: Int): Int {
|
||||
return try {
|
||||
origin.getInt(key, defValue)
|
||||
} catch (e: ClassCastException) {
|
||||
edit().remove(key).apply()
|
||||
defValue
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLong(key: String, defValue: Long): Long {
|
||||
return try {
|
||||
origin.getLong(key, defValue)
|
||||
} catch (e: ClassCastException) {
|
||||
edit().remove(key).apply()
|
||||
defValue
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFloat(key: String, defValue: Float): Float {
|
||||
return try {
|
||||
origin.getFloat(key, defValue)
|
||||
} catch (e: java.lang.ClassCastException) {
|
||||
edit().remove(key).apply()
|
||||
defValue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun getString(key: String, defValue: String?): String? {
|
||||
return try {
|
||||
origin.getString(key, defValue)
|
||||
} catch (e: java.lang.ClassCastException) {
|
||||
edit().remove(key).apply()
|
||||
defValue
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package tw.nekomimi.nekogram.parts;
|
||||
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
|
||||
public class PKCS1Pub {
|
||||
|
||||
private static final int SEQUENCE_TAG = 0x30;
|
||||
private static final int BIT_STRING_TAG = 0x03;
|
||||
private static final byte[] NO_UNUSED_BITS = new byte[] { 0x00 };
|
||||
private static final byte[] RSA_ALGORITHM_IDENTIFIER_SEQUENCE =
|
||||
{(byte) 0x30, (byte) 0x0d,
|
||||
(byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x01,
|
||||
(byte) 0x05, (byte) 0x00};
|
||||
|
||||
|
||||
public static RSAPublicKey decodePKCS1PublicKey(byte[] pkcs1PublicKeyEncoding)
|
||||
throws NoSuchAlgorithmException, InvalidKeySpecException
|
||||
{
|
||||
byte[] subjectPublicKeyInfo2 = createSubjectPublicKeyInfoEncoding(pkcs1PublicKeyEncoding);
|
||||
KeyFactory rsaKeyFactory = KeyFactory.getInstance("RSA");
|
||||
RSAPublicKey generatePublic = (RSAPublicKey) rsaKeyFactory.generatePublic(new X509EncodedKeySpec(subjectPublicKeyInfo2));
|
||||
return generatePublic;
|
||||
}
|
||||
|
||||
public static byte[] createSubjectPublicKeyInfoEncoding(byte[] pkcs1PublicKeyEncoding)
|
||||
{
|
||||
byte[] subjectPublicKeyBitString = createDEREncoding(BIT_STRING_TAG, concat(NO_UNUSED_BITS, pkcs1PublicKeyEncoding));
|
||||
byte[] subjectPublicKeyInfoValue = concat(RSA_ALGORITHM_IDENTIFIER_SEQUENCE, subjectPublicKeyBitString);
|
||||
byte[] subjectPublicKeyInfoSequence = createDEREncoding(SEQUENCE_TAG, subjectPublicKeyInfoValue);
|
||||
|
||||
return subjectPublicKeyInfoSequence;
|
||||
}
|
||||
|
||||
private static byte[] concat(byte[] ... bas)
|
||||
{
|
||||
int len = 0;
|
||||
for (int i = 0; i < bas.length; i++)
|
||||
{
|
||||
len += bas[i].length;
|
||||
}
|
||||
|
||||
byte[] buf = new byte[len];
|
||||
int off = 0;
|
||||
for (int i = 0; i < bas.length; i++)
|
||||
{
|
||||
System.arraycopy(bas[i], 0, buf, off, bas[i].length);
|
||||
off += bas[i].length;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
private static byte[] createDEREncoding(int tag, byte[] value)
|
||||
{
|
||||
if (tag < 0 || tag >= 0xFF)
|
||||
{
|
||||
throw new IllegalArgumentException("Currently only single byte tags supported");
|
||||
}
|
||||
|
||||
byte[] lengthEncoding = createDERLengthEncoding(value.length);
|
||||
|
||||
int size = 1 + lengthEncoding.length + value.length;
|
||||
byte[] derEncodingBuf = new byte[size];
|
||||
|
||||
int off = 0;
|
||||
derEncodingBuf[off++] = (byte) tag;
|
||||
System.arraycopy(lengthEncoding, 0, derEncodingBuf, off, lengthEncoding.length);
|
||||
off += lengthEncoding.length;
|
||||
System.arraycopy(value, 0, derEncodingBuf, off, value.length);
|
||||
|
||||
return derEncodingBuf;
|
||||
}
|
||||
|
||||
private static byte[] createDERLengthEncoding(int size)
|
||||
{
|
||||
if (size <= 0x7F)
|
||||
{
|
||||
// single byte length encoding
|
||||
return new byte[] { (byte) size };
|
||||
}
|
||||
else if (size <= 0xFF)
|
||||
{
|
||||
// double byte length encoding
|
||||
return new byte[] { (byte) 0x81, (byte) size };
|
||||
}
|
||||
else if (size <= 0xFFFF)
|
||||
{
|
||||
// triple byte length encoding
|
||||
return new byte[] { (byte) 0x82, (byte) (size >> Byte.SIZE), (byte) size };
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("size too large, only up to 64KiB length encoding supported: " + size);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,232 @@
|
|||
package tw.nekomimi.nekogram.parts
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.IntentSender
|
||||
import com.google.android.play.core.appupdate.AppUpdateManagerFactory
|
||||
import com.google.android.play.core.install.InstallStateUpdatedListener
|
||||
import com.google.android.play.core.install.model.AppUpdateType
|
||||
import com.google.android.play.core.install.model.InstallStatus
|
||||
import com.google.android.play.core.install.model.UpdateAvailability
|
||||
import org.json.JSONObject
|
||||
import org.telegram.messenger.BuildConfig
|
||||
import org.telegram.messenger.LocaleController
|
||||
import org.telegram.messenger.R
|
||||
import org.telegram.ui.Cells.TextCell
|
||||
import tw.nekomimi.nekogram.BottomBuilder
|
||||
import tw.nekomimi.nekogram.ExternalGcm
|
||||
import tw.nekomimi.nekogram.NekoXConfig
|
||||
import tw.nekomimi.nekogram.utils.*
|
||||
import java.util.*
|
||||
|
||||
fun Activity.switchVersion() {
|
||||
|
||||
val builder = BottomBuilder(this)
|
||||
|
||||
builder.addItems(arrayOf(
|
||||
"Mini Release",
|
||||
"Mini Release NoGcm",
|
||||
"Full Release",
|
||||
"Full Release NoGcm"
|
||||
).filterIndexed { index, text ->
|
||||
|
||||
!(BuildConfig.BUILD_TYPE == when {
|
||||
text.endsWith("NoGcm") -> "releaseNoGcm"
|
||||
else -> "release"
|
||||
} && BuildConfig.FLAVOR == text.substringBefore(" ").toLowerCase())
|
||||
|
||||
}.toTypedArray()) { index: Int, text: String, _: TextCell ->
|
||||
|
||||
builder.dismiss()
|
||||
|
||||
val buildType = when {
|
||||
text.endsWith("NoGcm") -> "releaseNoGcm"
|
||||
else -> "release"
|
||||
}
|
||||
|
||||
val flavor = text.substringBefore(" ").toLowerCase()
|
||||
|
||||
val progress = AlertUtil.showProgress(this)
|
||||
|
||||
progress.show()
|
||||
|
||||
UIUtil.runOnIoDispatcher {
|
||||
|
||||
val ex = mutableListOf<Throwable>()
|
||||
|
||||
UpdateUtil.updateUrls.forEach { url ->
|
||||
|
||||
runCatching {
|
||||
|
||||
val updateInfo = JSONObject(HttpUtil.get("$url/update.json"))
|
||||
|
||||
val code = updateInfo.getInt("versionCode")
|
||||
|
||||
UIUtil.runOnUIThread {
|
||||
|
||||
progress.dismiss()
|
||||
|
||||
UpdateUtil.doUpdate(this, code, updateInfo.getString("defaultFlavor"), buildType, flavor)
|
||||
|
||||
}
|
||||
|
||||
return@runOnIoDispatcher
|
||||
|
||||
}.onFailure {
|
||||
|
||||
ex.add(it)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
progress.dismiss()
|
||||
|
||||
AlertUtil.showToast(ex.joinToString("\n") { it.message ?: it.javaClass.simpleName })
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
builder.show()
|
||||
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun Activity.checkUpdate(force: Boolean = false) {
|
||||
|
||||
val progress = AlertUtil.showProgress(this)
|
||||
|
||||
progress.show()
|
||||
|
||||
UIUtil.runOnIoDispatcher {
|
||||
|
||||
if (ExternalGcm.checkPlayServices() && !force) {
|
||||
|
||||
progress.uUpdate(LocaleController.getString("Checking", R.string.Checking) + " (Play Store)")
|
||||
|
||||
val manager = AppUpdateManagerFactory.create(this)
|
||||
|
||||
manager.registerListener(InstallStateUpdatedListener {
|
||||
|
||||
if (it.installStatus() == InstallStatus.DOWNLOADED) {
|
||||
|
||||
val builder = BottomBuilder(this)
|
||||
|
||||
builder.addTitle(LocaleController.getString("UpdateDownloaded", R.string.UpdateDownloaded), false)
|
||||
|
||||
builder.addItem(LocaleController.getString("UpdateUpdate", R.string.UpdateUpdate), R.drawable.baseline_system_update_24, false) {
|
||||
|
||||
manager.completeUpdate()
|
||||
|
||||
}
|
||||
|
||||
builder.addItem(LocaleController.getString("UpdateLater", R.string.UpdateLater), R.drawable.baseline_watch_later_24, false, null)
|
||||
|
||||
builder.show()
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
manager.appUpdateInfo.addOnSuccessListener {
|
||||
|
||||
progress.dismiss()
|
||||
|
||||
if (it.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE && it.availableVersionCode() > BuildConfig.VERSION_CODE) {
|
||||
|
||||
try {
|
||||
|
||||
manager.startUpdateFlowForResult(it, AppUpdateType.FLEXIBLE, this, 114514)
|
||||
|
||||
} catch (ignored: IntentSender.SendIntentException) {
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
AlertUtil.showToast(LocaleController.getString("NoUpdate", R.string.NoUpdate))
|
||||
|
||||
}
|
||||
|
||||
}.addOnFailureListener {
|
||||
|
||||
progress.uDismiss()
|
||||
|
||||
AlertUtil.showToast(it.message ?: it.javaClass.simpleName)
|
||||
|
||||
}
|
||||
|
||||
return@runOnIoDispatcher
|
||||
|
||||
}
|
||||
|
||||
progress.uUpdate(LocaleController.getString("Checking", R.string.Checking) + " (Repo)")
|
||||
|
||||
val ex = LinkedList<Throwable>()
|
||||
|
||||
UpdateUtil.updateUrls.forEach { url ->
|
||||
|
||||
runCatching {
|
||||
|
||||
val updateInfo = JSONObject(HttpUtil.get("$url/update.json"))
|
||||
|
||||
val code = updateInfo.getInt("versionCode")
|
||||
|
||||
progress.uDismiss()
|
||||
|
||||
if (code > BuildConfig.VERSION_CODE || force) UIUtil.runOnUIThread {
|
||||
|
||||
val builder = BottomBuilder(this)
|
||||
|
||||
builder.addTitle(LocaleController.getString("UpdateAvailable", R.string.UpdateAvailable), updateInfo.getString("version"))
|
||||
|
||||
builder.addItem(LocaleController.getString("UpdateUpdate", R.string.UpdateUpdate), R.drawable.baseline_system_update_24, false) {
|
||||
|
||||
UpdateUtil.doUpdate(this, code, updateInfo.getString("defaultFlavor"))
|
||||
|
||||
builder.dismiss()
|
||||
|
||||
NekoXConfig.preferences.edit().remove("ignored_update_at").remove("ignore_update_at").apply()
|
||||
|
||||
}
|
||||
|
||||
builder.addItem(LocaleController.getString("UpdateLater", R.string.UpdateLater), R.drawable.baseline_watch_later_24, false) {
|
||||
|
||||
builder.dismiss()
|
||||
|
||||
NekoXConfig.preferences.edit().putLong("ignored_update_at", System.currentTimeMillis()).apply()
|
||||
|
||||
}
|
||||
|
||||
builder.addItem(LocaleController.getString("Ignore", R.string.Ignore), R.drawable.baseline_block_24, true) {
|
||||
|
||||
builder.dismiss()
|
||||
|
||||
NekoXConfig.preferences.edit().putInt("ignore_update", code).apply()
|
||||
|
||||
}
|
||||
|
||||
builder.show()
|
||||
|
||||
} else {
|
||||
|
||||
AlertUtil.showToast(LocaleController.getString("NoUpdate", R.string.NoUpdate))
|
||||
|
||||
}
|
||||
|
||||
return@runOnIoDispatcher
|
||||
|
||||
}.onFailure {
|
||||
|
||||
ex.add(it)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
progress.uDismiss()
|
||||
|
||||
AlertUtil.showToast(ex.joinToString("\n") { it.message ?: it.javaClass.simpleName })
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,303 @@
|
|||
package tw.nekomimi.nekogram.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.Toast
|
||||
import org.telegram.messenger.AndroidUtilities
|
||||
import org.telegram.messenger.ApplicationLoader
|
||||
import org.telegram.messenger.LocaleController
|
||||
import org.telegram.messenger.R
|
||||
import org.telegram.tgnet.TLRPC
|
||||
import org.telegram.ui.ActionBar.AlertDialog
|
||||
import org.telegram.ui.Components.EditTextBoldCursor
|
||||
import org.telegram.ui.Components.NumberPicker
|
||||
import tw.nekomimi.nekogram.BottomBuilder
|
||||
import tw.nekomimi.nekogram.NekoConfig
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
object AlertUtil {
|
||||
|
||||
@JvmStatic
|
||||
fun showToast(e: Throwable) = showToast(e.message ?: e.javaClass.simpleName)
|
||||
|
||||
@JvmStatic
|
||||
fun showToast(e: TLRPC.TL_error) = showToast("${e.code}: ${e.text}")
|
||||
|
||||
@JvmStatic
|
||||
fun showToast(text: String) = UIUtil.runOnUIThread(Runnable {
|
||||
Toast.makeText(
|
||||
ApplicationLoader.applicationContext,
|
||||
text.takeIf { it.isNotBlank() }
|
||||
?: "喵 !",
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
})
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun showSimpleAlert(ctx: Context?, text: String, listener: ((AlertDialog.Builder) -> Unit)? = null) {
|
||||
|
||||
showSimpleAlert(ctx,null, text, listener)
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun showSimpleAlert(ctx: Context?,title: String?, text: String, listener: ((AlertDialog.Builder) -> Unit)? = null) = UIUtil.runOnUIThread(Runnable {
|
||||
|
||||
if(ctx == null) return@Runnable
|
||||
|
||||
val builder = AlertDialog.Builder(ctx)
|
||||
|
||||
builder.setTitle(title ?: LocaleController.getString("NekoX", R.string.NekoX))
|
||||
builder.setMessage(text)
|
||||
|
||||
if (listener != null) {
|
||||
|
||||
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK)) { _, _ ->
|
||||
|
||||
builder.dismissRunnable.run()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
builder.show()
|
||||
|
||||
})
|
||||
|
||||
@JvmStatic
|
||||
fun showCopyAlert(ctx: Context, text: String) = UIUtil.runOnUIThread(Runnable {
|
||||
|
||||
val builder = AlertDialog.Builder(ctx)
|
||||
|
||||
builder.setTitle(LocaleController.getString("Translate", R.string.Translate))
|
||||
builder.setMessage(text)
|
||||
|
||||
builder.setNegativeButton(LocaleController.getString("Copy", R.string.Copy)) { _, _ ->
|
||||
|
||||
AndroidUtilities.addToClipboard(text)
|
||||
|
||||
AlertUtil.showToast(LocaleController.getString("TextCopied", R.string.TextCopied))
|
||||
|
||||
builder.dismissRunnable.run()
|
||||
|
||||
}
|
||||
|
||||
builder.setPositiveButton(LocaleController.getString("OK", R.string.OK)) { _, _ ->
|
||||
|
||||
builder.dismissRunnable.run()
|
||||
|
||||
}
|
||||
|
||||
builder.show()
|
||||
|
||||
})
|
||||
|
||||
@JvmOverloads
|
||||
@JvmStatic
|
||||
fun showProgress(ctx: Context, text: String = LocaleController.getString("Loading", R.string.Loading)): AlertDialog {
|
||||
|
||||
return AlertDialog.Builder(ctx, 1).apply {
|
||||
|
||||
setMessage(text)
|
||||
|
||||
}.create()
|
||||
|
||||
}
|
||||
|
||||
fun showInput(ctx: Context, title: String, hint: String, onInput: (AlertDialog.Builder, String) -> String) = UIUtil.runOnUIThread(Runnable {
|
||||
|
||||
val builder = AlertDialog.Builder(ctx)
|
||||
|
||||
builder.setTitle(title)
|
||||
|
||||
builder.setView(EditTextBoldCursor(ctx).apply {
|
||||
|
||||
setHintText(hint)
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun showConfirm(ctx: Context, title: String, text: String? = null, icon: Int, button: String, red: Boolean, listener: Runnable) = UIUtil.runOnUIThread(Runnable {
|
||||
|
||||
/*
|
||||
|
||||
val builder = AlertDialog.Builder(ctx)
|
||||
|
||||
builder.setTitle(title)
|
||||
|
||||
builder.setMessage(AndroidUtilities.replaceTags(text))
|
||||
builder.setPositiveButton(button, listener)
|
||||
|
||||
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null)
|
||||
val alertDialog = builder.show()
|
||||
|
||||
if (red) {
|
||||
|
||||
(alertDialog.getButton(DialogInterface.BUTTON_POSITIVE) as TextView?)?.setTextColor(Theme.getColor(Theme.key_dialogTextRed2))
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
val builder = BottomBuilder(ctx)
|
||||
|
||||
if (text != null) {
|
||||
|
||||
builder.addTitle(title, text)
|
||||
|
||||
} else {
|
||||
|
||||
builder.addTitle(title)
|
||||
|
||||
}
|
||||
|
||||
builder.addItem(button, icon, red) {
|
||||
|
||||
builder.dismiss()
|
||||
|
||||
listener.run()
|
||||
|
||||
}
|
||||
|
||||
builder.addCancelItem()
|
||||
|
||||
builder.show()
|
||||
|
||||
})
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun showTransFailedDialog(ctx: Context, noRetry: Boolean, noWeb: Boolean = false, message: String, retryRunnable: Runnable) = UIUtil.runOnUIThread(Runnable {
|
||||
|
||||
ctx.setTheme(R.style.Theme_TMessages)
|
||||
|
||||
val builder = AlertDialog.Builder(ctx)
|
||||
|
||||
builder.setTitle(LocaleController.getString("TranslateFailed", R.string.TranslateFailed))
|
||||
|
||||
builder.setMessage(message)
|
||||
|
||||
val reference = AtomicReference<AlertDialog>()
|
||||
|
||||
builder.setNeutralButton(LocaleController.getString("ChangeTranslateProvider", R.string.ChangeTranslateProvider)) {
|
||||
|
||||
_, _ ->
|
||||
|
||||
val view = reference.get().getButton(AlertDialog.BUTTON_NEUTRAL)
|
||||
|
||||
val popup = PopupBuilder(view, true)
|
||||
|
||||
val items = LinkedList<String>()
|
||||
|
||||
items.addAll(arrayOf(
|
||||
LocaleController.getString("ProviderGoogleTranslate", R.string.ProviderGoogleTranslate),
|
||||
LocaleController.getString("ProviderGoogleTranslateCN", R.string.ProviderGoogleTranslateCN),
|
||||
LocaleController.getString("ProviderYandexTranslate", R.string.ProviderYandexTranslate),
|
||||
LocaleController.getString("ProviderLingocloud", R.string.ProviderLingocloud)
|
||||
))
|
||||
|
||||
if (!noWeb) {
|
||||
|
||||
items.addAll(arrayOf(
|
||||
LocaleController.getString("ProviderGoogleTranslateWeb", R.string.ProviderGoogleTranslateWeb),
|
||||
LocaleController.getString("ProviderGoogleTranslateCNWeb", R.string.ProviderGoogleTranslateCNWeb),
|
||||
LocaleController.getString("ProviderBaiduFanyiWeb", R.string.ProviderBaiduFanyiWeb),
|
||||
LocaleController.getString("ProviderDeepLWeb", R.string.ProviderDeepLWeb)
|
||||
))
|
||||
|
||||
}
|
||||
|
||||
popup.setItems(items.toTypedArray()) { item, _ ->
|
||||
|
||||
reference.get().dismiss()
|
||||
|
||||
NekoConfig.setTranslationProvider(if (item < 4) item + 1 else -item + 3)
|
||||
|
||||
retryRunnable.run()
|
||||
|
||||
}
|
||||
|
||||
popup.show()
|
||||
|
||||
}
|
||||
|
||||
if (noRetry) {
|
||||
|
||||
builder.setPositiveButton(LocaleController.getString("Cancel", R.string.Cancel)) { _, _ ->
|
||||
|
||||
reference.get().dismiss()
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
builder.setPositiveButton(LocaleController.getString("Retry", R.string.Retry)) { _, _ ->
|
||||
|
||||
reference.get().dismiss()
|
||||
|
||||
retryRunnable.run()
|
||||
|
||||
}
|
||||
|
||||
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel)) { _, _ ->
|
||||
|
||||
reference.get().dismiss()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
reference.set(builder.create().apply {
|
||||
|
||||
setDismissDialogByButtons(false)
|
||||
show()
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
fun showTimePicker(ctx: Context, title: String, callback: (Long) -> Unit) {
|
||||
|
||||
ctx.setTheme(R.style.Theme_TMessages)
|
||||
|
||||
val builder = AlertDialog.Builder(ctx)
|
||||
|
||||
builder.setTitle(title)
|
||||
|
||||
builder.setView(LinearLayout(ctx).apply {
|
||||
|
||||
orientation = LinearLayout.HORIZONTAL
|
||||
|
||||
addView(NumberPicker(ctx).apply {
|
||||
|
||||
minValue = 0
|
||||
maxValue = 60
|
||||
|
||||
}, LinearLayout.LayoutParams(-2, -2).apply {
|
||||
|
||||
weight = 1F
|
||||
|
||||
})
|
||||
|
||||
addView(NumberPicker(ctx).apply {
|
||||
|
||||
minValue = 0
|
||||
maxValue = 60
|
||||
|
||||
}, LinearLayout.LayoutParams(-2, -2).apply {
|
||||
|
||||
weight = 1F
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package tw.nekomimi.nekogram.utils
|
||||
|
||||
import okhttp3.Dns
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.dnsoverhttps.DnsOverHttps
|
||||
import org.telegram.tgnet.ConnectionsManager
|
||||
import org.xbill.DNS.DohResolver
|
||||
import org.xbill.DNS.Lookup
|
||||
import org.xbill.DNS.TXTRecord
|
||||
import org.xbill.DNS.Type
|
||||
import java.net.InetAddress
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
open class DnsFactory : Dns {
|
||||
|
||||
companion object : DnsFactory() {
|
||||
|
||||
init {
|
||||
|
||||
addProvider("https://mozilla.cloudflare-dns.com/dns-query")
|
||||
addProvider("https://dns.google/dns-query")
|
||||
addProvider("https://dns.twnic.tw/dns-query")
|
||||
addProvider("https://dns.adguard.com/dns-query")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
val providers = LinkedList<DnsOverHttps>()
|
||||
val dnsJavaProviders = LinkedList<DohResolver>()
|
||||
|
||||
val client = OkHttpClient.Builder().connectTimeout(3,TimeUnit.SECONDS).build()
|
||||
|
||||
fun addProvider(url: String) {
|
||||
|
||||
providers.add(DnsOverHttps.Builder()
|
||||
.client(client)
|
||||
.url(url.toHttpUrl())
|
||||
.includeIPv6(ConnectionsManager.useIpv6Address())
|
||||
.build())
|
||||
|
||||
}
|
||||
|
||||
override fun lookup(hostname: String): List<InetAddress> {
|
||||
|
||||
providers.forEach {
|
||||
|
||||
runCatching {
|
||||
|
||||
return it.lookup(hostname)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
runCatching {
|
||||
|
||||
return Dns.SYSTEM.lookup(hostname)
|
||||
|
||||
}
|
||||
|
||||
return listOf()
|
||||
|
||||
}
|
||||
|
||||
fun getTxts(domain: String): ArrayList<String> {
|
||||
|
||||
val results = ArrayList<String>()
|
||||
|
||||
dnsJavaProviders.forEach {
|
||||
|
||||
runCatching {
|
||||
|
||||
val lookup = Lookup(domain, Type.TXT)
|
||||
|
||||
lookup.setResolver(it)
|
||||
|
||||
lookup.run()
|
||||
|
||||
if (lookup.result == Lookup.SUCCESSFUL) {
|
||||
|
||||
lookup.answers.forEach {
|
||||
|
||||
(it as TXTRecord).strings.forEach {
|
||||
|
||||
results.add(it)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return results
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package tw.nekomimi.nekogram.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.os.storage.StorageManager
|
||||
import org.telegram.messenger.ApplicationLoader
|
||||
import org.telegram.messenger.FileLog
|
||||
import tw.nekomimi.nekogram.NekoConfig
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
object EnvUtil {
|
||||
|
||||
@JvmStatic
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val rootDirectories by lazy {
|
||||
|
||||
val mStorageManager = ApplicationLoader.applicationContext.getSystemService(Context.STORAGE_SERVICE) as StorageManager
|
||||
|
||||
(mStorageManager.javaClass.getMethod("getVolumePaths").invoke(mStorageManager) as Array<String>).map { File(it) }
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
val availableDirectories
|
||||
get() = LinkedList<File>().apply {
|
||||
|
||||
add(File(ApplicationLoader.getDataDirFixed(), "files/media"))
|
||||
add(File(ApplicationLoader.getDataDirFixed(), "cache/media"))
|
||||
|
||||
rootDirectories.forEach {
|
||||
|
||||
add(File(it, "Android/data/" + ApplicationLoader.applicationContext.packageName + "/files"))
|
||||
add(File(it, "Android/data/" + ApplicationLoader.applicationContext.packageName + "/cache"))
|
||||
|
||||
}
|
||||
|
||||
}.map { it.path }.toTypedArray()
|
||||
|
||||
@JvmStatic
|
||||
fun getTelegramPath(): File {
|
||||
|
||||
if (NekoConfig.cachePath == null) {
|
||||
|
||||
NekoConfig.setCachePath(ApplicationLoader.applicationContext.getExternalFilesDir(null)!!.path)
|
||||
|
||||
}
|
||||
|
||||
var telegramPath = File(NekoConfig.cachePath)
|
||||
|
||||
if (telegramPath.isDirectory || telegramPath.mkdirs()) {
|
||||
|
||||
return telegramPath
|
||||
|
||||
}
|
||||
|
||||
telegramPath = ApplicationLoader.applicationContext.getExternalFilesDir(null) ?: File(ApplicationLoader.getDataDirFixed(), "cache/files")
|
||||
|
||||
if (telegramPath.isDirectory || telegramPath.mkdirs()) {
|
||||
|
||||
return telegramPath
|
||||
|
||||
}
|
||||
|
||||
telegramPath = File(ApplicationLoader.getDataDirFixed(), "cache/files")
|
||||
|
||||
if (!telegramPath.isDirectory) telegramPath.mkdirs();
|
||||
|
||||
return telegramPath;
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun doTest() {
|
||||
|
||||
FileLog.d("rootDirectories: ${rootDirectories.size}")
|
||||
|
||||
rootDirectories.forEach { FileLog.d(it.path) }
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,279 @@
|
|||
package tw.nekomimi.nekogram.utils
|
||||
|
||||
import android.os.Build
|
||||
import cn.hutool.core.io.resource.ResourceUtil
|
||||
import org.telegram.messenger.ApplicationLoader
|
||||
import org.telegram.messenger.FileLog
|
||||
import java.io.File
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
object FileUtil {
|
||||
|
||||
@JvmStatic
|
||||
fun initDir(dir: File) {
|
||||
|
||||
var parentDir: File? = dir
|
||||
|
||||
while (parentDir != null) {
|
||||
|
||||
if (parentDir.isDirectory) break
|
||||
|
||||
if (parentDir.isFile) parentDir.deleteRecursively()
|
||||
|
||||
parentDir = parentDir.parentFile
|
||||
|
||||
}
|
||||
|
||||
dir.mkdirs()
|
||||
|
||||
// ignored
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun delete(file: File?, filter: (File) -> Boolean = { true }) {
|
||||
|
||||
runCatching {
|
||||
|
||||
file?.takeIf { filter(it) }?.deleteRecursively()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun initFile(file: File) {
|
||||
|
||||
file.parentFile?.also { initDir(it) }
|
||||
|
||||
if (!file.isFile) {
|
||||
|
||||
if (file.isDirectory) file.deleteRecursively()
|
||||
|
||||
if (!file.isFile) {
|
||||
|
||||
if (!file.createNewFile() && !file.isFile) {
|
||||
|
||||
error("unable to create file ${file.path}")
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun readUtf8String(file: File) = file.readText()
|
||||
|
||||
@JvmStatic
|
||||
fun writeUtf8String(text: String, save: File) {
|
||||
|
||||
initFile(save)
|
||||
|
||||
save.writeText(text)
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun saveAsset(path: String, saveTo: File) {
|
||||
|
||||
val assets = ApplicationLoader.applicationContext.assets
|
||||
|
||||
saveTo.outputStream().use {
|
||||
|
||||
IoUtil.copy(assets.open(path), it)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Suppress("DEPRECATION") val abi by lazy {
|
||||
|
||||
val libDirs = mutableListOf<String>()
|
||||
|
||||
ZipFile(ApplicationLoader.applicationContext.applicationInfo.sourceDir).use {
|
||||
|
||||
it.getEntry("lib/") ?: return@use
|
||||
|
||||
for (entry in it.entries()) {
|
||||
|
||||
if (entry.isDirectory && it.name.length > 4 && it.name.startsWith("lib/")) {
|
||||
|
||||
libDirs.add(entry.name.substringAfter("lib/").substringBefore("/"))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
|
||||
ApplicationLoader.applicationContext.applicationInfo.splitSourceDirs?.forEach { split ->
|
||||
|
||||
ZipFile(split).use {
|
||||
|
||||
it.getEntry("lib/") ?: return@use
|
||||
|
||||
for (entry in it.entries()) {
|
||||
|
||||
if (entry.isDirectory && it.name.length > 4 && it.name.startsWith("lib/")) {
|
||||
|
||||
libDirs.add(entry.name.substringAfter("lib/").substringBefore("/"))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (libDirs.size == 1) libDirs[0] else {
|
||||
|
||||
Build.CPU_ABI.toLowerCase()
|
||||
|
||||
}.also {
|
||||
|
||||
FileLog.d("current abi: $it")
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun extLib(name: String): File {
|
||||
|
||||
val execFile = File(ApplicationLoader.applicationContext.applicationInfo.nativeLibraryDir, "lib$name.so")
|
||||
|
||||
if (execFile.isFile && execFile.canExecute()) return execFile
|
||||
|
||||
val newFile = File(ApplicationLoader.getDataDirFixed(), "cache/lib/${execFile.name}")
|
||||
|
||||
if (newFile.isFile) {
|
||||
|
||||
FileLog.d("lib already extracted: $newFile")
|
||||
|
||||
if (!newFile.canExecute()) {
|
||||
|
||||
newFile.setExecutable(true)
|
||||
|
||||
}
|
||||
|
||||
return newFile
|
||||
|
||||
}
|
||||
|
||||
if (execFile.isFile) {
|
||||
|
||||
FileLog.w("$execFile not executable")
|
||||
|
||||
if (!newFile.isFile) {
|
||||
|
||||
execFile.copyTo(newFile)
|
||||
|
||||
}
|
||||
|
||||
if (!newFile.canExecute()) {
|
||||
|
||||
newFile.setExecutable(true)
|
||||
|
||||
}
|
||||
|
||||
return newFile
|
||||
|
||||
}
|
||||
|
||||
if (!newFile.isFile) {
|
||||
|
||||
runCatching {
|
||||
|
||||
saveNonAsset("lib/${Build.CPU_ABI}/${execFile.name}", execFile)
|
||||
|
||||
FileLog.d("lib extracted with default abi: $execFile, ${Build.CPU_ABI}")
|
||||
|
||||
}.recover {
|
||||
|
||||
saveNonAsset("lib/${Build.CPU_ABI2}/${execFile.name}", execFile)
|
||||
|
||||
FileLog.d("lib extracted with abi2: $execFile, ${Build.CPU_ABI2}")
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!execFile.canExecute()) {
|
||||
|
||||
execFile.setExecutable(true)
|
||||
|
||||
}
|
||||
|
||||
return execFile
|
||||
|
||||
}
|
||||
|
||||
|
||||
@JvmStatic
|
||||
fun saveNonAsset(path: String, saveTo: File) {
|
||||
|
||||
runCatching {
|
||||
|
||||
ResourceUtil.getStream(path).use {
|
||||
|
||||
FileLog.d("found nonAsset in resources: $path")
|
||||
|
||||
IoUtil.copy(it, saveTo)
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ZipFile(ApplicationLoader.applicationContext.applicationInfo.sourceDir).use {
|
||||
|
||||
it.getInputStream(it.getEntry(path) ?: return@use).use { ins ->
|
||||
|
||||
FileLog.d("found nonAsset in main apk: $path")
|
||||
|
||||
IoUtil.copy(ins, saveTo)
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
|
||||
ApplicationLoader.applicationContext.applicationInfo.splitSourceDirs?.forEach { split ->
|
||||
|
||||
ZipFile(split).use {
|
||||
|
||||
it.getInputStream(it.getEntry(path) ?: return@use).use { ins ->
|
||||
|
||||
FileLog.d("found nonAsset in split apk: $path, $split")
|
||||
|
||||
IoUtil.copy(ins, saveTo)
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
error("res not found: $path")
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package tw.nekomimi.nekogram.utils
|
||||
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.telegram.messenger.SharedConfig
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.Proxy
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
fun Request.Builder.applyUserAgent(): Request.Builder {
|
||||
|
||||
header("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0 like Mac OS X) AppleWebKit/602.1.38 (KHTML, like Gecko) Version/10.0 Mobile/14A5297c Safari/602.1")
|
||||
header("X-Requested-With", "XMLHttpRequest")
|
||||
|
||||
return this
|
||||
|
||||
}
|
||||
|
||||
object HttpUtil {
|
||||
|
||||
@JvmField
|
||||
val okHttpClient = OkHttpClient().newBuilder()
|
||||
.dns(DnsFactory)
|
||||
.connectTimeout(3, TimeUnit.SECONDS)
|
||||
.readTimeout(3, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
val okHttpClientNoDoh = OkHttpClient()
|
||||
.newBuilder()
|
||||
.connectTimeout(3, TimeUnit.SECONDS)
|
||||
.readTimeout(3, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
@JvmStatic
|
||||
val okHttpClientWithCurrProxy: OkHttpClient
|
||||
get() {
|
||||
|
||||
return if (!SharedConfig.proxyEnabled || SharedConfig.currentProxy?.secret != null) {
|
||||
|
||||
okHttpClient
|
||||
|
||||
} else {
|
||||
|
||||
okHttpClient.newBuilder()
|
||||
.proxy(Proxy(Proxy.Type.SOCKS, InetSocketAddress(SharedConfig.currentProxy.address, SharedConfig.currentProxy.port)))
|
||||
.build()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun get(url: String): String {
|
||||
|
||||
val request = Request.Builder().url(url)
|
||||
.applyUserAgent()
|
||||
.build()
|
||||
|
||||
okHttpClient.newCall(request).execute().apply {
|
||||
|
||||
val body = body
|
||||
|
||||
return body?.string() ?: error("HTTP ERROR $code")
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getByteArray(url: String): ByteArray {
|
||||
|
||||
val request = Request.Builder()
|
||||
.url(url)
|
||||
.applyUserAgent()
|
||||
.build()
|
||||
|
||||
okHttpClient.newCall(request).execute().apply {
|
||||
|
||||
return body?.bytes() ?: error("HTTP ERROR $code")
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package tw.nekomimi.nekogram.utils
|
||||
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
object IoUtil {
|
||||
|
||||
@JvmStatic
|
||||
fun copy(inS: InputStream, outS: OutputStream) = inS.copyTo(outS)
|
||||
|
||||
@JvmStatic
|
||||
fun copy(inS: InputStream, outF: File) {
|
||||
|
||||
outF.parentFile?.also { FileUtil.initDir(it) }
|
||||
|
||||
FileUtil.delete(outF)
|
||||
|
||||
outF.createNewFile()
|
||||
|
||||
outF.outputStream().use {
|
||||
|
||||
inS.copyTo(it)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun copy(process: Process, outF: File) {
|
||||
|
||||
outF.parentFile?.also { FileUtil.initDir(it) }
|
||||
|
||||
FileUtil.delete(outF)
|
||||
|
||||
outF.createNewFile()
|
||||
|
||||
outF.outputStream().use {
|
||||
|
||||
process.inputStream.copyTo(it, 512)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
149
TMessagesProj/src/main/java/tw/nekomimi/nekogram/utils/Langs.kt
Normal file
149
TMessagesProj/src/main/java/tw/nekomimi/nekogram/utils/Langs.kt
Normal file
|
@ -0,0 +1,149 @@
|
|||
package tw.nekomimi.nekogram.utils
|
||||
|
||||
import cn.hutool.core.collection.CollUtil
|
||||
import cn.hutool.core.util.ArrayUtil
|
||||
import cn.hutool.core.util.StrUtil
|
||||
import org.telegram.ui.ActionBar.AlertDialog
|
||||
import java.math.BigInteger
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.reflect.KMutableProperty0
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.KProperty0
|
||||
|
||||
/**
|
||||
* 一些基于语言特性的全局函数
|
||||
*/
|
||||
|
||||
fun <T> T.applyIf(boolean: Boolean, block: (T.() -> Unit)?): T {
|
||||
if (boolean) block?.invoke(this)
|
||||
return this
|
||||
}
|
||||
|
||||
fun <T> T.applyIfNot(boolean: Boolean, block: (T.() -> Unit)?): T {
|
||||
if (!boolean) block?.invoke(this)
|
||||
return this
|
||||
}
|
||||
|
||||
fun String.input(vararg params: Any): String {
|
||||
|
||||
return StrUtil.format(this, *params)
|
||||
|
||||
}
|
||||
|
||||
val Number.asByteArray get() = BigInteger.valueOf(toLong()).toByteArray()!!
|
||||
|
||||
val ByteArray.asLong get() = BigInteger(this).toLong()
|
||||
val ByteArray.asInt get() = BigInteger(this).toInt()
|
||||
|
||||
fun <T> Array<T>.shift(): Array<T> {
|
||||
|
||||
return shift(1)
|
||||
|
||||
}
|
||||
|
||||
fun <T> Array<T>.shift(size: Int): Array<T> {
|
||||
|
||||
return ArrayUtil.sub(this, size, this.size)
|
||||
|
||||
}
|
||||
|
||||
fun <T> Collection<T>.shift() = shift(1)
|
||||
|
||||
fun <T> Collection<T>.shift(size: Int): Collection<T> {
|
||||
|
||||
return LinkedList(CollUtil.sub(this, size, this.size))
|
||||
|
||||
}
|
||||
|
||||
class WriteOnlyField<T>(val setter: (T) -> Unit) {
|
||||
|
||||
operator fun getValue(thisRef: Any?, property: KProperty<*>): T = error("WriteOnlyField : ${property.name}")
|
||||
|
||||
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
||||
|
||||
setter.invoke(value)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class WeakField<T> {
|
||||
|
||||
private var value: T? = null
|
||||
|
||||
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
||||
return value
|
||||
?: throw IllegalStateException("Property ${property.name} should be initialized before get.")
|
||||
}
|
||||
|
||||
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun <T, R> receive(getter: T.() -> R) = Receiver(getter)
|
||||
|
||||
class Receiver<T, R>(val getter: T.() -> R) {
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
operator fun getValue(thisRef: Any?, property: KProperty<*>): R {
|
||||
|
||||
return getter(thisRef as T)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun <T : Any, R> receiveLazy(initializer: T.() -> R) = LazyReceiver(initializer)
|
||||
|
||||
class LazyReceiver<T : Any, R>(val initializer: T.() -> R) {
|
||||
|
||||
private val isInitialized = HashMap<T, Unit>()
|
||||
private val cache = HashMap<T, R>()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
operator fun getValue(thisRef: Any, property: KProperty<*>): R {
|
||||
|
||||
if (isInitialized[thisRef] != null) return cache[thisRef] as R
|
||||
|
||||
synchronized(this) {
|
||||
|
||||
if (isInitialized[thisRef] != null) return cache[thisRef] as R
|
||||
|
||||
return initializer(thisRef as T).apply {
|
||||
|
||||
cache[thisRef] = this
|
||||
|
||||
isInitialized[thisRef] = Unit
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
operator fun <F> KProperty0<F>.getValue(thisRef: Any?, property: KProperty<*>): F = get()
|
||||
operator fun <F> KMutableProperty0<F>.setValue(thisRef: Any?, property: KProperty<*>, value: F) = set(value)
|
||||
|
||||
operator fun AtomicBoolean.getValue(thisRef: Any?, property: KProperty<*>): Boolean = get()
|
||||
operator fun AtomicBoolean.setValue(thisRef: Any?, property: KProperty<*>, value: Boolean) = set(value)
|
||||
|
||||
operator fun AtomicInteger.getValue(thisRef: Any?, property: KProperty<*>): Int = get()
|
||||
operator fun AtomicInteger.setValue(thisRef: Any?, property: KProperty<*>, value: Int) = set(value)
|
||||
|
||||
operator fun AtomicLong.getValue(thisRef: Any?, property: KProperty<*>): Long = get()
|
||||
operator fun AtomicLong.setValue(thisRef: Any?, property: KProperty<*>, value: Long) = set(value)
|
||||
|
||||
operator fun <T> AtomicReference<T>.getValue(thisRef: Any?, property: KProperty<*>): T = get()
|
||||
operator fun <T> AtomicReference<T>.setValue(thisRef: Any?, property: KProperty<*>, value: T) = set(value)
|
||||
|
||||
fun AlertDialog.uUpdate(message: String) = UIUtil.runOnUIThread { setMessage(message) }
|
||||
fun AlertDialog.uDismiss() = UIUtil.runOnUIThread { dismiss() }
|
|
@ -0,0 +1,38 @@
|
|||
package tw.nekomimi.nekogram.utils
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.telegram.messenger.ApplicationLoader
|
||||
import org.telegram.messenger.LocaleController
|
||||
import tw.nekomimi.nekogram.utils.FileUtil.delete
|
||||
import tw.nekomimi.nekogram.utils.FileUtil.initDir
|
||||
import java.io.File
|
||||
|
||||
object LocaleUtil {
|
||||
|
||||
@JvmField
|
||||
val cacheDir = File(ApplicationLoader.applicationContext.cacheDir, "builtIn_lang_export")
|
||||
|
||||
@JvmStatic
|
||||
fun fetchAndExportLang() = runBlocking {
|
||||
|
||||
delete(cacheDir)
|
||||
initDir(cacheDir)
|
||||
|
||||
for (localeInfo in LocaleController.getInstance().languages) {
|
||||
|
||||
if (!localeInfo.builtIn || localeInfo.pathToFile != "unofficial") continue
|
||||
|
||||
if (localeInfo.hasBaseLang()) {
|
||||
|
||||
localeInfo.pathToBaseFile.takeIf { it.isFile }?.copyTo(File(cacheDir, localeInfo.pathToBaseFile.name))
|
||||
|
||||
}
|
||||
|
||||
localeInfo.getPathToFile()?.takeIf { it.isFile }?.copyTo(File(cacheDir, localeInfo.getPathToFile().name))
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package tw.nekomimi.nekogram.utils
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.View
|
||||
import org.telegram.ui.ActionBar.ActionBarMenuItem
|
||||
import org.telegram.ui.ActionBar.Theme
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
class PopupBuilder @JvmOverloads constructor(anchor: View, dialog: Boolean = false) : ActionBarMenuItem(anchor.context, null, Theme.ACTION_BAR_WHITE_SELECTOR_COLOR, -0x4c4c4d) {
|
||||
|
||||
init {
|
||||
|
||||
setAnchor(anchor)
|
||||
|
||||
isShowOnTop = dialog
|
||||
|
||||
isVerticalScrollBarEnabled = true
|
||||
|
||||
}
|
||||
|
||||
fun setItems(items: Array<CharSequence>, listener: (Int,CharSequence) -> Unit) {
|
||||
|
||||
removeAllSubItems()
|
||||
|
||||
items.forEachIndexed { i, v ->
|
||||
|
||||
addSubItem(i, v)
|
||||
|
||||
}
|
||||
|
||||
setDelegate {
|
||||
|
||||
listener(it,items[it])
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun show() {
|
||||
|
||||
toggleSubMenu()
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,270 @@
|
|||
package tw.nekomimi.nekogram.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.widget.TextView
|
||||
import org.telegram.messenger.AndroidUtilities
|
||||
import org.telegram.messenger.LocaleController
|
||||
import org.telegram.messenger.MessagesController
|
||||
import org.telegram.messenger.R
|
||||
import org.telegram.tgnet.ConnectionsManager
|
||||
import org.telegram.tgnet.TLRPC
|
||||
import org.telegram.ui.ActionBar.AlertDialog
|
||||
import org.telegram.ui.ActionBar.Theme
|
||||
import org.telegram.ui.LaunchActivity
|
||||
import org.telegram.ui.TwoStepVerificationActivity
|
||||
|
||||
object PrivacyUtil {
|
||||
|
||||
@JvmStatic
|
||||
fun postCheckAll(ctx: Context, account: Int) {
|
||||
|
||||
if (!MessagesController.getMainSettings(account).getBoolean("privacy_warning_skip_phone_number", false)) {
|
||||
|
||||
postCheckPhoneNumberVisible(ctx, account)
|
||||
|
||||
}
|
||||
|
||||
if (!MessagesController.getMainSettings(account).getBoolean("privacy_warning_skip_add_by_phone", false)) {
|
||||
|
||||
postCheckAddMeByPhone(ctx, account)
|
||||
|
||||
}
|
||||
|
||||
if (!MessagesController.getMainSettings(account).getBoolean("privacy_warning_skip_p2p", false)) {
|
||||
|
||||
postCheckAllowP2p(ctx, account)
|
||||
|
||||
}
|
||||
|
||||
if (!MessagesController.getMainSettings(account).getBoolean("privacy_warning_skip_2fa", false)) {
|
||||
|
||||
postCheckAllow2fa(ctx, account)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun postCheckPhoneNumberVisible(ctx: Context, account: Int) {
|
||||
|
||||
ConnectionsManager.getInstance(account).sendRequest(TLRPC.TL_account_getPrivacy().apply {
|
||||
|
||||
key = TLRPC.TL_inputPrivacyKeyPhoneNumber()
|
||||
|
||||
}, { response, _ ->
|
||||
|
||||
if (response is TLRPC.TL_account_privacyRules) {
|
||||
|
||||
if (response.rules.isEmpty()) {
|
||||
|
||||
showPrivacyAlert(ctx, account, 0)
|
||||
|
||||
} else {
|
||||
|
||||
response.rules.forEach {
|
||||
|
||||
if (it is TLRPC.TL_privacyValueAllowAll) {
|
||||
|
||||
showPrivacyAlert(ctx, account, 0)
|
||||
|
||||
return@forEach
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}, ConnectionsManager.RequestFlagFailOnServerErrors)
|
||||
|
||||
}
|
||||
|
||||
private fun postCheckAddMeByPhone(ctx: Context, account: Int) {
|
||||
|
||||
ConnectionsManager.getInstance(account).sendRequest(TLRPC.TL_account_getPrivacy().apply {
|
||||
|
||||
key = TLRPC.TL_inputPrivacyKeyAddedByPhone()
|
||||
|
||||
}, { response, _ ->
|
||||
|
||||
if (response is TLRPC.TL_account_privacyRules) {
|
||||
|
||||
if (response.rules.isEmpty()) {
|
||||
|
||||
showPrivacyAlert(ctx, account, 1)
|
||||
|
||||
} else {
|
||||
|
||||
response.rules.forEach {
|
||||
|
||||
if (it is TLRPC.TL_privacyValueAllowAll) {
|
||||
|
||||
showPrivacyAlert(ctx, account, 1)
|
||||
|
||||
return@forEach
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}, ConnectionsManager.RequestFlagFailOnServerErrors)
|
||||
|
||||
}
|
||||
|
||||
private fun postCheckAllowP2p(ctx: Context, account: Int) {
|
||||
|
||||
ConnectionsManager.getInstance(account).sendRequest(TLRPC.TL_account_getPrivacy().apply {
|
||||
|
||||
key = TLRPC.TL_inputPrivacyKeyPhoneP2P()
|
||||
|
||||
}, { response, _ ->
|
||||
|
||||
if (response is TLRPC.TL_account_privacyRules) {
|
||||
|
||||
if (response.rules.isEmpty()) {
|
||||
|
||||
showPrivacyAlert(ctx, account, 2)
|
||||
|
||||
} else {
|
||||
|
||||
response.rules.forEach {
|
||||
|
||||
if (it is TLRPC.TL_privacyValueAllowAll) {
|
||||
|
||||
showPrivacyAlert(ctx, account, 2)
|
||||
|
||||
return@forEach
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}, ConnectionsManager.RequestFlagFailOnServerErrors)
|
||||
|
||||
}
|
||||
|
||||
private fun postCheckAllow2fa(ctx: Context, account: Int) {
|
||||
|
||||
ConnectionsManager.getInstance(account).sendRequest(TLRPC.TL_account_getPassword(), { response, _ ->
|
||||
|
||||
if (response is TLRPC.TL_account_password) {
|
||||
|
||||
if (!response.has_password) {
|
||||
|
||||
show2faAlert(ctx, account, response)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}, ConnectionsManager.RequestFlagFailOnServerErrors)
|
||||
|
||||
}
|
||||
|
||||
private fun showPrivacyAlert(ctx: Context, account: Int, type: Int) {
|
||||
|
||||
val builder = AlertDialog.Builder(ctx)
|
||||
|
||||
builder.setTitle(LocaleController.getString("", R.string.PrivacyNotice))
|
||||
|
||||
builder.setMessage(AndroidUtilities.replaceTags(when (type) {
|
||||
0 -> LocaleController.getString("PrivacyNoticePhoneVisible", R.string.PrivacyNoticePhoneVisible)
|
||||
1 -> LocaleController.getString("PrivacyNoticeAddByPhone", R.string.PrivacyNoticeAddByPhone)
|
||||
else -> LocaleController.getString("PrivacyNoticeP2p", R.string.PrivacyNoticeP2p)
|
||||
}))
|
||||
|
||||
builder.setPositiveButton(LocaleController.getString("ApplySuggestion", R.string.ApplySuggestion)) { _, _ ->
|
||||
|
||||
ConnectionsManager.getInstance(account).sendRequest(TLRPC.TL_account_setPrivacy().apply {
|
||||
|
||||
key = when (type) {
|
||||
|
||||
0 -> TLRPC.TL_inputPrivacyKeyPhoneNumber()
|
||||
1 -> TLRPC.TL_inputPrivacyKeyAddedByPhone()
|
||||
else -> TLRPC.TL_inputPrivacyKeyPhoneP2P()
|
||||
|
||||
}
|
||||
|
||||
rules = arrayListOf(when (type) {
|
||||
|
||||
0 -> TLRPC.TL_inputPrivacyValueDisallowAll()
|
||||
1 -> TLRPC.TL_inputPrivacyValueAllowContacts()
|
||||
else -> TLRPC.TL_inputPrivacyValueDisallowAll()
|
||||
|
||||
})
|
||||
|
||||
}) { _, _ -> /* ignored */ }
|
||||
|
||||
|
||||
}
|
||||
|
||||
builder.setNeutralButton(LocaleController.getString("Cancel", R.string.Cancel), null)
|
||||
|
||||
builder.setNeutralButton(LocaleController.getString("DoNotRemindAgain", R.string.DoNotRemindAgain)) { _, _ ->
|
||||
|
||||
MessagesController.getMainSettings(account).edit().putBoolean("privacy_warning_skip_${when (type) {
|
||||
0 -> "phone_number"
|
||||
1 -> "add_by_phone"
|
||||
2 -> "p2p"
|
||||
else -> "2fa"
|
||||
}
|
||||
}", true).apply()
|
||||
|
||||
}
|
||||
|
||||
runCatching {
|
||||
|
||||
(builder.show().getButton(DialogInterface.BUTTON_NEUTRAL) as TextView?)?.setTextColor(Theme.getColor(Theme.key_dialogTextRed2))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun show2faAlert(ctx: Context, account: Int, password: TLRPC.TL_account_password) {
|
||||
|
||||
val builder = AlertDialog.Builder(ctx)
|
||||
|
||||
builder.setTitle(LocaleController.getString("", R.string.PrivacyNotice))
|
||||
|
||||
builder.setMessage(AndroidUtilities.replaceTags(LocaleController.getString("PrivacyNotice2fa", R.string.PrivacyNotice2fa)))
|
||||
|
||||
builder.setPositiveButton(LocaleController.getString("Set", R.string.Set)) { _, _ ->
|
||||
|
||||
if (ctx is LaunchActivity) {
|
||||
|
||||
UIUtil.runOnUIThread(Runnable {
|
||||
|
||||
ctx.presentFragment(TwoStepVerificationActivity(account, password))
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
builder.setNeutralButton(LocaleController.getString("Cancel", R.string.Cancel), null)
|
||||
|
||||
builder.setNeutralButton(LocaleController.getString("DoNotRemindAgain", R.string.DoNotRemindAgain)) { _, _ ->
|
||||
|
||||
MessagesController.getMainSettings(account).edit().putBoolean("privacy_warning_skip_2fa", true).apply()
|
||||
|
||||
}
|
||||
|
||||
runCatching {
|
||||
|
||||
(builder.show().getButton(DialogInterface.BUTTON_NEUTRAL) as TextView?)?.setTextColor(Theme.getColor(Theme.key_dialogTextRed2))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
package tw.nekomimi.nekogram.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.webkit.MimeTypeMap
|
||||
import androidx.core.content.FileProvider
|
||||
import org.telegram.messenger.BuildConfig
|
||||
import org.telegram.ui.LaunchActivity
|
||||
import java.io.File
|
||||
|
||||
object ShareUtil {
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun shareText(ctx: Context, text: String, choose: Boolean = false) {
|
||||
|
||||
val intent = Intent(Intent.ACTION_SEND).apply {
|
||||
type = "text/plain"
|
||||
putExtra(Intent.EXTRA_TEXT, text)
|
||||
}
|
||||
|
||||
if (!choose) {
|
||||
|
||||
intent.setClass(ctx, LaunchActivity::class.java)
|
||||
ctx.startActivity(intent)
|
||||
|
||||
} else {
|
||||
|
||||
ctx.startActivity(Intent.createChooser(intent, text))
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
@JvmStatic
|
||||
fun shareFile(ctx: Context, fileToShare: File, caption: String = "") {
|
||||
|
||||
val uri = if (Build.VERSION.SDK_INT >= 24) {
|
||||
FileProvider.getUriForFile(ctx, BuildConfig.APPLICATION_ID + ".provider", fileToShare)
|
||||
} else {
|
||||
Uri.fromFile(fileToShare)
|
||||
}
|
||||
|
||||
val i = Intent(Intent.ACTION_SEND)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 24) {
|
||||
|
||||
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
|
||||
}
|
||||
|
||||
i.type = "message/rfc822"
|
||||
i.putExtra(Intent.EXTRA_EMAIL, "")
|
||||
|
||||
if (caption.isNotBlank()) i.putExtra(Intent.EXTRA_SUBJECT, caption)
|
||||
|
||||
i.putExtra(Intent.EXTRA_STREAM, uri)
|
||||
i.setClass(ctx, LaunchActivity::class.java)
|
||||
|
||||
ctx.startActivity(i)
|
||||
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
@JvmStatic
|
||||
fun openFile(ctx: Context, fileToOpen: File) {
|
||||
|
||||
val uri = if (Build.VERSION.SDK_INT >= 24) {
|
||||
|
||||
FileProvider.getUriForFile(ctx, BuildConfig.APPLICATION_ID + ".provider", fileToOpen)
|
||||
|
||||
} else {
|
||||
|
||||
Uri.fromFile(fileToOpen)
|
||||
|
||||
}
|
||||
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 24) {
|
||||
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
|
||||
}
|
||||
|
||||
if (fileToOpen.extension.isBlank()) {
|
||||
|
||||
intent.type = "application/octet-stream"
|
||||
|
||||
} else {
|
||||
|
||||
intent.type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileToOpen.extension)
|
||||
|
||||
}
|
||||
|
||||
intent.data = uri
|
||||
|
||||
ctx.startActivity(intent)
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,294 @@
|
|||
package tw.nekomimi.nekogram.utils
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.telegram.messenger.AndroidUtilities
|
||||
import org.telegram.messenger.MediaDataController
|
||||
import org.telegram.messenger.NotificationCenter
|
||||
import org.telegram.tgnet.ConnectionsManager
|
||||
import org.telegram.tgnet.TLRPC.*
|
||||
import org.telegram.ui.ActionBar.AlertDialog
|
||||
import org.telegram.ui.ActionBar.BaseFragment
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
object StickersUtil {
|
||||
|
||||
private fun AlertDialog.updateStatus(message: CharSequence) = AndroidUtilities.runOnUIThread { setMessage(message); }
|
||||
|
||||
@JvmStatic
|
||||
fun importStickers(stickerObj: JsonObject, f: BaseFragment, progress: AlertDialog) = runBlocking {
|
||||
|
||||
val cancel = AtomicBoolean()
|
||||
|
||||
progress.setOnCancelListener {
|
||||
|
||||
cancel.set(true)
|
||||
|
||||
}
|
||||
|
||||
val installed = f.mediaDataController.getStickerSets(MediaDataController.TYPE_IMAGE)
|
||||
|
||||
val finishLoad = AtomicBoolean()
|
||||
val archivedSets = LinkedList<StickerSetCovered>()
|
||||
|
||||
fun loadStickers() {
|
||||
|
||||
val req = TL_messages_getArchivedStickers()
|
||||
req.offset_id = if (archivedSets.isEmpty()) 0 else archivedSets[archivedSets.size - 1].set.id
|
||||
req.limit = 100
|
||||
req.masks = false
|
||||
|
||||
f.connectionsManager.sendRequest(req) { response, _ ->
|
||||
|
||||
if (response is TL_messages_archivedStickers) {
|
||||
|
||||
archivedSets.addAll(response.sets)
|
||||
|
||||
if (response.sets.size < 100) {
|
||||
|
||||
finishLoad.set(true)
|
||||
|
||||
} else {
|
||||
|
||||
loadStickers()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
loadStickers()
|
||||
|
||||
stickerObj.getAsJsonObject("stickerSets")?.also {
|
||||
|
||||
val stickerSets = LinkedList(it.entrySet().map {
|
||||
|
||||
object : Map.Entry<String, String> {
|
||||
|
||||
override val key: String get() = it.key
|
||||
override val value: String get() = it.value.asString
|
||||
|
||||
}
|
||||
|
||||
}).apply { reverse() }
|
||||
|
||||
val waitLock = AtomicBoolean()
|
||||
|
||||
install@ for (stickerSetObj in stickerSets) {
|
||||
|
||||
if (cancel.get()) return@runBlocking
|
||||
|
||||
for (s in installed) if (s.set.short_name == stickerSetObj.value) continue@install
|
||||
for (s in archivedSets) if (s.set.short_name == stickerSetObj.value) continue@install
|
||||
|
||||
waitLock.set(false)
|
||||
|
||||
f.connectionsManager.sendRequest(TL_messages_installStickerSet().apply {
|
||||
|
||||
stickerset = TL_inputStickerSetShortName().apply {
|
||||
|
||||
short_name = stickerSetObj.value
|
||||
|
||||
}
|
||||
|
||||
}) { response, error ->
|
||||
|
||||
if (response is TL_messages_stickerSetInstallResultSuccess) {
|
||||
|
||||
f.mediaDataController.loadStickers(MediaDataController.TYPE_IMAGE, false, true)
|
||||
|
||||
progress.updateStatus("Installed: ${stickerSetObj.key}")
|
||||
|
||||
} else if (response is TL_messages_stickerSetInstallResultArchive) {
|
||||
|
||||
f.mediaDataController.loadStickers(MediaDataController.TYPE_IMAGE, false, true)
|
||||
|
||||
AndroidUtilities.runOnUIThread {
|
||||
|
||||
f.notificationCenter.postNotificationName(NotificationCenter.needAddArchivedStickers, response.sets)
|
||||
|
||||
}
|
||||
|
||||
progress.updateStatus("Archived: ${stickerSetObj.key}")
|
||||
|
||||
} else if (error != null) {
|
||||
|
||||
progress.updateStatus("Error ${error.code}: ${error.text}")
|
||||
|
||||
}
|
||||
|
||||
waitLock.set(true)
|
||||
|
||||
}
|
||||
|
||||
while (!waitLock.get() && !cancel.get()) delay(100L)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
stickerObj.getAsJsonObject("archivedStickers")?.also {
|
||||
|
||||
val stickerSets = LinkedList(it.entrySet().map {
|
||||
|
||||
object : Map.Entry<String, String> {
|
||||
|
||||
override val key: String get() = it.key
|
||||
override val value: String get() = it.value.asString
|
||||
|
||||
}
|
||||
|
||||
}).apply { reverse() }
|
||||
|
||||
val waitLock = AtomicBoolean()
|
||||
|
||||
install@ for (stickerSetObj in stickerSets) {
|
||||
|
||||
if (cancel.get()) return@runBlocking
|
||||
|
||||
waitLock.set(false)
|
||||
|
||||
for (s in installed) if (s.set.short_name == stickerSetObj.value) continue@install
|
||||
for (s in archivedSets) if (s.set.short_name == stickerSetObj.value) continue@install
|
||||
|
||||
f.connectionsManager.sendRequest(TL_messages_installStickerSet().apply {
|
||||
|
||||
stickerset = TL_inputStickerSetShortName().apply {
|
||||
|
||||
short_name = stickerSetObj.value
|
||||
archived = true
|
||||
|
||||
}
|
||||
|
||||
}) { response, error ->
|
||||
|
||||
if (response is TL_messages_stickerSetInstallResultArchive) {
|
||||
|
||||
f.mediaDataController.loadStickers(MediaDataController.TYPE_IMAGE, false, true)
|
||||
|
||||
AndroidUtilities.runOnUIThread {
|
||||
|
||||
f.notificationCenter.postNotificationName(NotificationCenter.needAddArchivedStickers, response.sets)
|
||||
|
||||
}
|
||||
|
||||
progress.updateStatus("Archived: ${stickerSetObj.key}")
|
||||
|
||||
} else if (error != null) {
|
||||
|
||||
progress.updateStatus("Error ${error.code}: ${error.text}")
|
||||
|
||||
}
|
||||
|
||||
waitLock.set(true)
|
||||
|
||||
}
|
||||
|
||||
while (!waitLock.get() && !cancel.get()) delay(100L)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return@runBlocking
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun exportStickers(account: Int, exportSets: Boolean, exportArchived: Boolean) = runBlocking {
|
||||
|
||||
val exportObj = JsonObject()
|
||||
|
||||
if (exportSets) {
|
||||
|
||||
exportObj.add("stickerSets", JsonObject().apply {
|
||||
|
||||
MediaDataController.getInstance(account).getStickerSets(MediaDataController.TYPE_IMAGE).forEach {
|
||||
|
||||
addProperty(it.set.title, it.set.short_name)
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
if (exportArchived) {
|
||||
|
||||
val finishLoad = AtomicBoolean()
|
||||
val archivedSets = LinkedList<StickerSetCovered>()
|
||||
|
||||
fun loadStickers() {
|
||||
|
||||
val req = TL_messages_getArchivedStickers()
|
||||
req.offset_id = if (archivedSets.isEmpty()) 0 else archivedSets[archivedSets.size - 1].set.id
|
||||
req.limit = 100
|
||||
req.masks = false
|
||||
|
||||
ConnectionsManager.getInstance(account).sendRequest(req) { response, _ ->
|
||||
|
||||
if (response is TL_messages_archivedStickers) {
|
||||
|
||||
archivedSets.addAll(response.sets)
|
||||
|
||||
if (response.sets.size < 100) {
|
||||
|
||||
finishLoad.set(true)
|
||||
|
||||
} else {
|
||||
|
||||
loadStickers()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
loadStickers()
|
||||
|
||||
while (!finishLoad.get()) delay(100L)
|
||||
|
||||
exportObj.add("archivedStickers", JsonObject().apply {
|
||||
|
||||
archivedSets.forEach {
|
||||
|
||||
addProperty(it.set.title, it.set.short_name)
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
return@runBlocking exportObj
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun exportStickers(exportSets: Collection<StickerSet>) = runBlocking {
|
||||
|
||||
val exportObj = JsonObject()
|
||||
|
||||
exportObj.add("stickerSets", JsonObject().apply {
|
||||
|
||||
exportSets.forEach {
|
||||
|
||||
addProperty(it.title, it.short_name)
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
return@runBlocking exportObj
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package tw.nekomimi.nekogram.utils
|
||||
|
||||
object ThreadUtil {
|
||||
|
||||
@JvmStatic
|
||||
fun sleep(time: Long) = Thread.sleep(time)
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package tw.nekomimi.nekogram.utils
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.telegram.messenger.ApplicationLoader
|
||||
|
||||
object UIUtil {
|
||||
|
||||
@JvmStatic
|
||||
fun runOnUIThread(runnable: Runnable) = ApplicationLoader.applicationHandler.post(runnable)
|
||||
|
||||
fun runOnUIThread(runnable: () -> Unit) = ApplicationLoader.applicationHandler.post(runnable)
|
||||
|
||||
@JvmStatic
|
||||
fun runOnIoDispatcher(runnable: Runnable) {
|
||||
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
|
||||
runnable.run()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun runOnIoDispatcher(runnable: () -> Unit) {
|
||||
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
|
||||
runnable()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,282 @@
|
|||
package tw.nekomimi.nekogram.utils
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Build
|
||||
import cn.hutool.core.io.IoUtil
|
||||
import cn.hutool.core.io.StreamProgress
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import okhttp3.internal.closeQuietly
|
||||
import org.json.JSONObject
|
||||
import org.telegram.messenger.BuildConfig
|
||||
import org.telegram.messenger.BuildVars
|
||||
import org.telegram.messenger.FileLog
|
||||
import org.telegram.messenger.LocaleController
|
||||
import org.telegram.messenger.R
|
||||
import org.tukaani.xz.XZInputStream
|
||||
import tw.nekomimi.nekogram.BottomBuilder
|
||||
import tw.nekomimi.nekogram.ExternalGcm
|
||||
import tw.nekomimi.nekogram.NekoXConfig
|
||||
import java.io.File
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
object UpdateUtil {
|
||||
|
||||
val updateUrls = arrayOf("https://raw.githubusercontent.com/NekoX-Dev/Resources/master")
|
||||
|
||||
@JvmStatic
|
||||
fun checkUpdate(ctx: Activity) = UIUtil.runOnIoDispatcher {
|
||||
|
||||
if (BuildVars.isUnknown) {
|
||||
|
||||
FileLog.d("${BuildConfig.BUILD_TYPE} version, skip update check.")
|
||||
|
||||
return@runOnIoDispatcher
|
||||
|
||||
}
|
||||
|
||||
if (ExternalGcm.checkPlayServices()) {
|
||||
|
||||
FileLog.d("checking updates from google play")
|
||||
|
||||
ExternalGcm.checkUpdate(ctx)
|
||||
|
||||
return@runOnIoDispatcher
|
||||
|
||||
}
|
||||
|
||||
FileLog.d("checking updates from repo")
|
||||
|
||||
if (System.currentTimeMillis() - NekoXConfig.preferences.getLong("ignored_update_at", -1) < 1 * 60 * 60 * 1000L) {
|
||||
|
||||
FileLog.d("ignored")
|
||||
|
||||
return@runOnIoDispatcher
|
||||
|
||||
}
|
||||
|
||||
updateUrls.forEach { url ->
|
||||
|
||||
runCatching {
|
||||
|
||||
val updateInfo = JSONObject(HttpUtil.get("$url/update.json"))
|
||||
|
||||
val code = updateInfo.getInt("versionCode")
|
||||
|
||||
if (code > BuildConfig.VERSION_CODE.coerceAtLeast(NekoXConfig.preferences.getInt("ignore_update", -1))) UIUtil.runOnUIThread {
|
||||
|
||||
FileLog.d("update available")
|
||||
|
||||
val builder = BottomBuilder(ctx)
|
||||
|
||||
builder.addTitle(LocaleController.getString("UpdateAvailable", R.string.UpdateAvailable), updateInfo.getString("version"))
|
||||
|
||||
builder.addItem(LocaleController.getString("UpdateUpdate", R.string.UpdateUpdate), R.drawable.baseline_system_update_24, false) {
|
||||
|
||||
doUpdate(ctx, code, updateInfo.getString("defaultFlavor"))
|
||||
|
||||
builder.dismiss()
|
||||
|
||||
NekoXConfig.preferences.edit().remove("ignored_update_at").remove("ignore_update_at").apply()
|
||||
|
||||
}
|
||||
|
||||
builder.addItem(LocaleController.getString("UpdateLater", R.string.UpdateLater), R.drawable.baseline_watch_later_24, false) {
|
||||
|
||||
builder.dismiss()
|
||||
|
||||
NekoXConfig.preferences.edit().putLong("ignored_update_at", System.currentTimeMillis()).apply()
|
||||
|
||||
}
|
||||
|
||||
builder.addItem(LocaleController.getString("Ignore", R.string.Ignore), R.drawable.baseline_block_24, true) {
|
||||
|
||||
builder.dismiss()
|
||||
|
||||
NekoXConfig.preferences.edit().putInt("ignore_update", code).apply()
|
||||
|
||||
}
|
||||
|
||||
runCatching {
|
||||
|
||||
builder.show()
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
FileLog.d("no updates")
|
||||
|
||||
}
|
||||
|
||||
return@runOnIoDispatcher
|
||||
|
||||
}.onFailure {
|
||||
|
||||
FileLog.d(it.toString())
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun doUpdate(ctx: Activity, targetVer: Int, defFlavor: String, buildType: String = BuildConfig.BUILD_TYPE, flavor: String = BuildConfig.FLAVOR) {
|
||||
|
||||
val pro = AlertUtil.showProgress(ctx)
|
||||
pro.setCanCacnel(false)
|
||||
pro.show()
|
||||
|
||||
fun update(message: String) = UIUtil.runOnUIThread { pro.setMessage(message) }
|
||||
fun dismiss() = UIUtil.runOnUIThread { pro.dismiss() }
|
||||
|
||||
var exception: Exception? = null
|
||||
|
||||
UIUtil.runOnIoDispatcher {
|
||||
|
||||
var fileName = "NekoX-$flavor-${Build.CPU_ABI}-$buildType.apk.xz"
|
||||
|
||||
var response: Response? = null
|
||||
|
||||
runCatching {
|
||||
|
||||
for (url in updateUrls) {
|
||||
|
||||
try {
|
||||
|
||||
response = HttpUtil.okHttpClient.newCall(Request.Builder().url("$url/$fileName").build()).execute()
|
||||
|
||||
if (response!!.code != 200) error("HTTP ${response!!.code} :${response!!.body!!.string()}")
|
||||
|
||||
break
|
||||
|
||||
} catch (e: Exception) {
|
||||
|
||||
exception = e
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (response == null) {
|
||||
|
||||
for (url in updateUrls) {
|
||||
|
||||
try {
|
||||
|
||||
fileName = "NekoX-$defFlavor-${Build.CPU_ABI}-$buildType.apk.xz"
|
||||
|
||||
response = HttpUtil.okHttpClient.newCall(Request.Builder().url("$url/$fileName").build()).execute()
|
||||
|
||||
if (response!!.code != 200) error("HTTP ${response!!.code} :${response!!.body!!.string()}")
|
||||
|
||||
break
|
||||
|
||||
} catch (e: Exception) {
|
||||
|
||||
exception = e
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}.onFailure {
|
||||
|
||||
dismiss()
|
||||
|
||||
AlertUtil.showSimpleAlert(ctx, LocaleController.getString("DownloadFailed", R.string.DownloadFailed), it.toString())
|
||||
|
||||
return@runOnIoDispatcher
|
||||
|
||||
}
|
||||
|
||||
if (response == null) {
|
||||
|
||||
dismiss()
|
||||
|
||||
AlertUtil.showSimpleAlert(ctx, LocaleController.getString("DownloadFailed", R.string.DownloadFailed), exception!!.toString())
|
||||
|
||||
return@runOnIoDispatcher
|
||||
|
||||
}
|
||||
|
||||
val body = response!!.body!!
|
||||
|
||||
val size = body.contentLength()
|
||||
|
||||
val target = File(ctx.externalCacheDir, "nekox-$targetVer-$flavor-$buildType.apk")
|
||||
|
||||
update("Downloading...")
|
||||
|
||||
if (target.isFile) {
|
||||
|
||||
runCatching {
|
||||
|
||||
ZipInputStream(target.inputStream()).use { it.nextEntry }
|
||||
|
||||
dismiss()
|
||||
|
||||
ShareUtil.openFile(ctx, target)
|
||||
|
||||
return@runOnIoDispatcher
|
||||
|
||||
}.onFailure {
|
||||
|
||||
target.delete()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
runCatching {
|
||||
|
||||
val input = XZInputStream(body.byteStream())
|
||||
|
||||
FileUtil.initFile(target)
|
||||
|
||||
target.outputStream().use {
|
||||
|
||||
IoUtil.copy(input, it, IoUtil.DEFAULT_BUFFER_SIZE, object : StreamProgress {
|
||||
|
||||
override fun progress(progressSize: Long) {
|
||||
|
||||
update("$progressSize / $size")
|
||||
|
||||
}
|
||||
|
||||
override fun start() {
|
||||
|
||||
update("0 / $size")
|
||||
|
||||
}
|
||||
|
||||
override fun finish() {
|
||||
|
||||
update("Finish")
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
input.closeQuietly()
|
||||
|
||||
dismiss()
|
||||
|
||||
ShareUtil.openFile(ctx, target)
|
||||
|
||||
}.onFailure {
|
||||
|
||||
dismiss()
|
||||
|
||||
AlertUtil.showSimpleAlert(ctx, LocaleController.getString("DownloadFailed", R.string.DownloadFailed), it.toString())
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package tw.nekomimi.nekogram.utils
|
||||
|
||||
import cn.hutool.core.util.ZipUtil
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
object ZipUtil {
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun makeZip(zipFile: File, withSrcDirs: Boolean = false, vararg contents: File) {
|
||||
|
||||
ZipUtil.zip(zipFile, withSrcDirs, *contents)
|
||||
|
||||
}
|
||||
|
||||
fun read(input: InputStream, path: String): ByteArray {
|
||||
|
||||
ZipInputStream(input).use { zip ->
|
||||
|
||||
while (true) {
|
||||
|
||||
val entry = zip.nextEntry ?: break
|
||||
|
||||
if (entry.name == path) return zip.readBytes()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
error("path not found")
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun unzip(input: InputStream, output: File) {
|
||||
|
||||
ZipInputStream(input).use { zip ->
|
||||
|
||||
while (true) {
|
||||
|
||||
val entry = zip.nextEntry ?: break
|
||||
|
||||
val entryFile = File(output, entry.name)
|
||||
|
||||
if (entry.isDirectory) {
|
||||
|
||||
entryFile.mkdirs()
|
||||
|
||||
} else {
|
||||
|
||||
entryFile.outputStream().use {
|
||||
|
||||
zip.copyTo(it)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user