diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index f7d331b8b61..ee5a84d3754 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -36,6 +36,7 @@ dependencies { implementation 'com.google.android.gms:play-services-wearable:18.0.0' implementation 'com.google.android.gms:play-services-location:21.0.1' implementation 'com.google.android.gms:play-services-wallet:19.1.0' + implementation 'com.google.android.gms:play-services-safetynet:18.0.1' implementation 'com.googlecode.mp4parser:isoparser:1.0.6' implementation 'com.stripe:stripe-android:2.0.2' implementation 'com.google.mlkit:language-id:16.1.1' diff --git a/TMessagesProj/config/debug/AndroidManifest.xml b/TMessagesProj/config/debug/AndroidManifest.xml index 92a95c77883..b7f49c6f5da 100644 --- a/TMessagesProj/config/debug/AndroidManifest.xml +++ b/TMessagesProj/config/debug/AndroidManifest.xml @@ -18,7 +18,6 @@ readInt32(&error); + if ((flags & 2) != 0) { + otherwise_relogin_days = stream->readInt32(&error); + } if ((flags & 1) != 0) { tmp_sessions = stream->readInt32(&error); } + if ((flags & 4) != 0) { + future_auth_token = std::unique_ptr(stream->readByteArray(&error)); + } user = std::unique_ptr(User::TLdeserialize(stream, stream->readUint32(&error), instanceNum, error)); } diff --git a/TMessagesProj/jni/tgnet/ApiScheme.h b/TMessagesProj/jni/tgnet/ApiScheme.h index 8f8a046e206..77a8da911a1 100644 --- a/TMessagesProj/jni/tgnet/ApiScheme.h +++ b/TMessagesProj/jni/tgnet/ApiScheme.h @@ -705,10 +705,12 @@ class TL_auth_authorizationSignUpRequired : public auth_Authorization { class TL_auth_authorization : public auth_Authorization { public: - static const uint32_t constructor = 0x33fb7bb8; + static const uint32_t constructor = 0x2ea2c0d4; int32_t flags; int32_t tmp_sessions; + int32_t otherwise_relogin_days; + std::unique_ptr future_auth_token; std::unique_ptr user; void readParams(NativeByteBuffer *stream, int32_t instanceNum, bool &error); diff --git a/TMessagesProj/jni/tgnet/ConnectionsManager.cpp b/TMessagesProj/jni/tgnet/ConnectionsManager.cpp index a1a911edd8d..4e884a11851 100644 --- a/TMessagesProj/jni/tgnet/ConnectionsManager.cpp +++ b/TMessagesProj/jni/tgnet/ConnectionsManager.cpp @@ -891,10 +891,12 @@ void ConnectionsManager::onConnectionDataReceived(Connection *connection, Native if (object != nullptr) { if (datacenter->isHandshaking(connection->isMediaConnection)) { + if (LOGS_ENABLED) DEBUG_E("process handshake"); datacenter->processHandshakeResponse(connection->isMediaConnection, object, messageId); } else { - processServerResponse(object, messageId, 0, 0, connection, 0, 0); - connection->addProcessedMessageId(messageId); + if (LOGS_ENABLED) DEBUG_E("connection(%p) received incorrect unencrypted message type", connection); + connection->reconnect(); + return; } lastProtocolUsefullData = true; connection->setHasUsefullData(); diff --git a/TMessagesProj/src/main/AndroidManifest.xml b/TMessagesProj/src/main/AndroidManifest.xml index d350aa887d1..cd6a7009f5e 100644 --- a/TMessagesProj/src/main/AndroidManifest.xml +++ b/TMessagesProj/src/main/AndroidManifest.xml @@ -84,7 +84,9 @@ = 19) { + oldViewAnim.setUpdateListener(animation1 -> onChangeAnimationUpdate(changeInfo.oldHolder)); + } oldViewAnim .setInterpolator(getChangeInterpolator()) .setListener(new AnimatorListenerAdapter() { @@ -493,6 +509,9 @@ public void onAnimationEnd(Animator animator) { if (animateByScale(newView) > 0) { newViewAnimation.scaleX(1f).scaleY(1f); } + if (Build.VERSION.SDK_INT >= 19) { + newViewAnimation.setUpdateListener(animation1 -> onChangeAnimationUpdate(changeInfo.newHolder)); + } newViewAnimation .setListener(new AnimatorListenerAdapter() { @Override @@ -512,6 +531,8 @@ public void onAnimationEnd(Animator animator) { dispatchChangeFinished(changeInfo.newHolder, false); mChangeAnimations.remove(changeInfo.newHolder); dispatchFinishedWhenDone(); + + afterAnimateChangeImpl(changeInfo.oldHolder, changeInfo.newHolder); } }).start(); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java index 7ab496f9dd1..639bd502aef 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java @@ -541,6 +541,27 @@ public static void recycleBitmap(Bitmap image) { recycleBitmaps(Collections.singletonList(image)); } + public static boolean findClickableView(ViewGroup container, float x, float y) { + for (int i = 0; i < container.getChildCount(); i++) { + View child = container.getChildAt(i); + if (child.getVisibility() != View.VISIBLE) { + continue; + } + if (child.isClickable()) { + return true; + } else if (child instanceof ViewGroup && findClickableView((ViewGroup) child, x - child.getX(), y - child.getY())) { + return true; + } + } + return false; + } + + public static void removeFromParent(View child) { + if (child.getParent() != null) { + ((ViewGroup) child.getParent()).removeView(child); + } + } + private static class LinkSpec { String url; int start; @@ -2193,12 +2214,20 @@ public static String obtainLoginPhoneCall(String pattern) { if (!hasCallPermissions) { return null; } + String order; + Bundle selectionArgs; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + order = "date DESC"; + } else { + order = "date DESC LIMIT 5"; + } try (Cursor cursor = ApplicationLoader.applicationContext.getContentResolver().query( CallLog.Calls.CONTENT_URI, new String[]{CallLog.Calls.NUMBER, CallLog.Calls.DATE}, CallLog.Calls.TYPE + " IN (" + CallLog.Calls.MISSED_TYPE + "," + CallLog.Calls.INCOMING_TYPE + "," + CallLog.Calls.REJECTED_TYPE + ")", null, - "date DESC LIMIT 5")) { + order + )) { while (cursor.moveToNext()) { String number = cursor.getString(0); long date = cursor.getLong(1); @@ -2926,7 +2955,9 @@ public static String formatFileSize(long size) { } public static String formatFileSize(long size, boolean removeZero) { - if (size < 1024) { + if (size == 0) { + return String.format("%d KB", 0); + } else if (size < 1024) { return String.format("%d B", size); } else if (size < 1024 * 1024) { float value = size / 1024.0f; @@ -2935,7 +2966,7 @@ public static String formatFileSize(long size, boolean removeZero) { } else { return String.format("%.1f KB", value); } - } else if (size < 1024 * 1024 * 1024) { + } else if (size < 1000 * 1024 * 1024) { float value = size / 1024.0f / 1024.0f; if (removeZero && (value - (int) value) * 10 == 0) { return String.format("%d MB", (int) value); @@ -3633,7 +3664,7 @@ public static void showProxyAlert(Activity activity, final String address, final lineView.setBackgroundColor(Theme.getColor(Theme.key_divider)); linearLayout.addView(lineView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1)); } - for (int a = 0; a < 5; a++) { + for (int a = 0; a < 6; a++) { String text = null; String detail = null; if (a == 0) { @@ -3651,6 +3682,9 @@ public static void showProxyAlert(Activity activity, final String address, final } else if (a == 4) { text = password; detail = LocaleController.getString("UseProxyPassword", R.string.UseProxyPassword); + } else if (a == 5) { + text = LocaleController.getString(R.string.Checking); + detail = LocaleController.getString(R.string.ProxyStatus); } if (TextUtils.isEmpty(text)) { continue; @@ -3660,8 +3694,22 @@ public static void showProxyAlert(Activity activity, final String address, final cell.getTextView().setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); cell.getValueTextView().setTextColor(Theme.getColor(Theme.key_dialogTextGray3)); linearLayout.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - if (a == 2) { - break; + + if (a == 5) { + try { + ConnectionsManager.getInstance(UserConfig.selectedAccount).checkProxy(address, Integer.parseInt(port), user, password, secret, time -> AndroidUtilities.runOnUIThread(() -> { + if (time == -1) { + cell.getTextView().setText(LocaleController.getString(R.string.Unavailable)); + cell.getTextView().setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText4)); + } else { + cell.getTextView().setText(LocaleController.getString(R.string.Available) + ", " + LocaleController.formatString(R.string.Ping, time)); + cell.getTextView().setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGreenText)); + } + })); + } catch (NumberFormatException ignored) { + cell.getTextView().setText(LocaleController.getString(R.string.Unavailable)); + cell.getTextView().setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText4)); + } } } @@ -4664,18 +4712,36 @@ public static CharSequence replaceCharSequence(String what, CharSequence from, C return spannableStringBuilder; } + public static CharSequence replaceMultipleCharSequence(String what, CharSequence from, CharSequence obj) { + SpannableStringBuilder spannableStringBuilder; + if (from instanceof SpannableStringBuilder) { + spannableStringBuilder = (SpannableStringBuilder) from; + } else { + spannableStringBuilder = new SpannableStringBuilder(from); + } + int index = TextUtils.indexOf(from, what); + while (index >= 0) { + spannableStringBuilder.replace(index, index + what.length(), obj); + index = TextUtils.indexOf(spannableStringBuilder, what); + } + return spannableStringBuilder; + } + public static Bitmap makeBlurBitmap(View view) { + return makeBlurBitmap(view, 6f, 7); + } + public static Bitmap makeBlurBitmap(View view, float downscale, int maxRadius) { if (view == null) { return null; } - int w = (int) (view.getWidth() / 6.0f); - int h = (int) (view.getHeight() / 6.0f); + int w = (int) (view.getWidth() / downscale); + int h = (int) (view.getHeight() / downscale); Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); - canvas.scale(1.0f / 6.0f, 1.0f / 6.0f); + canvas.scale(1.0f / downscale, 1.0f / downscale); canvas.drawColor(Theme.getColor(Theme.key_windowBackgroundWhite)); view.draw(canvas); - Utilities.stackBlurBitmap(bitmap, Math.max(7, Math.max(w, h) / 180)); + Utilities.stackBlurBitmap(bitmap, Math.max(maxRadius, Math.max(w, h) / 180)); return bitmap; } @@ -4808,4 +4874,54 @@ public static int[] roundPercents(float[] percents, int[] output) { return output; } + + public static boolean isRTL(CharSequence text) { + if (text == null || text.length() <= 0) { + return false; + } + char c; + for (int i = 0; i < text.length(); ++i) { + c = text.charAt(i); + if (c >= 0x590 && c <= 0x6ff) { + return true; + } + } + return false; + } + + private static Pattern uriParse; + private static Pattern getURIParsePattern() { + if (uriParse == null) { + uriParse = Pattern.compile("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"); // RFC 3986 B + } + return uriParse; + } + + public static String getHostAuthority(String uri) { + if (uri == null) { + return null; + } + // CVE-2017-13274 + Matcher matcher = getURIParsePattern().matcher(uri); + if (matcher.matches()) { + String authority = matcher.group(4); + if (authority != null) { + authority = authority.toLowerCase(); + } + return authority; + } + return null; + } + + public static String getHostAuthority(Uri uri) { + if (uri == null) { + return null; + } + return getHostAuthority(uri.toString()); + } + + public static boolean intersect1d(int x1, int x2, int y1, int y2) { + return Math.max(x1, x2) >= Math.min(y1, y2) && Math.max(y1, y2) >= Math.min(x1, x2); + } + } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java index d449fc06895..194ff0ca724 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java @@ -278,6 +278,7 @@ public void onActivityStarted(Activity activity) { AndroidUtilities.runOnUIThread(ApplicationLoader::startPushService); LauncherIconController.tryFixLauncherIconIfNeeded(); + ProxyRotationController.init(); } public static void startPushService() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AuthTokensHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/AuthTokensHelper.java new file mode 100644 index 00000000000..045670cba4f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AuthTokensHelper.java @@ -0,0 +1,119 @@ +package org.telegram.messenger; + +import android.content.Context; +import android.content.SharedPreferences; + +import com.google.android.exoplayer2.util.Log; + +import org.telegram.tgnet.SerializedData; +import org.telegram.tgnet.TLRPC; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; + +public class AuthTokensHelper { + + public static ArrayList getSavedLogOutTokens() { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("saved_tokens", Context.MODE_PRIVATE); + int count = preferences.getInt("count", 0); + + if (count == 0) { + return null; + } + + ArrayList tokens = new ArrayList<>(); + for (int i = 0; i < count; i++) { + String value = preferences.getString("log_out_token_" + i, ""); + SerializedData serializedData = new SerializedData(Utilities.hexToBytes(value)); + TLRPC.TL_auth_loggedOut token = TLRPC.TL_auth_loggedOut.TLdeserialize(serializedData, serializedData.readInt32(true), true); + if (token != null) { + tokens.add(token); + } + } + + return tokens; + } + + public static void saveLogOutTokens(ArrayList tokens) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("saved_tokens", Context.MODE_PRIVATE); + ArrayList activeTokens = new ArrayList<>(); + preferences.edit().clear().apply(); + int date = (int) (System.currentTimeMillis() / 1000L); + for (int i = 0; i < Math.min(20, tokens.size()); i++) { + activeTokens.add(tokens.get(i)); + } + if (activeTokens.size() > 0) { + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("count", activeTokens.size()); + for (int i = 0; i < activeTokens.size(); i++) { + SerializedData data = new SerializedData(activeTokens.get(i).getObjectSize()); + activeTokens.get(i).serializeToStream(data); + editor.putString("log_out_token_" + i, Utilities.bytesToHex(data.toByteArray())); + } + editor.apply(); + // BackupAgent.requestBackup(ApplicationLoader.applicationContext); + } + } + + public static ArrayList getSavedLogInTokens() { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("saved_tokens_login", Context.MODE_PRIVATE); + int count = preferences.getInt("count", 0); + + if (count == 0) { + return null; + } + + ArrayList tokens = new ArrayList<>(); + for (int i = 0; i < count; i++) { + String value = preferences.getString("log_in_token_" + i, ""); + SerializedData serializedData = new SerializedData(Utilities.hexToBytes(value)); + TLRPC.auth_Authorization token = TLRPC.auth_Authorization.TLdeserialize(serializedData, serializedData.readInt32(true), true); + if (token instanceof TLRPC.TL_auth_authorization) { + tokens.add((TLRPC.TL_auth_authorization) token); + } + } + + return tokens; + } + + public static void saveLogInToken(TLRPC.TL_auth_authorization token) { + if (BuildVars.DEBUG_VERSION) { + FileLog.d("saveLogInToken " + new String(token.future_auth_token, StandardCharsets.UTF_8)); + } + ArrayList tokens = getSavedLogInTokens(); + if (tokens == null) { + tokens = new ArrayList<>(); + } + tokens.add(0, token); + saveLogInTokens(tokens); + } + + private static void saveLogInTokens(ArrayList tokens) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("saved_tokens_login", Context.MODE_PRIVATE); + ArrayList activeTokens = new ArrayList<>(); + preferences.edit().clear().apply(); + for (int i = 0; i < Math.min(20, tokens.size()); i++) { + activeTokens.add(tokens.get(i)); + } + if (activeTokens.size() > 0) { + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("count", activeTokens.size()); + for (int i = 0; i < activeTokens.size(); i++) { + SerializedData data = new SerializedData(activeTokens.get(i).getObjectSize()); + activeTokens.get(i).serializeToStream(data); + editor.putString("log_in_token_" + i, Utilities.bytesToHex(data.toByteArray())); + } + editor.apply(); + BackupAgent.requestBackup(ApplicationLoader.applicationContext); + } + } + + public static void addLogOutToken(TLRPC.TL_auth_loggedOut response) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("saved_tokens", Context.MODE_PRIVATE); + int count = preferences.getInt("count", 0); + SerializedData data = new SerializedData(response.getObjectSize()); + response.serializeToStream(data); + preferences.edit().putString("log_out_token_" + count, Utilities.bytesToHex(data.toByteArray())).putInt("count", count + 1).apply(); + BackupAgent.requestBackup(ApplicationLoader.applicationContext); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BackupAgent.java b/TMessagesProj/src/main/java/org/telegram/messenger/BackupAgent.java new file mode 100644 index 00000000000..78ff6ee838f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BackupAgent.java @@ -0,0 +1,35 @@ +package org.telegram.messenger; + +import android.app.backup.BackupAgentHelper; +import android.app.backup.BackupDataInput; +import android.app.backup.BackupDataOutput; +import android.app.backup.BackupManager; +import android.app.backup.FullBackupDataOutput; +import android.app.backup.RestoreObserver; +import android.app.backup.SharedPreferencesBackupHelper; +import android.content.Context; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import org.telegram.tgnet.TLRPC; + +import java.io.IOException; +import java.util.ArrayList; + +public class BackupAgent extends BackupAgentHelper { + + private static BackupManager backupManager; + + @Override + public void onCreate() { + SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, "saved_tokens", "saved_tokens_login"); + addHelper("prefs", helper); + } + + public static void requestBackup(Context context) { + if (backupManager == null) { + backupManager = new BackupManager(context); + } + backupManager.dataChanged(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BillingController.java b/TMessagesProj/src/main/java/org/telegram/messenger/BillingController.java index 23ed977fa61..1a568b401d6 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BillingController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BillingController.java @@ -54,6 +54,8 @@ public class BillingController implements PurchasesUpdatedListener, BillingClien private Map> resultListeners = new HashMap<>(); private List requestingTokens = new ArrayList<>(); + private String lastPremiumTransaction; + private String lastPremiumToken; private Map currencyExpMap = new HashMap<>(); @@ -73,6 +75,14 @@ private BillingController(Context ctx) { .build(); } + public String getLastPremiumTransaction() { + return lastPremiumTransaction; + } + + public String getLastPremiumToken() { + return lastPremiumToken; + } + public String formatCurrency(long amount, String currency) { return formatCurrency(amount, currency, getCurrencyExp(currency)); } @@ -156,10 +166,10 @@ public void addResultListener(String productId, Consumer listener } public void launchBillingFlow(Activity activity, AccountInstance accountInstance, TLRPC.InputStorePaymentPurpose paymentPurpose, List productDetails) { - launchBillingFlow(activity, accountInstance, paymentPurpose, productDetails, false); + launchBillingFlow(activity, accountInstance, paymentPurpose, productDetails, null, false); } - public void launchBillingFlow(Activity activity, AccountInstance accountInstance, TLRPC.InputStorePaymentPurpose paymentPurpose, List productDetails, boolean checkedConsume) { + public void launchBillingFlow(Activity activity, AccountInstance accountInstance, TLRPC.InputStorePaymentPurpose paymentPurpose, List productDetails, BillingFlowParams.SubscriptionUpdateParams subscriptionUpdateParams, boolean checkedConsume) { if (!isReady() || activity == null) { return; } @@ -167,7 +177,7 @@ public void launchBillingFlow(Activity activity, AccountInstance accountInstance if (paymentPurpose instanceof TLRPC.TL_inputStorePaymentGiftPremium && !checkedConsume) { queryPurchases(BillingClient.ProductType.INAPP, (billingResult, list) -> { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { - Runnable callback = () -> launchBillingFlow(activity, accountInstance, paymentPurpose, productDetails, true); + Runnable callback = () -> launchBillingFlow(activity, accountInstance, paymentPurpose, productDetails, subscriptionUpdateParams, true); AtomicInteger productsToBeConsumed = new AtomicInteger(0); List productsConsumed = new ArrayList<>(); @@ -205,9 +215,12 @@ public void launchBillingFlow(Activity activity, AccountInstance accountInstance return; } - boolean ok = billingClient.launchBillingFlow(activity, BillingFlowParams.newBuilder() - .setProductDetailsParamsList(productDetails) - .build()).getResponseCode() == BillingClient.BillingResponseCode.OK; + BillingFlowParams.Builder flowParams = BillingFlowParams.newBuilder() + .setProductDetailsParamsList(productDetails); + if (subscriptionUpdateParams != null) { + flowParams.setSubscriptionUpdateParams(subscriptionUpdateParams); + } + boolean ok = billingClient.launchBillingFlow(activity, flowParams.build()).getResponseCode() == BillingClient.BillingResponseCode.OK; if (ok) { for (BillingFlowParams.ProductDetailsParams params : productDetails) { @@ -240,7 +253,13 @@ public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable L if (list == null) { return; } + lastPremiumTransaction = null; for (Purchase purchase : list) { + if (purchase.getProducts().contains(PREMIUM_PRODUCT_ID)) { + lastPremiumTransaction = purchase.getOrderId(); + lastPremiumToken = purchase.getPurchaseToken(); + } + if (!requestingTokens.contains(purchase.getPurchaseToken())) { for (int i = 0; i < UserConfig.MAX_ACCOUNT_COUNT; i++) { AccountInstance acc = AccountInstance.getInstance(i); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java index 194a65e389b..63052129fc6 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java @@ -24,11 +24,13 @@ public class BuildVars { public static boolean USE_CLOUD_STRINGS = true; public static boolean CHECK_UPDATES = true; public static boolean NO_SCOPED_STORAGE = Build.VERSION.SDK_INT <= 29; - public static int BUILD_VERSION = 3026; - public static String BUILD_VERSION_STRING = "9.3.3"; + public static int BUILD_VERSION = 3098; + public static String BUILD_VERSION_STRING = "9.4.0"; public static int APP_ID = 4; public static String APP_HASH = "014b35b6184100b085b0d0572f9b5103"; + // SafetyNet key for Google Identity SDK, set it to empty to disable + public static String SAFETYNET_KEY = "AIzaSyDqt8P-7F7CPCseMkOiVRgb1LY8RN1bvH8"; public static String SMS_HASH = isStandaloneApp() ? "w0lkcmTZkKh" : (DEBUG_VERSION ? "O2P2z+/jBpJ" : "oLeq9AcOZkT"); public static String PLAYSTORE_APP_URL = "https://play.google.com/store/apps/details?id=org.telegram.messenger"; public static String GOOGLE_AUTH_CLIENT_ID = "760348033671-81kmi3pi84p11ub8hp9a1funsv0rn2p9.apps.googleusercontent.com"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java index bd471c81a02..65ab143c5ab 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java @@ -38,6 +38,7 @@ public class ChatObject { public static final int CHAT_TYPE_CHANNEL = 2; public static final int CHAT_TYPE_USER = 3; public static final int CHAT_TYPE_MEGAGROUP = 4; + public static final int CHAT_TYPE_FORUM = 5; public static final int ACTION_PIN = 0; public static final int ACTION_CHANGE_INFO = 1; @@ -46,6 +47,7 @@ public class ChatObject { public static final int ACTION_ADD_ADMINS = 4; public static final int ACTION_POST = 5; public static final int ACTION_SEND = 6; + public static final int ACTION_SEND_TEXT = 22; public static final int ACTION_SEND_MEDIA = 7; public static final int ACTION_SEND_STICKERS = 8; public static final int ACTION_EMBED_LINKS = 9; @@ -56,6 +58,15 @@ public class ChatObject { public static final int ACTION_MANAGE_CALLS = 14; public static final int ACTION_MANAGE_TOPICS = 15; + public static final int ACTION_SEND_PHOTO = 16; + public static final int ACTION_SEND_VIDEO = 17; + public static final int ACTION_SEND_MUSIC = 18; + public static final int ACTION_SEND_DOCUMENTS = 19; + public static final int ACTION_SEND_VOICE = 20; + public static final int ACTION_SEND_ROUND = 21; + public static final int ACTION_SEND_PLAIN = 22; + public static final int ACTION_SEND_GIFS = 23; + public final static int VIDEO_FRAME_NO_FRAME = 0; public final static int VIDEO_FRAME_REQUESTING = 1; public final static int VIDEO_FRAME_HAS_FRAME = 2; @@ -85,6 +96,61 @@ public static boolean isForum(int currentAccount, long dialogId) { return false; } + public static boolean canSendAnyMedia(TLRPC.Chat currentChat) { + return canSendPhoto(currentChat) || canSendVideo(currentChat) || canSendRoundVideo(currentChat)|| canSendVoice(currentChat) || canSendDocument(currentChat) || canSendMusic(currentChat) || canSendStickers(currentChat); + } + + public static String getAllowedSendString(TLRPC.Chat chat) { + StringBuilder stringBuilder = new StringBuilder(); + if (ChatObject.canSendPhoto(chat)) { + stringBuilder.append(LocaleController.getString("SendMediaPermissionPhotos", R.string.SendMediaPermissionPhotos)); + } + if (ChatObject.canSendVideo(chat)) { + if (stringBuilder.length() > 0) { + stringBuilder.append(", "); + } + stringBuilder.append(LocaleController.getString("SendMediaPermissionVideos", R.string.SendMediaPermissionVideos)); + } + if (ChatObject.canSendStickers(chat)) { + if (stringBuilder.length() > 0) { + stringBuilder.append(", "); + } + stringBuilder.append(LocaleController.getString("SendMediaPermissionStickersGifs", R.string.SendMediaPermissionStickersGifs)); + } + if (ChatObject.canSendMusic(chat)) { + if (stringBuilder.length() > 0) { + stringBuilder.append(", "); + } + stringBuilder.append(LocaleController.getString("SendMediaPermissionMusic", R.string.SendMediaPermissionMusic)); + } + if (ChatObject.canSendDocument(chat)) { + if (stringBuilder.length() > 0) { + stringBuilder.append(", "); + } + stringBuilder.append(LocaleController.getString("SendMediaPermissionFiles", R.string.SendMediaPermissionFiles)); + } + if (ChatObject.canSendVoice(chat)) { + if (stringBuilder.length() > 0) { + stringBuilder.append(", "); + } + stringBuilder.append(LocaleController.getString("SendMediaPermissionVoice", R.string.SendMediaPermissionVoice)); + } + if (ChatObject.canSendRoundVideo(chat)) { + if (stringBuilder.length() > 0) { + stringBuilder.append(", "); + } + stringBuilder.append(LocaleController.getString("SendMediaPermissionRound", R.string.SendMediaPermissionRound)); + } + if (ChatObject.canSendEmbed(chat)) { + if (stringBuilder.length() > 0) { + stringBuilder.append(", "); + } + stringBuilder.append(LocaleController.getString("SendMediaEmbededLinks", R.string.SendMediaEmbededLinks)); + } + + return stringBuilder.toString(); + } + public static class Call { public final static int RECORD_TYPE_AUDIO = 0, RECORD_TYPE_VIDEO_PORTAIT = 1, @@ -1412,6 +1478,13 @@ private static boolean isBannableAction(int action) { case ACTION_SEND_POLLS: case ACTION_VIEW: case ACTION_MANAGE_TOPICS: + case ACTION_SEND_PHOTO: + case ACTION_SEND_VIDEO: + case ACTION_SEND_MUSIC: + case ACTION_SEND_DOCUMENTS: + case ACTION_SEND_VOICE: + case ACTION_SEND_ROUND: + case ACTION_SEND_PLAIN: return true; } return false; @@ -1459,14 +1532,31 @@ private static boolean getBannedRight(TLRPC.TL_chatBannedRights rights, int acti return rights.view_messages; case ACTION_MANAGE_TOPICS: return rights.manage_topics; + case ACTION_SEND_PHOTO: + return rights.send_photos; + case ACTION_SEND_VIDEO: + return rights.send_videos; + case ACTION_SEND_MUSIC: + return rights.send_audios; + case ACTION_SEND_DOCUMENTS: + return rights.send_docs; + case ACTION_SEND_VOICE: + return rights.send_voices; + case ACTION_SEND_ROUND: + return rights.send_roundvideos; + case ACTION_SEND_PLAIN: + return rights.send_plain; } return false; } public static boolean isActionBannedByDefault(TLRPC.Chat chat, int action) { - if (getBannedRight(chat.banned_rights, action)) { + if (chat == null) { return false; } + if (getBannedRight(chat.banned_rights, action) && getBannedRight(chat.default_banned_rights, action)) { + return true; + } return getBannedRight(chat.default_banned_rights, action); } @@ -1628,8 +1718,31 @@ public static boolean canSendEmbed(TLRPC.Chat chat) { return canUserDoAction(chat, ACTION_EMBED_LINKS); } - public static boolean canSendMedia(TLRPC.Chat chat) { - return canUserDoAction(chat, ACTION_SEND_MEDIA); + // public static boolean canSendMedia(TLRPC.Chat chat) { +// return canUserDoAction(chat, ACTION_SEND_MEDIA); +// } + public static boolean canSendPhoto(TLRPC.Chat chat) { + return canUserDoAction(chat, ACTION_SEND_PHOTO); + } + + public static boolean canSendVideo(TLRPC.Chat chat) { + return canUserDoAction(chat, ACTION_SEND_VIDEO); + } + + public static boolean canSendMusic(TLRPC.Chat chat) { + return canUserDoAction(chat, ACTION_SEND_MUSIC); + } + + public static boolean canSendDocument(TLRPC.Chat chat) { + return canUserDoAction(chat, ACTION_SEND_DOCUMENTS); + } + + public static boolean canSendVoice(TLRPC.Chat chat) { + return canUserDoAction(chat, ACTION_SEND_VOICE); + } + + public static boolean canSendRoundVideo(TLRPC.Chat chat) { + return canUserDoAction(chat, ACTION_SEND_ROUND); } public static boolean canSendPolls(TLRPC.Chat chat) { @@ -1640,6 +1753,10 @@ public static boolean canSendMessages(TLRPC.Chat chat) { return canUserDoAction(chat, ACTION_SEND); } + public static boolean canSendPlain(TLRPC.Chat chat) { + return canUserDoAction(chat, ACTION_SEND_PLAIN); + } + public static boolean canPost(TLRPC.Chat chat) { return canUserDoAction(chat, ACTION_POST); } @@ -1760,6 +1877,13 @@ public static String getBannedRightsString(TLRPC.TL_chatBannedRights bannedRight currentBannedRights += bannedRights.change_info ? 1 : 0; currentBannedRights += bannedRights.pin_messages ? 1 : 0; currentBannedRights += bannedRights.manage_topics ? 1 : 0; + currentBannedRights += bannedRights.send_photos ? 1 : 0; + currentBannedRights += bannedRights.send_videos ? 1 : 0; + currentBannedRights += bannedRights.send_roundvideos ? 1 : 0; + currentBannedRights += bannedRights.send_voices ? 1 : 0; + currentBannedRights += bannedRights.send_audios ? 1 : 0; + currentBannedRights += bannedRights.send_docs ? 1 : 0; + currentBannedRights += bannedRights.send_plain ? 1 : 0; currentBannedRights += bannedRights.until_date; return currentBannedRights; } @@ -1819,6 +1943,93 @@ public static boolean isPublic(TLRPC.Chat chat) { return !TextUtils.isEmpty(getPublicUsername(chat)); } + public static String getRestrictedErrorText(TLRPC.Chat chat, int action) { + if (action == ACTION_SEND_GIFS) { + if (chat == null || ChatObject.isActionBannedByDefault(chat, action)) { + return LocaleController.getString("GlobalAttachGifRestricted", R.string.GlobalAttachGifRestricted); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + return LocaleController.formatString("AttachGifRestrictedForever", R.string.AttachGifRestrictedForever); + } else { + return LocaleController.formatString("AttachGifRestricted", R.string.AttachGifRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date)); + } + } else if (action == ACTION_SEND_STICKERS) { + if (chat == null || ChatObject.isActionBannedByDefault(chat, action)) { + return LocaleController.getString("GlobalAttachStickersRestricted", R.string.GlobalAttachStickersRestricted); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + return LocaleController.formatString("AttachStickersRestrictedForever", R.string.AttachStickersRestrictedForever); + } else { + return LocaleController.formatString("AttachStickersRestricted", R.string.AttachStickersRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date)); + } + } else if (action == ACTION_SEND_PHOTO) { + if (chat == null || ChatObject.isActionBannedByDefault(chat, action)) { + return LocaleController.getString("GlobalAttachPhotoRestricted", R.string.GlobalAttachPhotoRestricted); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + return LocaleController.formatString("AttachPhotoRestrictedForever", R.string.AttachPhotoRestrictedForever); + } else { + return LocaleController.formatString("AttachPhotoRestricted", R.string.AttachPhotoRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date)); + } + } else if (action == ACTION_SEND_VIDEO) { + if (chat == null || ChatObject.isActionBannedByDefault(chat, action)) { + return LocaleController.getString("GlobalAttachVideoRestricted", R.string.GlobalAttachVideoRestricted); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + return LocaleController.formatString("AttachVideoRestrictedForever", R.string.AttachVideoRestrictedForever); + } else { + return LocaleController.formatString("AttachVideoRestricted", R.string.AttachVideoRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date)); + } + } else if (action == ACTION_SEND_DOCUMENTS) { + if (chat == null || ChatObject.isActionBannedByDefault(chat, action)) { + return LocaleController.getString("GlobalAttachDocumentsRestricted", R.string.GlobalAttachDocumentsRestricted); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + return LocaleController.formatString("AttachDocumentsRestrictedForever", R.string.AttachDocumentsRestrictedForever); + } else { + return LocaleController.formatString("AttachDocumentsRestricted", R.string.AttachDocumentsRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date)); + } + } else if (action == ACTION_SEND_MEDIA) { + if (chat == null || ChatObject.isActionBannedByDefault(chat, action)) { + return LocaleController.getString("GlobalAttachMediaRestricted", R.string.GlobalAttachMediaRestricted); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + return LocaleController.formatString("AttachMediaRestrictedForever", R.string.AttachMediaRestrictedForever); + } else { + return LocaleController.formatString("AttachMediaRestricted", R.string.AttachMediaRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date)); + } + } else if (action == ACTION_SEND_MUSIC) { + if (chat == null || ChatObject.isActionBannedByDefault(chat, action)) { + return LocaleController.getString("GlobalAttachAudioRestricted", R.string.GlobalAttachAudioRestricted); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + return LocaleController.formatString("AttachAudioRestrictedForever", R.string.AttachAudioRestrictedForever); + } else { + return LocaleController.formatString("AttachAudioRestricted", R.string.AttachAudioRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date)); + } + } else if (action == ACTION_SEND_PLAIN) { + if (chat == null || ChatObject.isActionBannedByDefault(chat, action)) { + return LocaleController.getString("GlobalAttachPlainRestricted", R.string.GlobalAttachPlainRestricted); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + return LocaleController.formatString("AttachPlainRestrictedForever", R.string.AttachPlainRestrictedForever); + } else { + return LocaleController.formatString("AttachPlainRestricted", R.string.AttachPlainRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date)); + } + } else if (action == ACTION_SEND_ROUND) { + if (chat == null || ChatObject.isActionBannedByDefault(chat, action)) { + return LocaleController.getString("GlobalAttachRoundRestricted", R.string.GlobalAttachRoundRestricted); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + return LocaleController.formatString("AttachRoundRestrictedForever", R.string.AttachRoundRestrictedForever); + } else { + return LocaleController.formatString("AttachRoundRestricted", R.string.AttachRoundRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date)); + } + } else if (action == ACTION_SEND_VOICE) { + if (chat == null || ChatObject.isActionBannedByDefault(chat, action)) { + return LocaleController.getString("GlobalAttachVoiceRestricted", R.string.GlobalAttachVoiceRestricted); + } else if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + return LocaleController.formatString("AttachVoiceRestrictedForever", R.string.AttachVoiceRestrictedForever); + } else { + return LocaleController.formatString("AttachVoiceRestricted", R.string.AttachVoiceRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date)); + } + } + + return ""; + } + + public static class VideoParticipant { public TLRPC.TL_groupCallParticipant participant; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java index 3a2020d4fdc..fd23f542132 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java @@ -762,7 +762,7 @@ public HashMap readContactsFromPhoneBook() { String lookup_key = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)); String name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); String phone = null; - if (contactsMap.get(lookup_key) != null || TextUtils.isEmpty(name)) { + if ((contactsMap != null && contactsMap.get(lookup_key) != null) || TextUtils.isEmpty(name)) { continue; } pCur = cr.query( diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java index 1ecc488f48c..db5c54af32a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java @@ -1218,6 +1218,12 @@ public static int migrate(MessagesStorage messagesStorage, int version) throws E version = 111; } + if (version == 111) { + database.executeFast("CREATE TABLE emoji_groups(type INTEGER PRIMARY KEY, data BLOB)").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 112").stepThis().dispose(); + version = 112; + } + return version; } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DocumentObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/DocumentObject.java index cc2f161b153..b63fe281065 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/DocumentObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/DocumentObject.java @@ -116,7 +116,10 @@ public static SvgHelper.SvgDrawable getSvgThumb(TLRPC.Document document, String int w = 512, h = 512; for (int a = 0, N = document.attributes.size(); a < N; a++) { TLRPC.DocumentAttribute attribute = document.attributes.get(a); - if (attribute instanceof TLRPC.TL_documentAttributeImageSize) { + if ( + attribute instanceof TLRPC.TL_documentAttributeImageSize || + attribute instanceof TLRPC.TL_documentAttributeVideo + ) { w = attribute.w; h = attribute.h; break; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java b/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java index d036520ee41..58fb9d41f87 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java @@ -64,6 +64,15 @@ public class Emoji { public static float emojiDrawingYOffset; public static boolean emojiDrawingUseAlpha = true; + private static String[] DEFAULT_RECENT = new String[]{ + "\uD83D\uDE02", "\uD83D\uDE18", "\u2764", "\uD83D\uDE0D", "\uD83D\uDE0A", "\uD83D\uDE01", + "\uD83D\uDC4D", "\u263A", "\uD83D\uDE14", "\uD83D\uDE04", "\uD83D\uDE2D", "\uD83D\uDC8B", + "\uD83D\uDE12", "\uD83D\uDE33", "\uD83D\uDE1C", "\uD83D\uDE48", "\uD83D\uDE09", "\uD83D\uDE03", + "\uD83D\uDE22", "\uD83D\uDE1D", "\uD83D\uDE31", "\uD83D\uDE21", "\uD83D\uDE0F", "\uD83D\uDE1E", + "\uD83D\uDE05", "\uD83D\uDE1A", "\uD83D\uDE4A", "\uD83D\uDE0C", "\uD83D\uDE00", "\uD83D\uDE0B", + "\uD83D\uDE06", "\uD83D\uDC4C", "\uD83D\uDE10", "\uD83D\uDE15" + }; + private final static int MAX_RECENT_EMOJI_COUNT = 48; static { @@ -663,6 +672,14 @@ public static void addRecentEmoji(String code) { emojiUseHistory.put(code, ++count); } + public static void removeRecentEmoji(String code) { + emojiUseHistory.remove(code); + recentEmoji.remove(code); + if (emojiUseHistory.isEmpty() || recentEmoji.isEmpty()) { + addRecentEmoji(DEFAULT_RECENT[0]); + } + } + public static void sortEmoji() { recentEmoji.clear(); for (HashMap.Entry entry : emojiUseHistory.entrySet()) { @@ -756,15 +773,8 @@ public static void loadRecentEmoji() { } if (emojiUseHistory.isEmpty()) { if (!preferences.getBoolean("filled_default", false)) { - String[] newRecent = new String[]{ - "\uD83D\uDE02", "\uD83D\uDE18", "\u2764", "\uD83D\uDE0D", "\uD83D\uDE0A", "\uD83D\uDE01", - "\uD83D\uDC4D", "\u263A", "\uD83D\uDE14", "\uD83D\uDE04", "\uD83D\uDE2D", "\uD83D\uDC8B", - "\uD83D\uDE12", "\uD83D\uDE33", "\uD83D\uDE1C", "\uD83D\uDE48", "\uD83D\uDE09", "\uD83D\uDE03", - "\uD83D\uDE22", "\uD83D\uDE1D", "\uD83D\uDE31", "\uD83D\uDE21", "\uD83D\uDE0F", "\uD83D\uDE1E", - "\uD83D\uDE05", "\uD83D\uDE1A", "\uD83D\uDE4A", "\uD83D\uDE0C", "\uD83D\uDE00", "\uD83D\uDE0B", - "\uD83D\uDE06", "\uD83D\uDC4C", "\uD83D\uDE10", "\uD83D\uDE15"}; - for (int i = 0; i < newRecent.length; i++) { - emojiUseHistory.put(newRecent[i], newRecent.length - i); + for (int i = 0; i < DEFAULT_RECENT.length; i++) { + emojiUseHistory.put(DEFAULT_RECENT[i], DEFAULT_RECENT.length - i); } preferences.edit().putBoolean("filled_default", true).commit(); saveRecentEmoji(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Fetcher.java b/TMessagesProj/src/main/java/org/telegram/messenger/Fetcher.java new file mode 100644 index 00000000000..44aa1f90aa1 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Fetcher.java @@ -0,0 +1,132 @@ +package org.telegram.messenger; + +import android.util.Pair; + +import java.util.ArrayList; +import java.util.HashMap; + +public abstract class Fetcher { + + protected void getRemote(int currentAccount, Args arguments, long hash, Utilities.Callback3 onResult) { + // Implement this function + } + + // Not specifying getLocal and setLocal would mean that data is cached only in RAM + protected void getLocal(int currentAccount, Args arguments, Utilities.Callback2 onResult) { + // Implement this function + onResult.run(0L, null); + } + + protected void setLocal(int currentAccount, Args arguments, R data, long hash) { + // Implement this function + } + + private long requestRemotelyTimeout = 4 * 60 * 1000; + + private HashMap, R> cachedResults; + private HashMap, ArrayList>> loadingCallbacks; + private HashMap, Long> lastRequestedRemotely; + + public void fetch(int currentAccount, Args arguments, Utilities.Callback onResult) { + final Pair key = new Pair<>(currentAccount, arguments); + + if (isLoading(key)) { + saveCallback(key, onResult); + return; + } + + R cached = getCachedResult(key); + if (cached != null && !shouldRequest(key)) { + if (onResult != null) { + onResult.run(cached); + } + return; + } + + saveCallback(key, onResult); + getLocal(currentAccount, arguments, (hash, data) -> { + if (shouldRequest(key)) { + saveLastRequested(key); + getRemote(currentAccount, arguments, hash, (notModified, remoteData, newHash) -> { + if (notModified) { + cacheResult(key, data); + callCallbacks(key, data); + } else { + if (remoteData != null) { + setLocal(currentAccount, arguments, remoteData, newHash); + cacheResult(key, remoteData); + } + callCallbacks(key, remoteData); + } + }); + } else { + cacheResult(key, data); + callCallbacks(key, data); + } + }); + } + + private R getCachedResult(Pair key) { + if (cachedResults == null) { + return null; + } + return cachedResults.get(key); + } + + private void cacheResult(Pair key, R result) { + if (cachedResults == null) { + cachedResults = new HashMap<>(); + } + cachedResults.put(key, result); + } + + private void saveLastRequested(Pair key) { + if (lastRequestedRemotely == null) { + lastRequestedRemotely = new HashMap<>(); + } + lastRequestedRemotely.put(key, System.currentTimeMillis()); + } + + private boolean shouldRequest(Pair key) { + Long lastRequested = lastRequestedRemotely != null ? lastRequestedRemotely.get(key) : null; + return lastRequested == null || System.currentTimeMillis() - lastRequested >= requestRemotelyTimeout; + } + + private boolean isLoading(Pair key) { + return loadingCallbacks != null && loadingCallbacks.get(key) != null; + } + + private void saveCallback(Pair key, Utilities.Callback callback) { + if (callback == null) { + return; + } + if (loadingCallbacks == null) { + loadingCallbacks = new HashMap<>(); + } + ArrayList> callbacks = loadingCallbacks.get(key); + if (callbacks == null) { + loadingCallbacks.put(key, callbacks = new ArrayList<>()); + } + callbacks.add(callback); + } + + private void callCallbacks(Pair key, R result) { + if (loadingCallbacks == null) { + return; + } + + final ArrayList> callbacks = loadingCallbacks.get(key); + if (callbacks == null) { + return; + } + + AndroidUtilities.runOnUIThread(() -> { + for (Utilities.Callback callback: callbacks) { + callback.run(result); + } + callbacks.clear(); + }); + + loadingCallbacks.remove(key); + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java index d96cc333933..9da5b22f6f1 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java @@ -1412,7 +1412,11 @@ private void onFinishLoadingFile(final boolean increment) { } else if (currentType == ConnectionsManager.FileTypePhoto) { StatsController.getInstance(currentAccount).incrementReceivedItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_PHOTOS, 1); } else if (currentType == ConnectionsManager.FileTypeFile) { - StatsController.getInstance(currentAccount).incrementReceivedItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_FILES, 1); + if (ext != null && (ext.toLowerCase().endsWith("mp3") || ext.toLowerCase().endsWith("m4a"))) { + StatsController.getInstance(currentAccount).incrementReceivedItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_MUSIC, 1); + } else { + StatsController.getInstance(currentAccount).incrementReceivedItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_FILES, 1); + } } } delegate.didFinishLoadingFile(FileLoadOperation.this, cacheFileFinal); @@ -2148,7 +2152,11 @@ protected void startDownloadRequest() { } else if (currentType == ConnectionsManager.FileTypePhoto) { StatsController.getInstance(currentAccount).incrementReceivedBytesCount(response.networkType, StatsController.TYPE_PHOTOS, response.getObjectSize() + 4); } else if (currentType == ConnectionsManager.FileTypeFile) { - StatsController.getInstance(currentAccount).incrementReceivedBytesCount(response.networkType, StatsController.TYPE_FILES, response.getObjectSize() + 4); + if (ext != null && (ext.toLowerCase().endsWith("mp3") || ext.toLowerCase().endsWith("m4a"))) { + StatsController.getInstance(currentAccount).incrementReceivedBytesCount(response.networkType, StatsController.TYPE_MUSIC, response.getObjectSize() + 4); + } else { + StatsController.getInstance(currentAccount).incrementReceivedBytesCount(response.networkType, StatsController.TYPE_FILES, response.getObjectSize() + 4); + } } } processRequestResult(requestInfo, error); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java index 9abfea23a92..c9febf7b8a1 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java @@ -45,7 +45,7 @@ public static FilePathDatabase.FileMeta getFileMetadataFromParent(int currentAcc String str = (String) parentObject; if (str.startsWith("sent_")) { if (sentPattern == null) { - sentPattern = Pattern.compile("sent_.*_([0-9]+)_([0-9]+)_([0-9]+)"); + sentPattern = Pattern.compile("sent_.*_([0-9]+)_([0-9]+)_([0-9]+)_([0-9]+)"); } try { Matcher matcher = sentPattern.matcher(str); @@ -54,6 +54,7 @@ public static FilePathDatabase.FileMeta getFileMetadataFromParent(int currentAcc fileMeta.messageId = Integer.parseInt(matcher.group(1)); fileMeta.dialogId = Long.parseLong(matcher.group(2)); fileMeta.messageType = Integer.parseInt(matcher.group(3)); + fileMeta.messageSize = Long.parseLong(matcher.group(4)); return fileMeta; } } catch (Exception e) { @@ -66,11 +67,25 @@ public static FilePathDatabase.FileMeta getFileMetadataFromParent(int currentAcc fileMeta.messageId = messageObject.getId(); fileMeta.dialogId = messageObject.getDialogId(); fileMeta.messageType = messageObject.type; + fileMeta.messageSize = messageObject.getSize(); return fileMeta; } return null; } + public static TLRPC.VideoSize getVectorMarkupVideoSize(TLRPC.Photo photo) { + if (photo == null || photo.video_sizes == null) { + return null; + } + for (int i = 0; i < photo.video_sizes.size(); i++) { + TLRPC.VideoSize videoSize = photo.video_sizes.get(i); + if (videoSize instanceof TLRPC.TL_videoSizeEmojiMarkup || videoSize instanceof TLRPC.TL_videoSizeStickerMarkup) { + return videoSize; + } + } + return null; + } + private int getPriorityValue(int priorityType) { if (priorityType == PRIORITY_STREAM) { return Integer.MAX_VALUE; @@ -732,7 +747,6 @@ private FileLoadOperation loadFileInternal(final TLRPC.Document document, final storeDir = getDirectory(type); boolean saveCustomPath = false; - if ((type == MEDIA_DIR_IMAGE || type == MEDIA_DIR_VIDEO) && canSaveToPublicStorage(parentObject)) { File newDir; if (type == MEDIA_DIR_IMAGE) { @@ -856,16 +870,27 @@ private boolean canSaveAsFile(Object parentObject) { } private boolean canSaveToPublicStorage(Object parentObject) { - if (SharedConfig.saveToGalleryFlags == 0 || BuildVars.NO_SCOPED_STORAGE) { + if (BuildVars.NO_SCOPED_STORAGE) { return false; } - if (parentObject instanceof MessageObject) { - MessageObject messageObject = (MessageObject) parentObject; + FilePathDatabase.FileMeta metadata = getFileMetadataFromParent(currentAccount, parentObject); + MessageObject messageObject = null; + if (metadata != null) { int flag; - long dialogId = messageObject.getDialogId(); - if (messageObject.isRoundVideo() || messageObject.isVoice() || messageObject.isAnyKindOfSticker() || getMessagesController().isChatNoForwards(getMessagesController().getChat(-dialogId)) || messageObject.messageOwner.noforwards || DialogObject.isEncryptedDialog(dialogId)) { + long dialogId = metadata.dialogId; + if (getMessagesController().isChatNoForwards(getMessagesController().getChat(-dialogId)) || DialogObject.isEncryptedDialog(dialogId)) { return false; } + if (parentObject instanceof MessageObject) { + messageObject = (MessageObject) parentObject; + if (messageObject.isRoundVideo() || messageObject.isVoice() || messageObject.isAnyKindOfSticker() || messageObject.messageOwner.noforwards) { + return false; + } + } else { + if (metadata.messageType == MessageObject.TYPE_ROUND_VIDEO || metadata.messageType == MessageObject.TYPE_STICKER || metadata.messageType == MessageObject.TYPE_VOICE) { + return false; + } + } if (dialogId >= 0) { flag = SharedConfig.SAVE_TO_GALLERY_FLAG_PEER; } else { @@ -876,7 +901,7 @@ private boolean canSaveToPublicStorage(Object parentObject) { } } - if ((SharedConfig.saveToGalleryFlags & flag) != 0) { + if (SaveToGallerySettingsHelper.needSave(flag, metadata, messageObject, currentAccount)) { return true; } } @@ -1182,13 +1207,64 @@ public static TLRPC.PhotoSize getClosestPhotoSizeWithSize(ArrayList 100 && closestObject.location != null && closestObject.location.dc_id == Integer.MIN_VALUE || obj instanceof TLRPC.TL_photoCachedSize || side > lastSide && lastSide < currentSide) { + if ( + closestObject == null || + side > 100 && closestObject.location != null && closestObject.location.dc_id == Integer.MIN_VALUE || + obj instanceof TLRPC.TL_photoCachedSize || side > lastSide && lastSide < currentSide + ) { + closestObject = obj; + lastSide = currentSide; + } + } else { + int currentSide = Math.max(obj.w, obj.h); + if ( + closestObject == null || + side > 100 && closestObject.location != null && closestObject.location.dc_id == Integer.MIN_VALUE || + obj instanceof TLRPC.TL_photoCachedSize || + currentSide <= side && lastSide < currentSide + ) { + closestObject = obj; + lastSide = currentSide; + } + } + } + return closestObject; + } + + public static TLRPC.VideoSize getClosestVideoSizeWithSize(ArrayList sizes, int side) { + return getClosestVideoSizeWithSize(sizes, side, false); + } + + public static TLRPC.VideoSize getClosestVideoSizeWithSize(ArrayList sizes, int side, boolean byMinSide) { + return getClosestVideoSizeWithSize(sizes, side, byMinSide, false); + } + + public static TLRPC.VideoSize getClosestVideoSizeWithSize(ArrayList sizes, int side, boolean byMinSide, boolean ignoreStripped) { + if (sizes == null || sizes.isEmpty()) { + return null; + } + int lastSide = 0; + TLRPC.VideoSize closestObject = null; + for (int a = 0; a < sizes.size(); a++) { + TLRPC.VideoSize obj = sizes.get(a); + if (obj == null || obj instanceof TLRPC.TL_videoSizeEmojiMarkup || obj instanceof TLRPC.TL_videoSizeStickerMarkup) { + continue; + } + if (byMinSide) { + int currentSide = Math.min(obj.h, obj.w); + if (closestObject == null || + side > 100 && closestObject.location != null && closestObject.location.dc_id == Integer.MIN_VALUE || + side > lastSide && lastSide < currentSide) { closestObject = obj; lastSide = currentSide; } } else { int currentSide = Math.max(obj.w, obj.h); - if (closestObject == null || side > 100 && closestObject.location != null && closestObject.location.dc_id == Integer.MIN_VALUE || obj instanceof TLRPC.TL_photoCachedSize || currentSide <= side && lastSide < currentSide) { + if ( + closestObject == null || + side > 100 && closestObject.location != null && closestObject.location.dc_id == Integer.MIN_VALUE || + currentSide <= side && lastSide < currentSide + ) { closestObject = obj; lastSide = currentSide; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FilePathDatabase.java b/TMessagesProj/src/main/java/org/telegram/messenger/FilePathDatabase.java index ad1e909f5d5..929c237d398 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FilePathDatabase.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FilePathDatabase.java @@ -445,5 +445,6 @@ public static class FileMeta { public long dialogId; public int messageId; public int messageType; + public long messageSize; } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileUploadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileUploadOperation.java index f208907fe3f..f1574ff3620 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileUploadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileUploadOperation.java @@ -535,7 +535,11 @@ private void startUploadRequest() { } else if (currentType == ConnectionsManager.FileTypePhoto) { StatsController.getInstance(currentAccount).incrementSentBytesCount(networkType, StatsController.TYPE_PHOTOS, requestSize); } else if (currentType == ConnectionsManager.FileTypeFile) { - StatsController.getInstance(currentAccount).incrementSentBytesCount(networkType, StatsController.TYPE_FILES, requestSize); + if (uploadingFilePath != null && (uploadingFilePath.toLowerCase().endsWith("mp3") || uploadingFilePath.toLowerCase().endsWith("m4a"))) { + StatsController.getInstance(currentAccount).incrementSentBytesCount(networkType, StatsController.TYPE_MUSIC, requestSize); + } else { + StatsController.getInstance(currentAccount).incrementSentBytesCount(networkType, StatsController.TYPE_FILES, requestSize); + } } if (currentRequestIv != null) { freeRequestIvs.add(currentRequestIv); @@ -590,7 +594,11 @@ private void startUploadRequest() { } else if (currentType == ConnectionsManager.FileTypePhoto) { StatsController.getInstance(currentAccount).incrementSentItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_PHOTOS, 1); } else if (currentType == ConnectionsManager.FileTypeFile) { - StatsController.getInstance(currentAccount).incrementSentItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_FILES, 1); + if (uploadingFilePath != null && (uploadingFilePath.toLowerCase().endsWith("mp3") || uploadingFilePath.toLowerCase().endsWith("m4a"))) { + StatsController.getInstance(currentAccount).incrementSentItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_MUSIC, 1); + } else { + StatsController.getInstance(currentAccount).incrementSentItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_FILES, 1); + } } } else if (currentUploadRequetsCount < maxRequestsCount) { if (estimatedSize == 0 && !uploadFirstPartLater && !nextPartFirst) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java index d6d522523f0..1e8af90fb9f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java @@ -74,6 +74,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; import java.util.zip.GZIPInputStream; @@ -86,6 +87,7 @@ * b - need blur image * g - autoplay * lastframe - return lastframe for Lottie animation + * lastreactframe - return lastframe for Lottie animation + some scale ReactionLastFrame magic * firstframe - return firstframe for Lottie animation */ public class ImageLoader { @@ -870,6 +872,7 @@ public void run() { boolean precache = false; boolean limitFps = false; boolean lastFrameBitmap = false; + boolean lastFrameReactionScaleBitmap = false; boolean firstFrameBitmap = false; int autoRepeat = 1; int[] colors = null; @@ -896,6 +899,10 @@ public void run() { if (cacheImage.filter.contains("lastframe")) { lastFrameBitmap = true; } + if (cacheImage.filter.contains("lastreactframe")) { + lastFrameBitmap = true; + lastFrameReactionScaleBitmap = true; + } if (cacheImage.filter.contains("firstframe")) { firstFrameBitmap = true; } @@ -964,13 +971,17 @@ public void run() { precache = false; } BitmapsCache.CacheOptions cacheOptions = null; - if (precache) { + if (precache || lastFrameBitmap || firstFrameBitmap) { cacheOptions = new BitmapsCache.CacheOptions(); - if (cacheImage.filter != null && cacheImage.filter.contains("compress")) { - cacheOptions.compressQuality = BitmapsCache.COMPRESS_QUALITY_DEFAULT; - } - if (cacheImage.filter != null && cacheImage.filter.contains("flbk")) { - cacheOptions.fallback = true; + if (!lastFrameBitmap && !firstFrameBitmap) { + if (cacheImage.filter != null && cacheImage.filter.contains("compress")) { + cacheOptions.compressQuality = BitmapsCache.COMPRESS_QUALITY_DEFAULT; + } + if (cacheImage.filter != null && cacheImage.filter.contains("flbk")) { + cacheOptions.fallback = true; + } + } else { + cacheOptions.firstFrame = true; } } if (compressed) { @@ -980,7 +991,7 @@ public void run() { } } if (lastFrameBitmap || firstFrameBitmap) { - loadLastFrame(lottieDrawable, h, w, lastFrameBitmap); + loadLastFrame(lottieDrawable, h, w, lastFrameBitmap, lastFrameReactionScaleBitmap); } else { lottieDrawable.setAutoRepeat(autoRepeat); onPostExecute(lottieDrawable); @@ -995,6 +1006,8 @@ public void run() { } boolean limitFps = false; boolean precache = false; + boolean fistFrame = false; + boolean notCreateStream = false; if (cacheImage.filter != null) { String[] args = cacheImage.filter.split("_"); if (args.length >= 2) { @@ -1008,20 +1021,28 @@ public void run() { if ("pcache".equals(args[i])) { precache = true; } + if ("firstframe".equals(args[i])) { + fistFrame = true; + } + if ("nostream".equals(args[i])) { + notCreateStream = true; + } + } + if (fistFrame) { + notCreateStream = true; + } + } + BitmapsCache.CacheOptions cacheOptions = null; + if (precache && !fistFrame) { + cacheOptions = new BitmapsCache.CacheOptions(); + if (cacheImage.filter != null && cacheImage.filter.contains("compress")) { + cacheOptions.compressQuality = BitmapsCache.COMPRESS_QUALITY_DEFAULT; } } if ((isAnimatedAvatar(cacheImage.filter) || AUTOPLAY_FILTER.equals(cacheImage.filter)) && !(cacheImage.imageLocation.document instanceof TLRPC.TL_documentEncrypted) && !precache) { TLRPC.Document document = cacheImage.imageLocation.document instanceof TLRPC.Document ? cacheImage.imageLocation.document : null; long size = document != null ? cacheImage.size : cacheImage.imageLocation.currentSize; - BitmapsCache.CacheOptions cacheOptions = null; - if (precache) { - cacheOptions = new BitmapsCache.CacheOptions(); - if (cacheImage.filter != null && cacheImage.filter.contains("compress")) { - cacheOptions.compressQuality = BitmapsCache.COMPRESS_QUALITY_DEFAULT; - } - } - boolean notCreateStream = cacheImage.filter != null && cacheImage.filter.contains("nostream"); - fileDrawable = new AnimatedFileDrawable(cacheImage.finalFilePath, false, notCreateStream ? 0 : size, notCreateStream ? null : document, document == null && !notCreateStream ? cacheImage.imageLocation : null, cacheImage.parentObject, seekTo, cacheImage.currentAccount, false, cacheOptions); + fileDrawable = new AnimatedFileDrawable(cacheImage.finalFilePath, fistFrame, notCreateStream ? 0 : size, notCreateStream ? null : document, document == null && !notCreateStream ? cacheImage.imageLocation : null, cacheImage.parentObject, seekTo, cacheImage.currentAccount, false, cacheOptions); fileDrawable.setIsWebmSticker(MessageObject.isWebM(document) || MessageObject.isVideoSticker(document) || isAnimatedAvatar(cacheImage.filter)); } else { @@ -1036,21 +1057,25 @@ public void run() { h = (int) (h_filter * AndroidUtilities.density); } } - BitmapsCache.CacheOptions cacheOptions = null; - if (precache) { - cacheOptions = new BitmapsCache.CacheOptions(); - if (cacheImage.filter != null && cacheImage.filter.contains("compress")) { - cacheOptions.compressQuality = BitmapsCache.COMPRESS_QUALITY_DEFAULT; - } - } - boolean createDecoder = cacheImage.filter != null && ("d".equals(cacheImage.filter) || cacheImage.filter.contains("_d")); - boolean notCreateStream = cacheImage.filter != null && cacheImage.filter.contains("nostream"); + boolean createDecoder = fistFrame || (cacheImage.filter != null && ("d".equals(cacheImage.filter) || cacheImage.filter.contains("_d"))); fileDrawable = new AnimatedFileDrawable(cacheImage.finalFilePath, createDecoder, 0, notCreateStream ? null : cacheImage.imageLocation.document, null, null, seekTo, cacheImage.currentAccount, false, w, h, cacheOptions); fileDrawable.setIsWebmSticker(MessageObject.isWebM(cacheImage.imageLocation.document) || MessageObject.isVideoSticker(cacheImage.imageLocation.document) || isAnimatedAvatar(cacheImage.filter)); } - fileDrawable.setLimitFps(limitFps); - Thread.interrupted(); - onPostExecute(fileDrawable); + if (fistFrame) { + Bitmap bitmap = fileDrawable.getFrameAtTime(0, false); + + fileDrawable.recycle(); + Thread.interrupted(); + if (bitmap == null) { + onPostExecute(null); + } else { + onPostExecute(new BitmapDrawable(bitmap)); + } + } else { + fileDrawable.setLimitFps(limitFps); + Thread.interrupted(); + onPostExecute(fileDrawable); + } } else { Long mediaId = null; boolean mediaIsVideo = false; @@ -1548,10 +1573,10 @@ public void run() { } } - private void loadLastFrame(RLottieDrawable lottieDrawable, int w, int h, boolean lastFrame) { + private void loadLastFrame(RLottieDrawable lottieDrawable, int w, int h, boolean lastFrame, boolean reaction) { Bitmap bitmap; Canvas canvas; - if (lastFrame) { + if (lastFrame && reaction) { bitmap = Bitmap.createBitmap((int) (w * ImageReceiver.ReactionLastFrame.LAST_FRAME_SCALE), (int) (h * ImageReceiver.ReactionLastFrame.LAST_FRAME_SCALE), Bitmap.Config.ARGB_8888); canvas = new Canvas(bitmap); canvas.scale(2f, 2f, w * ImageReceiver.ReactionLastFrame.LAST_FRAME_SCALE / 2f, h * ImageReceiver.ReactionLastFrame.LAST_FRAME_SCALE / 2f); @@ -1560,32 +1585,29 @@ private void loadLastFrame(RLottieDrawable lottieDrawable, int w, int h, boolean canvas = new Canvas(bitmap); } + lottieDrawable.prepareForGenerateCache(); + Bitmap currentBitmap = Bitmap.createBitmap(lottieDrawable.getIntrinsicWidth(), lottieDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); + lottieDrawable.setGeneratingFrame(lastFrame ? lottieDrawable.getFramesCount() - 1 : 0); + lottieDrawable.getNextFrame(currentBitmap); + lottieDrawable.releaseForGenerateCache(); + canvas.save(); + if (!(lastFrame && reaction)) { + canvas.scale(currentBitmap.getWidth() / w, currentBitmap.getHeight() / h, w / 2f, h / 2f); + } + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setFilterBitmap(true); + BitmapDrawable bitmapDrawable = null; + if (lastFrame && reaction) { + canvas.drawBitmap(currentBitmap, (bitmap.getWidth() - currentBitmap.getWidth()) / 2f, (bitmap.getHeight() - currentBitmap.getHeight()) / 2f, paint); + bitmapDrawable = new ImageReceiver.ReactionLastFrame(bitmap); + } else { + canvas.drawBitmap(currentBitmap, 0, 0, paint); + bitmapDrawable = new BitmapDrawable(bitmap); + } - AndroidUtilities.runOnUIThread(() -> { - lottieDrawable.setOnFrameReadyRunnable(() -> { - lottieDrawable.setOnFrameReadyRunnable(null); - BitmapDrawable bitmapDrawable = null; - if (lottieDrawable.getBackgroundBitmap() != null || lottieDrawable.getRenderingBitmap() != null) { - Bitmap currentBitmap = lottieDrawable.getBackgroundBitmap() != null ? lottieDrawable.getBackgroundBitmap() : lottieDrawable.getRenderingBitmap(); - canvas.save(); - if (!lastFrame) { - canvas.scale(currentBitmap.getWidth() / w, currentBitmap.getHeight() / h, w / 2f, h / 2f); - } - Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); - paint.setFilterBitmap(true); - if (lastFrame) { - canvas.drawBitmap(currentBitmap, (bitmap.getWidth() - currentBitmap.getWidth()) / 2f, (bitmap.getHeight() - currentBitmap.getHeight()) / 2f, paint); - bitmapDrawable = new ImageReceiver.ReactionLastFrame(bitmap); - } else { - canvas.drawBitmap(currentBitmap, 0, 0, paint); - bitmapDrawable = new BitmapDrawable(bitmap); - } - } - onPostExecute(bitmapDrawable); - lottieDrawable.recycle(); - }); - lottieDrawable.setCurrentFrame(lastFrame ? lottieDrawable.getFramesCount() - 1 : 0, true, true); - }); + lottieDrawable.recycle(); + currentBitmap.recycle(); + onPostExecute(bitmapDrawable); } private void onPostExecute(final Drawable drawable) { @@ -1736,7 +1758,7 @@ private class CacheImage { public void addImageReceiver(ImageReceiver imageReceiver, String key, String filter, int type, int guid) { int index = imageReceiverArray.indexOf(imageReceiver); - if (index >= 0) { + if (index >= 0 && Objects.equals(imageReceiverArray.get(index).getImageKey(), key)) { imageReceiverGuidsArray.set(index, guid); return; } @@ -2040,11 +2062,14 @@ public void fileDidFailedUpload(final String location, final boolean isEncrypted public void fileDidLoaded(final String location, final File finalFile, Object parentObject, final int type) { fileProgresses.remove(location); AndroidUtilities.runOnUIThread(() -> { - if (SharedConfig.saveToGalleryFlags != 0 && finalFile != null && (location.endsWith(".mp4") || location.endsWith(".jpg"))) { - if (parentObject instanceof MessageObject) { - MessageObject messageObject = (MessageObject) parentObject; - - long dialogId = messageObject.getDialogId(); + if (finalFile != null && (location.endsWith(".mp4") || location.endsWith(".jpg"))) { + FilePathDatabase.FileMeta meta = FileLoader.getFileMetadataFromParent(currentAccount, parentObject); + if (meta != null) { + MessageObject messageObject = null; + if (parentObject instanceof MessageObject) { + messageObject = (MessageObject) parentObject; + } + long dialogId = meta.dialogId; int flag; if (dialogId >= 0) { flag = SharedConfig.SAVE_TO_GALLERY_FLAG_PEER; @@ -2055,7 +2080,7 @@ public void fileDidLoaded(final String location, final File finalFile, Object pa flag = SharedConfig.SAVE_TO_GALLERY_FLAG_GROUP; } } - if ((SharedConfig.saveToGalleryFlags & flag) != 0) { + if (SaveToGallerySettingsHelper.needSave(flag, meta, messageObject, currentAccount)) { AndroidUtilities.addMediaToGallery(finalFile.toString()); } } @@ -2656,6 +2681,7 @@ private void createLoadOperationForImageReceiver(final ImageReceiver imageReceiv final boolean shouldGenerateQualityThumb = imageReceiver.isShouldGenerateQualityThumb(); final int currentAccount = imageReceiver.getCurrentAccount(); final boolean currentKeyQuality = type == ImageReceiver.TYPE_IMAGE && imageReceiver.isCurrentKeyQuality(); + final Runnable loadOperationRunnable = () -> { boolean added = false; if (thumb != 2) { @@ -3320,6 +3346,9 @@ private BitmapDrawable getFromLottieCache(String imageKey) { } private boolean useLottieMemCache(ImageLocation imageLocation, String key) { + if (key.endsWith("_firstframe") || key.endsWith("_lastframe")) { + return false; + } return imageLocation != null && (MessageObject.isAnimatedStickerDocument(imageLocation.document, true) || imageLocation.imageType == FileLoader.IMAGE_TYPE_LOTTIE || MessageObject.isVideoSticker(imageLocation.document)) || isAnimatedAvatar(key); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLocation.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLocation.java index 47a415bcd2b..287a6d5bfeb 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLocation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLocation.java @@ -118,7 +118,8 @@ public static ImageLocation getForPhoto(TLRPC.PhotoSize photoSize, TLRPC.Photo p public static final int TYPE_BIG = 0; public static final int TYPE_SMALL = 1; public static final int TYPE_STRIPPED = 2; - public static final int TYPE_VIDEO_THUMB = 3; + public static final int TYPE_VIDEO_SMALL = 3; + public static final int TYPE_VIDEO_BIG = 4; public static ImageLocation getForUserOrChat(TLObject object, int type) { if (object instanceof TLRPC.User) { @@ -133,19 +134,25 @@ public static ImageLocation getForUser(TLRPC.User user, int type) { if (user == null || user.access_hash == 0 || user.photo == null) { return null; } - if (type == TYPE_VIDEO_THUMB) { + if (type == TYPE_VIDEO_BIG || type == TYPE_VIDEO_SMALL) { int currentAccount = UserConfig.selectedAccount; if (MessagesController.getInstance(currentAccount).isPremiumUser(user) && user.photo.has_video) { final TLRPC.UserFull userFull = MessagesController.getInstance(currentAccount).getUserFull(user.id); if (userFull != null && userFull.profile_photo != null && userFull.profile_photo.video_sizes != null && !userFull.profile_photo.video_sizes.isEmpty()) { - TLRPC.VideoSize videoSize = userFull.profile_photo.video_sizes.get(0); - for (int i = 0; i < userFull.profile_photo.video_sizes.size(); i++) { - if ("p".equals(userFull.profile_photo.video_sizes.get(i).type)) { - videoSize = userFull.profile_photo.video_sizes.get(i); - break; + if (type == TYPE_VIDEO_BIG) { + TLRPC.VideoSize videoSize = FileLoader.getClosestVideoSizeWithSize(userFull.profile_photo.video_sizes, 1000); + return ImageLocation.getForPhoto(videoSize, userFull.profile_photo); + } else { + TLRPC.VideoSize videoSize = FileLoader.getClosestVideoSizeWithSize(userFull.profile_photo.video_sizes, 100); + for (int i = 0; i < userFull.profile_photo.video_sizes.size(); i++) { + if ("p".equals(userFull.profile_photo.video_sizes.get(i).type)) { + videoSize = userFull.profile_photo.video_sizes.get(i); + break; + } } + return ImageLocation.getForPhoto(videoSize, userFull.profile_photo); } - return ImageLocation.getForPhoto(videoSize, userFull.profile_photo); + } } return null; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java index 0ef7415bc05..dbc57d4cd2d 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java @@ -33,12 +33,14 @@ import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.Components.AnimatedFileDrawable; +import org.telegram.ui.Components.AttachableDrawable; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.ClipRoundedDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LoadingStickerDrawable; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RecyclableDrawable; +import org.telegram.ui.Components.VectorAvatarThumbDrawable; import java.util.ArrayList; @@ -370,10 +372,10 @@ public void setForUserOrChat(TLObject object, Drawable avatarDrawable) { setForUserOrChat(object, avatarDrawable, null); } public void setForUserOrChat(TLObject object, Drawable avatarDrawable, Object parentObject) { - setForUserOrChat(object, avatarDrawable, null, false); + setForUserOrChat(object, avatarDrawable, parentObject, false, 0); } - public void setForUserOrChat(TLObject object, Drawable avatarDrawable, Object parentObject, boolean animationEnabled) { + public void setForUserOrChat(TLObject object, Drawable avatarDrawable, Object parentObject, boolean animationEnabled, int vectorType) { if (parentObject == null) { parentObject = object; } @@ -381,29 +383,46 @@ public void setForUserOrChat(TLObject object, Drawable avatarDrawable, Object pa BitmapDrawable strippedBitmap = null; boolean hasStripped = false; ImageLocation videoLocation = null; + TLRPC.VideoSize vectorImageMarkup = null; + boolean isPremium = false; if (object instanceof TLRPC.User) { TLRPC.User user = (TLRPC.User) object; + isPremium = user.premium; if (user.photo != null) { strippedBitmap = user.photo.strippedBitmap; hasStripped = user.photo.stripped_thumb != null; - if (animationEnabled && MessagesController.getInstance(currentAccount).isPremiumUser(user) && user.photo.has_video && !SharedConfig.getLiteMode().enabled()) { + if (vectorType == VectorAvatarThumbDrawable.TYPE_STATIC) { + final TLRPC.UserFull userFull = MessagesController.getInstance(currentAccount).getUserFull(user.id); + if (userFull != null) { + TLRPC.Photo photo = user.photo.personal ? userFull.personal_photo : userFull.profile_photo; + if (photo != null) { + vectorImageMarkup = FileLoader.getVectorMarkupVideoSize(photo); + } + } + } + if (vectorImageMarkup == null && animationEnabled && MessagesController.getInstance(currentAccount).isPremiumUser(user) && user.photo.has_video && !SharedConfig.getLiteMode().enabled()) { final TLRPC.UserFull userFull = MessagesController.getInstance(currentAccount).getUserFull(user.id); if (userFull == null) { MessagesController.getInstance(currentAccount).loadFullUser(user, currentGuid, false); } else { - TLRPC.Photo photo = userFull.profile_photo; + TLRPC.Photo photo = user.photo.personal ? userFull.personal_photo : userFull.profile_photo; if (photo != null) { - ArrayList videoSizes = photo.video_sizes; - if (videoSizes != null && !videoSizes.isEmpty()) { - TLRPC.VideoSize videoSize = videoSizes.get(0); - for (int i = 0; i < videoSizes.size(); i++) { - TLRPC.VideoSize videoSize1 = videoSizes.get(i); - if ("p".equals(videoSize1.type)) { - videoSize = videoSize1; - break; + vectorImageMarkup = FileLoader.getVectorMarkupVideoSize(photo); + if (vectorImageMarkup == null) { + ArrayList videoSizes = photo.video_sizes; + if (videoSizes != null && !videoSizes.isEmpty()) { + TLRPC.VideoSize videoSize = FileLoader.getClosestVideoSizeWithSize(videoSizes, 100); + for (int i = 0; i < videoSizes.size(); i++) { + TLRPC.VideoSize videoSize1 = videoSizes.get(i); + if ("p".equals(videoSize1.type)) { + videoSize = videoSize1; + } + if (videoSize1 instanceof TLRPC.TL_videoSizeEmojiMarkup || videoSize1 instanceof TLRPC.TL_videoSizeStickerMarkup) { + vectorImageMarkup = videoSize1; + } } + videoLocation = ImageLocation.getForPhoto(videoSize, photo); } - videoLocation = ImageLocation.getForPhoto(videoSize, photo); } } } @@ -416,18 +435,23 @@ public void setForUserOrChat(TLObject object, Drawable avatarDrawable, Object pa hasStripped = chat.photo.stripped_thumb != null; } } - ImageLocation location = ImageLocation.getForUserOrChat(object, ImageLocation.TYPE_SMALL); - String filter = "50_50"; - if (videoLocation != null) { - setImage(videoLocation, "avatar", location, filter, null, null, strippedBitmap, 0, null, parentObject, 0); - animatedFileDrawableRepeatMaxCount = 3; + if (vectorImageMarkup != null && vectorType != 0) { + VectorAvatarThumbDrawable drawable = new VectorAvatarThumbDrawable(vectorImageMarkup, isPremium, vectorType); + setImageBitmap(drawable); } else { - if (strippedBitmap != null) { - setImage(location, filter, strippedBitmap, null, parentObject, 0); - } else if (hasStripped) { - setImage(location, filter, ImageLocation.getForUserOrChat(object, ImageLocation.TYPE_STRIPPED), "50_50_b", avatarDrawable, parentObject, 0); + ImageLocation location = ImageLocation.getForUserOrChat(object, ImageLocation.TYPE_SMALL); + String filter = "50_50"; + if (videoLocation != null) { + setImage(videoLocation, "avatar", location, filter, null, null, strippedBitmap, 0, null, parentObject, 0); + animatedFileDrawableRepeatMaxCount = 3; } else { - setImage(location, filter, avatarDrawable, null, parentObject, 0); + if (strippedBitmap != null) { + setImage(location, filter, strippedBitmap, null, parentObject, 0); + } else if (hasStripped) { + setImage(location, filter, ImageLocation.getForUserOrChat(object, ImageLocation.TYPE_STRIPPED), "50_50_b", avatarDrawable, parentObject, 0); + } else { + setImage(location, filter, avatarDrawable, null, parentObject, 0); + } } } @@ -501,7 +525,7 @@ public void setImage(ImageLocation mediaLocation, String mediaFilter, ImageLocat currentParentObject = null; currentCacheType = 0; roundPaint.setShader(null); - staticThumbDrawable = thumb; + setStaticDrawable(thumb); currentAlpha = 1.0f; previousAlpha = 1f; currentSize = 0; @@ -653,7 +677,7 @@ public void setImage(ImageLocation mediaLocation, String mediaFilter, ImageLocat currentExt = ext; currentSize = size; currentCacheType = cacheType; - staticThumbDrawable = thumb; + setStaticDrawable(thumb); imageShader = null; composeShader = null; thumbShader = null; @@ -820,7 +844,8 @@ public void setImageBitmap(Drawable bitmap) { } thumbShader = null; roundPaint.setShader(null); - staticThumbDrawable = bitmap; + setStaticDrawable(bitmap); + updateDrawableRadius(bitmap); currentMediaLocation = null; currentMediaFilter = null; @@ -870,6 +895,26 @@ public void setImageBitmap(Drawable bitmap) { } } + private void setStaticDrawable(Drawable bitmap) { + if (bitmap == staticThumbDrawable) { + return; + } + AttachableDrawable oldDrawable = null; + if (staticThumbDrawable instanceof AttachableDrawable) { + if (staticThumbDrawable.equals(bitmap)) { + return; + } + oldDrawable = (AttachableDrawable) staticThumbDrawable; + } + staticThumbDrawable = bitmap; + if (attachedToWindow && staticThumbDrawable instanceof AttachableDrawable) { + ((AttachableDrawable) staticThumbDrawable).onAttachedToWindow(this); + } + if (attachedToWindow && oldDrawable != null) { + oldDrawable.onDetachedFromWindow(this); + } + } + private void setDrawableShader(Drawable drawable, BitmapShader shader) { if (drawable == currentThumbDrawable || drawable == staticThumbDrawable) { thumbShader = shader; @@ -965,9 +1010,12 @@ public void onDetachedFromWindow() { NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.stopAllHeavyOperations); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.startAllHeavyOperations); } + if (staticThumbDrawable instanceof AttachableDrawable) { + ((AttachableDrawable) staticThumbDrawable).onDetachedFromWindow(this); + } if (staticThumbDrawable != null) { - staticThumbDrawable = null; + setStaticDrawable(null); thumbShader = null; roundPaint.setShader(null); } @@ -1055,6 +1103,9 @@ public boolean onAttachedToWindow() { if (NotificationCenter.getGlobalInstance().isAnimationInProgress()) { didReceivedNotification(NotificationCenter.stopAllHeavyOperations, currentAccount, 512); } + if (staticThumbDrawable instanceof AttachableDrawable) { + ((AttachableDrawable) staticThumbDrawable).onAttachedToWindow(this); + } return false; } @@ -1888,6 +1939,9 @@ public boolean draw(Canvas canvas, BackgroundThreadDrawHolder backgroundThreadDr checkAlphaAnimation(animationNotReady && crossfadeWithThumb, backgroundThreadDrawHolder); result = true; } else if (staticThumbDrawable != null) { + if (staticThumbDrawable instanceof VectorAvatarThumbDrawable) { + ((VectorAvatarThumbDrawable) staticThumbDrawable).setParent(this); + } drawDrawable(canvas, staticThumbDrawable, (int) (overrideAlpha * 255), null, thumbOrientation, backgroundThreadDrawHolder); checkAlphaAnimation(animationNotReady, backgroundThreadDrawHolder); result = true; @@ -2134,7 +2188,7 @@ public boolean hasImageLoaded() { } public boolean hasNotThumb() { - return currentImageDrawable != null || currentMediaDrawable != null; + return currentImageDrawable != null || currentMediaDrawable != null || staticThumbDrawable instanceof VectorAvatarThumbDrawable; } public boolean hasStaticThumb() { @@ -2872,7 +2926,7 @@ public void startCrossfadeFromStaticThumb(Drawable thumb) { currentThumbDrawable = null; thumbShader = null; roundPaint.setShader(null); - staticThumbDrawable = thumb; + setStaticDrawable(thumb); crossfadeWithThumb = true; currentAlpha = 0f; updateDrawableRadius(staticThumbDrawable); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java index 75decfcfafe..2c444dc42e2 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java @@ -442,7 +442,7 @@ public LocaleInfo getLanguageFromDict(String key) { public LocaleInfo getBuiltinLanguageByPlural(String plural) { Collection values = languagesDict.values(); for (LocaleInfo l : values) - if (l.pathToFile != null && l.pathToFile.equals("remote") && l.pluralLangCode != null && l.pluralLangCode.equals(plural)) + if (l.pathToFile != null && l.pathToFile.equals("remote") && !"en_raw".equals(l.shortName) && l.pluralLangCode != null && l.pluralLangCode.equals(plural)) return l; return null; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java index cacf807c91d..c6bee01153e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java @@ -352,6 +352,7 @@ public static class PhotoEntry extends MediaEditState { public boolean isChatPreviewSpoilerRevealed; public boolean isAttachSpoilerRevealed; + public TLRPC.VideoSize emojiMarkup; public PhotoEntry(int bucketId, int imageId, long dateTaken, String path, int orientation, boolean isVideo, int width, int height, long size) { this.bucketId = bucketId; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java index 4c8c272381c..5b060af5ab9 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java @@ -44,6 +44,8 @@ import androidx.core.content.pm.ShortcutManagerCompat; import androidx.core.graphics.drawable.IconCompat; +import com.android.billingclient.api.ProductDetails; + import org.telegram.SQLite.SQLiteCursor; import org.telegram.SQLite.SQLiteDatabase; import org.telegram.SQLite.SQLiteException; @@ -71,6 +73,7 @@ import org.telegram.ui.Components.URLSpanReplacement; import org.telegram.ui.Components.URLSpanUserMention; import org.telegram.ui.LaunchActivity; +import org.telegram.ui.PremiumPreviewFragment; import java.io.File; import java.util.ArrayList; @@ -177,6 +180,8 @@ public MediaDataController(int num) { loadStickersByEmojiOrName(AndroidUtilities.STICKERS_PLACEHOLDER_PACK_NAME, false, true); loadEmojiThemes(); loadRecentAndTopReactions(false); + loadAvatarConstructor(false); + loadAvatarConstructor(true); ringtoneDataStore = new RingtoneDataStore(currentAccount); } @@ -386,6 +391,70 @@ public TLRPC.TL_help_premiumPromo getPremiumPromo() { return premiumPromo; } + public Integer getPremiumHintAnnualDiscount(boolean checkTransaction) { + if (checkTransaction && (!BillingController.getInstance().isReady() || BillingController.getInstance().getLastPremiumTransaction() == null) || premiumPromo == null) { + return null; + } + + boolean found = false; + int discount = 0; + double currentPrice = 0; + for (TLRPC.TL_premiumSubscriptionOption option : premiumPromo.period_options) { + if (checkTransaction ? option.current && Objects.equals(option.transaction.replaceAll(PremiumPreviewFragment.TRANSACTION_PATTERN, "$1"), BillingController.getInstance().getLastPremiumTransaction()) : option.months == 1) { + found = true; + + if (!BuildVars.useInvoiceBilling() && BillingController.PREMIUM_PRODUCT_DETAILS != null) { + ProductDetails.SubscriptionOfferDetails offerDetails = null; + for (ProductDetails.SubscriptionOfferDetails details : BillingController.PREMIUM_PRODUCT_DETAILS.getSubscriptionOfferDetails()) { + String period = details.getPricingPhases().getPricingPhaseList().get(0).getBillingPeriod(); + if (option.months == 12 ? period.equals("P1Y") : period.equals(String.format(Locale.ROOT, "P%dM", option.months))) { + offerDetails = details; + break; + } + } + + if (offerDetails == null) { + currentPrice = (double) option.amount / option.months; + } else { + currentPrice = (double) offerDetails.getPricingPhases().getPricingPhaseList().get(0).getPriceAmountMicros() / option.months; + } + } else { + currentPrice = (double) option.amount / option.months; + } + } + } + for (TLRPC.TL_premiumSubscriptionOption option : premiumPromo.period_options) { + if (found && option.months == 12) { + double amount; + if (!BuildVars.useInvoiceBilling() && BillingController.PREMIUM_PRODUCT_DETAILS != null) { + ProductDetails.SubscriptionOfferDetails offerDetails = null; + for (ProductDetails.SubscriptionOfferDetails details : BillingController.PREMIUM_PRODUCT_DETAILS.getSubscriptionOfferDetails()) { + String period = details.getPricingPhases().getPricingPhaseList().get(0).getBillingPeriod(); + if (option.months == 12 ? period.equals("P1Y") : period.equals(String.format(Locale.ROOT, "P%dM", option.months))) { + offerDetails = details; + break; + } + } + + if (offerDetails == null) { + amount = (double) option.amount / option.months; + } else { + amount = (double) offerDetails.getPricingPhases().getPricingPhaseList().get(0).getPriceAmountMicros() / option.months; + } + } else { + amount = (double) option.amount / option.months; + } + + discount = (int) ((1.0 - amount / currentPrice) * 100); + } + } + if (!found || discount <= 0) { + return null; + } + + return discount; + } + public TLRPC.TL_attachMenuBots getAttachMenuBots() { return attachMenuBots; } @@ -1109,7 +1178,7 @@ public TLRPC.TL_messages_stickerSet getStickerSet(TLRPC.InputStickerSet inputSti } return cacheSet; } - if (inputStickerSet instanceof TLRPC.TL_inputStickerSetID && hash != null) { + if (inputStickerSet instanceof TLRPC.TL_inputStickerSetID) { getMessagesStorage().getStorageQueue().postRunnable(() -> { TLRPC.TL_messages_stickerSet cachedSet = getCachedStickerSetInternal(inputStickerSet.id, hash); AndroidUtilities.runOnUIThread(() -> { @@ -1191,7 +1260,7 @@ private TLRPC.TL_messages_stickerSet getCachedStickerSetInternal(long id, Intege if (data != null) { set = TLRPC.TL_messages_stickerSet.TLdeserialize(data, data.readInt32(false), false); int cachedHash = cursor.intValue(1); - if (hash != null && hash != cachedHash) { + if (hash != null && hash != 0 && hash != cachedHash) { return null; } } @@ -3715,12 +3784,14 @@ public static int getMediaType(TLRPC.Message message) { boolean isAnimated = false; boolean isVideo = false; boolean isVoice = false; + boolean isRound = false; boolean isMusic = false; boolean isSticker = false; for (int a = 0; a < document.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeVideo) { + isRound = attribute.round_message; isVoice = attribute.round_message; isVideo = !attribute.round_message; } else if (attribute instanceof TLRPC.TL_documentAttributeAnimated) { @@ -3732,7 +3803,7 @@ public static int getMediaType(TLRPC.Message message) { isSticker = true; } } - if (isVoice) { + if (isVoice || isRound) { return MEDIA_AUDIO; } else if (isVideo && !isAnimated && !isSticker) { return MEDIA_PHOTOVIDEO; @@ -3801,12 +3872,29 @@ private void processLoadedMedia(TLRPC.messages_Messages res, long dialogId, int } getFileLoader().checkMediaExistance(objects); - AndroidUtilities.runOnUIThread(() -> { - int totalCount = res.count; - getMessagesController().putUsers(res.users, fromCache != 0); - getMessagesController().putChats(res.chats, fromCache != 0); - getNotificationCenter().postNotificationName(NotificationCenter.mediaDidLoad, dialogId, totalCount, objects, classGuid, type, topReached, min_id != 0, requestIndex); - }); + Runnable notify = () -> { + AndroidUtilities.runOnUIThread(() -> { + int totalCount = res.count; + getMessagesController().putUsers(res.users, fromCache != 0); + getMessagesController().putChats(res.chats, fromCache != 0); + getNotificationCenter().postNotificationName(NotificationCenter.mediaDidLoad, dialogId, totalCount, objects, classGuid, type, topReached, min_id != 0, requestIndex); + }); + }; + + if (getMessagesController().getTranslateController().isFeatureAvailable()) { + getMessagesStorage().getStorageQueue().postRunnable(() -> { + for (int i = 0; i < objects.size(); ++i) { + MessageObject messageObject = objects.get(i); + TLRPC.Message message = getMessagesStorage().getMessageWithCustomParamsOnlyInternal(messageObject.getId(), messageObject.getDialogId()); + messageObject.messageOwner.translatedToLanguage = message.translatedToLanguage; + messageObject.messageOwner.translatedText = message.translatedText; + messageObject.updateTranslation(); + } + notify.run(); + }); + } else { + notify.run(); + } }); } } @@ -7071,14 +7159,14 @@ public void getAnimatedEmojiByKeywords(String query, Utilities.Callback ranges = Emoji.parseEmojis(keyword, emojiOnly); + if (emojiOnly[0] > 0) { + for (int i = 0; i < ranges.size(); ++i) { + String code = ranges.get(i).code.toString(); + boolean foundDuplicate = false; + for (int j = 0; j < result.size(); ++j) { + if (TextUtils.equals(result.get(j).emoji, code)) { + foundDuplicate = true; + break; + } + } + if (!foundDuplicate) { + KeywordResult keywordResult = new KeywordResult(); + keywordResult.emoji = code; + keywordResult.keyword = ""; + result.add(keywordResult); + } + } + } + } + String key = keyword.toLowerCase(); for (int a = 0; a < 2; a++) { if (a == 1) { @@ -7734,4 +7845,60 @@ public static ArrayList loadReactionsFromPref(SharedPreferences } return objects; } + + public TLRPC.TL_emojiList profileAvatarConstructorDefault; + public TLRPC.TL_emojiList groupAvatarConstructorDefault; + + private void loadAvatarConstructor(boolean profile) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("avatar_constructor" + currentAccount, Context.MODE_PRIVATE); + String value; + long lastCheckTime; + if (profile) { + value = preferences.getString("profile", null); + lastCheckTime = preferences.getLong("profile_last_check", 0); + } else { + value = preferences.getString("group", null); + lastCheckTime = preferences.getLong("group_last_check", 0); + } + + + TLRPC.TL_emojiList emojiList = null; + if (value != null) { + SerializedData serializedData = new SerializedData(Utilities.hexToBytes(value)); + try { + emojiList = (TLRPC.TL_emojiList) TLRPC.TL_emojiList.TLdeserialize(serializedData, serializedData.readInt32(true), true); + if (profile) { + profileAvatarConstructorDefault = emojiList; + } else { + groupAvatarConstructorDefault = emojiList; + } + } catch (Throwable e) { + FileLog.e(e); + } + } + + if (emojiList == null || (System.currentTimeMillis() - lastCheckTime) > 24 * 60 * 60 * 1000 || BuildVars.DEBUG_PRIVATE_VERSION) { + TLRPC.TL_account_getDefaultProfilePhotoEmojis req = new TLRPC.TL_account_getDefaultProfilePhotoEmojis(); + if (emojiList != null) { + req.hash = emojiList.hash; + } + getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (response instanceof TLRPC.TL_emojiList) { + SerializedData data = new SerializedData(response.getObjectSize()); + response.serializeToStream(data); + SharedPreferences.Editor editor = preferences.edit(); + if (profile) { + profileAvatarConstructorDefault = (TLRPC.TL_emojiList) response; + editor.putString("profile", Utilities.bytesToHex(data.toByteArray())); + editor.putLong("profile_last_check", System.currentTimeMillis()); + } else { + groupAvatarConstructorDefault = (TLRPC.TL_emojiList) response; + editor.putString("group", Utilities.bytesToHex(data.toByteArray())); + editor.putLong("group_last_check", System.currentTimeMillis()); + } + editor.apply(); + } + })); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageCustomParamsHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageCustomParamsHelper.java index 44f57a0fbff..8077a925f1b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageCustomParamsHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageCustomParamsHelper.java @@ -14,7 +14,10 @@ public static boolean isEmpty(TLRPC.Message message) { !message.voiceTranscriptionRated && !message.voiceTranscriptionForce && message.voiceTranscriptionId == 0 && - !message.premiumEffectWasPlayed; + !message.premiumEffectWasPlayed && + message.originalLanguage == null && + message.translatedToLanguage == null && + message.translatedText == null; } public static void copyParams(TLRPC.Message fromMessage, TLRPC.Message toMessage) { @@ -25,6 +28,9 @@ public static void copyParams(TLRPC.Message fromMessage, TLRPC.Message toMessage toMessage.voiceTranscriptionRated = fromMessage.voiceTranscriptionRated; toMessage.voiceTranscriptionId = fromMessage.voiceTranscriptionId; toMessage.premiumEffectWasPlayed = fromMessage.premiumEffectWasPlayed; + toMessage.originalLanguage = fromMessage.originalLanguage; + toMessage.translatedToLanguage = fromMessage.translatedToLanguage; + toMessage.translatedText = fromMessage.translatedText; } @@ -69,6 +75,10 @@ private Params_v1(TLRPC.Message message) { this.message = message; flags += message.voiceTranscription != null ? 1 : 0; flags += message.voiceTranscriptionForce ? 2 : 0; + + flags += message.originalLanguage != null ? 4 : 0; + flags += message.translatedToLanguage != null ? 8 : 0; + flags += message.translatedText != null ? 16 : 0; } @Override @@ -85,6 +95,16 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt64(message.voiceTranscriptionId); stream.writeBool(message.premiumEffectWasPlayed); + + if ((flags & 4) != 0) { + stream.writeString(message.originalLanguage); + } + if ((flags & 8) != 0) { + stream.writeString(message.translatedToLanguage); + } + if ((flags & 16) != 0) { + message.translatedText.serializeToStream(stream); + } } @Override @@ -100,6 +120,16 @@ public void readParams(AbstractSerializedData stream, boolean exception) { message.voiceTranscriptionId = stream.readInt64(exception); message.premiumEffectWasPlayed = stream.readBool(exception); + + if ((flags & 4) != 0) { + message.originalLanguage = stream.readString(exception); + } + if ((flags & 8) != 0) { + message.translatedToLanguage = stream.readString(exception); + } + if ((flags & 16) != 0) { + message.translatedText = TLRPC.TL_textWithEntities.TLdeserialize(stream, stream.readInt32(exception), exception); + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java index c3cbaf84444..f9197e24a88 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -56,6 +56,7 @@ import org.telegram.ui.Components.URLSpanReplacement; import org.telegram.ui.Components.URLSpanUserMention; import org.telegram.ui.Components.spoilers.SpoilerEffect; +import org.w3c.dom.Text; import java.io.BufferedReader; import java.io.File; @@ -114,6 +115,7 @@ public class MessageObject { public Long emojiAnimatedStickerId; public boolean isTopicMainMessage; public boolean settingAvatar; + public TLRPC.VideoSize emojiMarkup; private boolean emojiAnimatedStickerLoading; public String emojiAnimatedStickerColor; public CharSequence messageText; @@ -222,7 +224,6 @@ public class MessageObject { public int textHeight; public boolean hasRtl; public float textXOffset; - public int linesCount; public SendAnimationData sendAnimationData; @@ -1170,6 +1171,7 @@ public MessageObject(int accountNum, TLRPC.Message message, MessageObject replyT updateMessageText(users, chats, sUsers, sChats); setType(); + updateTranslation(false); measureInlineBotButtons(); Calendar rightNow = new GregorianCalendar(); @@ -1191,7 +1193,7 @@ public MessageObject(int accountNum, TLRPC.Message message, MessageObject replyT } int[] emojiOnly = allowsBigEmoji() ? new int[1] : null; messageText = Emoji.replaceEmoji(messageText, paint.getFontMetricsInt(), AndroidUtilities.dp(20), false, emojiOnly); - messageText = replaceAnimatedEmoji(messageText, messageOwner.entities, paint.getFontMetricsInt()); + messageText = replaceAnimatedEmoji(messageText, paint.getFontMetricsInt()); if (emojiOnly != null && emojiOnly[0] > 1) { replaceEmojiToLottieFrame(messageText, emojiOnly); } @@ -2415,7 +2417,7 @@ public MessageObject(int accountNum, TLRPC.TL_channelAdminLogEvent event, ArrayL int[] emojiOnly = allowsBigEmoji() ? new int[1] : null; messageText = Emoji.replaceEmoji(messageText, paint.getFontMetricsInt(), AndroidUtilities.dp(20), false, emojiOnly); - messageText = replaceAnimatedEmoji(messageText, messageOwner.entities, paint.getFontMetricsInt()); + messageText = replaceAnimatedEmoji(messageText, paint.getFontMetricsInt()); if (emojiOnly != null && emojiOnly[0] > 1) { replaceEmojiToLottieFrame(messageText, emojiOnly); } @@ -2511,7 +2513,38 @@ private String getUserName(TLObject object, ArrayList entit return name; } + public boolean updateTranslation() { + return updateTranslation(true); + } + + public boolean translated = false; + public boolean updateTranslation(boolean force) { + boolean replyUpdated = replyMessageObject != null && replyMessageObject.updateTranslation(force); + if ( + TranslateController.isTranslatable(this) && + MessagesController.getInstance(currentAccount).getTranslateController().isTranslatingDialog(getDialogId()) && + messageOwner != null && + messageOwner.translatedText != null && + TextUtils.equals(MessagesController.getInstance(currentAccount).getTranslateController().getDialogTranslateTo(getDialogId()), messageOwner.translatedToLanguage) + ) { + if (translated) { + return replyUpdated || false; + } + translated = true; + applyNewText(messageOwner.translatedText.text); + generateCaption(); + return replyUpdated || true; + } else if (messageOwner != null && (force || translated)) { + translated = false; + applyNewText(messageOwner.message); + generateCaption(); + return replyUpdated || true; + } + return replyUpdated || false; + } + public void applyNewText() { + translated = false; applyNewText(messageOwner.message); } @@ -2524,6 +2557,7 @@ public void applyNewText(CharSequence text) { fromUser = MessagesController.getInstance(currentAccount).getUser(messageOwner.from_id.user_id); } messageText = text; + ArrayList entities = translated && messageOwner.translatedText != null ? messageOwner.translatedText.entities : messageOwner.entities; TextPaint paint; if (getMedia(messageOwner) instanceof TLRPC.TL_messageMediaGame) { paint = Theme.chat_msgGameTextPaint; @@ -2532,7 +2566,7 @@ public void applyNewText(CharSequence text) { } int[] emojiOnly = allowsBigEmoji() ? new int[1] : null; messageText = Emoji.replaceEmoji(messageText, paint.getFontMetricsInt(), AndroidUtilities.dp(20), false, emojiOnly); - messageText = replaceAnimatedEmoji(messageText, messageOwner.entities, paint.getFontMetricsInt()); + messageText = replaceAnimatedEmoji(messageText, entities, paint.getFontMetricsInt()); if (emojiOnly != null && emojiOnly[0] > 1) { replaceEmojiToLottieFrame(messageText, emojiOnly); } @@ -2668,7 +2702,7 @@ public void generatePinMessageText(TLRPC.User fromUser, TLRPC.Chat chat) { } mess = Emoji.replaceEmoji(mess, Theme.chat_msgTextPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); if (replyMessageObject != null && replyMessageObject.messageOwner != null) { - mess = replaceAnimatedEmoji(mess, replyMessageObject.messageOwner.entities, Theme.chat_msgTextPaint.getFontMetricsInt()); + mess = replyMessageObject.replaceAnimatedEmoji(mess, Theme.chat_msgTextPaint.getFontMetricsInt()); } MediaDataController.addTextStyleRuns(replyMessageObject, (Spannable) mess); if (ellipsize) { @@ -3375,6 +3409,41 @@ private void updateMessageText(AbstractMap users, AbstractMap< } } else if (messageOwner.action instanceof TLRPC.TL_messageActionAttachMenuBotAllowed) { messageText = LocaleController.getString(R.string.ActionAttachMenuBotAllowed); + } else if (messageOwner.action instanceof TLRPC.TL_messageActionRequestedPeer) { + TLRPC.Peer peer = ((TLRPC.TL_messageActionRequestedPeer) messageOwner.action).peer; + TLObject peerObject = null; + if (peer instanceof TLRPC.TL_peerUser) { + peerObject = MessagesController.getInstance(currentAccount).getUser(peer.user_id); + if (peerObject == null) { + peerObject = getUser(users, sUsers, peer.user_id); + } + } else if (peer instanceof TLRPC.TL_peerChat) { + peerObject = MessagesController.getInstance(currentAccount).getChat(peer.chat_id); + if (peerObject == null) { + peerObject = getChat(chats, sChats, peer.chat_id); + } + } else if (peer instanceof TLRPC.TL_peerChannel) { + peerObject = MessagesController.getInstance(currentAccount).getChat(peer.channel_id); + if (peerObject == null) { + peerObject = getChat(chats, sChats, peer.channel_id); + } + } + TLRPC.User bot = MessagesController.getInstance(currentAccount).getUser(getDialogId()); + if (bot == null) { + bot = getUser(users, sUsers, getDialogId()); + } + if (peerObject == null) { + if (peer instanceof TLRPC.TL_peerUser) { + messageText = LocaleController.getString(R.string.ActionRequestedPeerUser); + } else if (peer instanceof TLRPC.TL_peerChat) { + messageText = LocaleController.getString(R.string.ActionRequestedPeerChat); + } else { + messageText = LocaleController.getString(R.string.ActionRequestedPeerChannel); + } + } else { + messageText = replaceWithLink(LocaleController.getString(R.string.ActionRequestedPeer), "un1", peerObject); + } + messageText = replaceWithLink(messageText, "un2", bot); } else if (messageOwner.action instanceof TLRPC.TL_messageActionSetMessagesTTL) { TLRPC.TL_messageActionSetMessagesTTL action = (TLRPC.TL_messageActionSetMessagesTTL) messageOwner.action; TLRPC.Chat chat = messageOwner.peer_id != null && messageOwner.peer_id.channel_id != 0 ? getChat(chats, sChats, messageOwner.peer_id.channel_id) : null; @@ -3824,7 +3893,7 @@ public void setType() { } else { type = TYPE_ANIMATED_STICKER; } - } else if (!isDice() && emojiOnlyCount >= 1 && !hasUnwrappedEmoji) { + } else if (isMediaEmpty() && !isDice() && emojiOnlyCount >= 1 && !hasUnwrappedEmoji) { type = TYPE_EMOJIS; } else if (isMediaEmpty()) { type = TYPE_TEXT; @@ -3951,7 +4020,7 @@ public boolean checkLayout() { } int[] emojiOnly = allowsBigEmoji() ? new int[1] : null; messageText = Emoji.replaceEmoji(messageText, paint.getFontMetricsInt(), AndroidUtilities.dp(20), false, emojiOnly); - messageText = replaceAnimatedEmoji(messageText, messageOwner.entities, paint.getFontMetricsInt()); + messageText = replaceAnimatedEmoji(messageText, paint.getFontMetricsInt()); if (emojiOnly != null && emojiOnly[0] > 1) { replaceEmojiToLottieFrame(messageText, emojiOnly); } @@ -4546,22 +4615,30 @@ public boolean isVoiceTranscriptionOpen() { ); } + private boolean captionTranslated; + public void generateCaption() { - if (caption != null || isRoundVideo()) { + if (caption != null && translated == captionTranslated || isRoundVideo()) { return; } + String text = messageOwner.message; + ArrayList entities = messageOwner.entities; if (hasExtendedMedia()) { - messageOwner.message = messageOwner.media.description; + text = messageOwner.message = messageOwner.media.description; + } + if (captionTranslated = translated) { + text = messageOwner.translatedText.text; + entities = messageOwner.translatedText.entities; } - if (!isMediaEmpty() && !(getMedia(messageOwner) instanceof TLRPC.TL_messageMediaGame) && !TextUtils.isEmpty(messageOwner.message)) { - caption = Emoji.replaceEmoji(messageOwner.message, Theme.chat_msgTextPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); - caption = replaceAnimatedEmoji(caption, messageOwner.entities, Theme.chat_msgTextPaint.getFontMetricsInt()); + if (!isMediaEmpty() && !(getMedia(messageOwner) instanceof TLRPC.TL_messageMediaGame) && !TextUtils.isEmpty(text)) { + caption = Emoji.replaceEmoji(text, Theme.chat_msgTextPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); + caption = replaceAnimatedEmoji(caption, Theme.chat_msgTextPaint.getFontMetricsInt()); boolean hasEntities; if (messageOwner.send_state != MESSAGE_SEND_STATE_SENT) { hasEntities = false; } else { - hasEntities = !messageOwner.entities.isEmpty(); + hasEntities = !entities.isEmpty(); } boolean useManualParse = !hasEntities && ( @@ -4819,7 +4896,17 @@ public boolean addEntitiesToText(CharSequence text, boolean photoViewer, boolean entities.add(entityItalic); return addEntitiesToText(text, entities, isOutOwner(), true, photoViewer, useManualParse); } else { - return addEntitiesToText(text, messageOwner.entities, isOutOwner(), true, photoViewer, useManualParse); + ArrayList entities; + if (translated) { + if (messageOwner.translatedText == null) { + entities = null; + } else { + entities = messageOwner.translatedText.entities; + } + } else { + entities = messageOwner.entities; + } + return addEntitiesToText(text, entities, isOutOwner(), true, photoViewer, useManualParse); } } @@ -4847,6 +4934,11 @@ public void replaceEmojiToLottieFrame(CharSequence text, int[] emojiOnly) { } } + public Spannable replaceAnimatedEmoji(CharSequence text, Paint.FontMetricsInt fontMetricsInt) { + ArrayList entities = translated && messageOwner.translatedText != null ? messageOwner.translatedText.entities : messageOwner.entities; + return replaceAnimatedEmoji(text, entities, fontMetricsInt, false); + } + public static Spannable replaceAnimatedEmoji(CharSequence text, ArrayList entities, Paint.FontMetricsInt fontMetricsInt) { return replaceAnimatedEmoji(text, entities, fontMetricsInt, false); } @@ -4866,8 +4958,7 @@ public static Spannable replaceAnimatedEmoji(CharSequence text, ArrayList 0; - if (entities.isEmpty()) { + if (entities == null || entities.isEmpty()) { return hasUrls; } @@ -5224,11 +5315,13 @@ public void generateLayout(TLRPC.User fromUser) { textLayoutBlocks = new ArrayList<>(); textWidth = 0; + ArrayList entities = translated && messageOwner.translatedText != null ? messageOwner.translatedText.entities : messageOwner.entities; + boolean hasEntities; if (messageOwner.send_state != MESSAGE_SEND_STATE_SENT) { hasEntities = false; } else { - hasEntities = !messageOwner.entities.isEmpty(); + hasEntities = !entities.isEmpty(); } boolean useManualParse = !hasEntities && ( @@ -5305,7 +5398,7 @@ public void generateLayout(TLRPC.User fromUser) { } textHeight = textLayout.getHeight(); - linesCount = textLayout.getLineCount(); + int linesCount = textLayout.getLineCount(); int linesPreBlock = totalAnimatedEmojiCount >= 50 ? LINES_PER_BLOCK_WITH_EMOJI : LINES_PER_BLOCK; int blocksCount; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index 5606cce5fb1..3c04a5a1cb6 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -26,6 +26,7 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Base64; +import android.util.Log; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; @@ -401,6 +402,8 @@ public class MessagesController extends BaseController implements NotificationCe private LongSparseArray emojiStatusUntilValues = new LongSparseArray<>(); private TopicsController topicsController; private CacheByChatsController cacheByChatsController; + private TranslateController translateController; + public boolean uploadMarkupVideo; public void getNextReactionMention(long dialogId, int topicId, int count, Consumer callback) { final MessagesStorage messagesStorage = getMessagesStorage(); @@ -590,6 +593,10 @@ public TopicsController getTopicsController() { return topicsController; } + public TranslateController getTranslateController() { + return translateController; + } + public boolean isForum(long dialogId) { TLRPC.Chat chatLocal = getChat(-dialogId); return chatLocal != null && chatLocal.forum; @@ -1008,6 +1015,10 @@ public static MessagesController getInstance(int num) { return localInstance; } + public SharedPreferences getMainSettings() { + return mainPreferences; + } + public static SharedPreferences getNotificationsSettings(int account) { return getInstance(account).notificationsPreferences; } @@ -1152,6 +1163,7 @@ public MessagesController(int num) { telegramAntispamUserId = mainPreferences.getLong("telegramAntispamUserId", -1); telegramAntispamGroupSizeMin = mainPreferences.getInt("telegramAntispamGroupSizeMin", 100); hiddenMembersGroupSizeMin = mainPreferences.getInt("hiddenMembersGroupSizeMin", 100); + uploadMarkupVideo = mainPreferences.getBoolean("uploadMarkupVideo", true); BuildVars.GOOGLE_AUTH_CLIENT_ID = mainPreferences.getString("googleAuthClientId", BuildVars.GOOGLE_AUTH_CLIENT_ID); Set currencySet = mainPreferences.getStringSet("directPaymentsCurrency", null); @@ -1290,6 +1302,7 @@ public MessagesController(int num) { topicsController = new TopicsController(num); cacheByChatsController = new CacheByChatsController(num); + translateController = new TranslateController(this); } @@ -1598,6 +1611,7 @@ protected void processLoadedDialogFilters(ArrayList filters, TLRPC } } } + getTranslateController().checkDialogMessages(key); } else { currentDialog.pinned = newDialog.pinned; currentDialog.pinnedNum = newDialog.pinnedNum; @@ -1645,6 +1659,7 @@ protected void processLoadedDialogFilters(ArrayList filters, TLRPC } } } + getTranslateController().checkDialogMessages(key); } } else { // if (newMsg == null || newMsg.messageOwner.date > oldMsg.messageOwner.date) { @@ -1682,6 +1697,7 @@ protected void processLoadedDialogFilters(ArrayList filters, TLRPC } } } + getTranslateController().checkDialogMessages(key); } } } @@ -1802,13 +1818,29 @@ public void addFilter(DialogFilter filter, boolean atBegin) { lockFiltersInternal(); } + public void updateEmojiStatus(TLRPC.EmojiStatus newStatus) { + TLRPC.TL_account_updateEmojiStatus req = new TLRPC.TL_account_updateEmojiStatus(); + req.emoji_status = newStatus; + TLRPC.User user = getUserConfig().getCurrentUser(); + if (user != null) { + user.emoji_status = req.emoji_status; + getNotificationCenter().postNotificationName(NotificationCenter.userEmojiStatusUpdated, user); + getMessagesController().updateEmojiStatusUntilUpdate(user.id, user.emoji_status); + } + getConnectionsManager().sendRequest(req, (res, err) -> { + if (!(res instanceof TLRPC.TL_boolTrue)) { + // TODO: reject + } + }); + } + public void removeFilter(DialogFilter filter) { dialogFilters.remove(filter); dialogFiltersById.remove(filter.id); getNotificationCenter().postNotificationName(NotificationCenter.dialogFiltersUpdated); } - private void loadAppConfig() { + public void loadAppConfig() { if (loadingAppConfig) { return; } @@ -1824,6 +1856,16 @@ private void loadAppConfig() { for (int a = 0, N = object.value.size(); a < N; a++) { TLRPC.TL_jsonObjectValue value = object.value.get(a); switch (value.key) { + case "upload_markup_video": { + if (value.value instanceof TLRPC.TL_jsonBool) { + if (uploadMarkupVideo != ((TLRPC.TL_jsonBool) value.value).value) { + uploadMarkupVideo = ((TLRPC.TL_jsonBool) value.value).value; + editor.putBoolean("uploadMarkupVideo", uploadMarkupVideo); + changed = true; + } + } + break; + } case "login_google_oauth_client_id": { if (value.value instanceof TLRPC.TL_jsonString) { String str = ((TLRPC.TL_jsonString) value.value).value; @@ -3450,6 +3492,7 @@ public void cleanup() { getLocationController().cleanup(); getMediaDataController().cleanup(); getColorPalette().cleanup(); + getTranslateController().cleanup(); showFiltersTooltip = false; @@ -4433,6 +4476,7 @@ public void loadFullChat(long chatId, int classGuid, boolean force) { res.full_chat.inviterId = old.inviterId; } fullChats.put(chatId, res.full_chat); + getTranslateController().updateDialogFull(-chatId); applyDialogNotificationsSettings(-chatId, 0, res.full_chat.notify_settings); for (int a = 0; a < res.full_chat.bot_info.size(); a++) { @@ -4530,6 +4574,7 @@ public void loadFullUser(final TLRPC.User user, int classGuid, boolean force) { } } fullUsers.put(user.id, userFull); + getTranslateController().updateDialogFull(user.id); loadingFullUsers.remove(user.id); loadedFullUsers.put(user.id, System.currentTimeMillis()); String names = user.first_name + user.last_name + UserObject.getPublicUsername(user); @@ -5269,7 +5314,7 @@ public void deleteUserPhoto(TLRPC.InputPhoto photo) { if (photo == null) { TLRPC.TL_photos_updateProfilePhoto req = new TLRPC.TL_photos_updateProfilePhoto(); req.id = new TLRPC.TL_inputPhotoEmpty(); - getUserConfig().getCurrentUser().photo = new TLRPC.TL_userProfilePhotoEmpty(); + // getUserConfig().getCurrentUser().photo = new TLRPC.TL_userProfilePhotoEmpty(); TLRPC.User user = getUser(getUserConfig().getClientUserId()); if (user == null) { user = getUserConfig().getCurrentUser(); @@ -5277,39 +5322,49 @@ public void deleteUserPhoto(TLRPC.InputPhoto photo) { if (user == null) { return; } - user.photo = getUserConfig().getCurrentUser().photo; + getMessagesStorage().clearUserPhoto(user.id, user.photo.photo_id); + // user.photo = getUserConfig().getCurrentUser().photo; getNotificationCenter().postNotificationName(NotificationCenter.mainUserInfoChanged); getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_ALL); + getConnectionsManager().sendRequest(req, (response, error) -> { if (error == null) { - TLRPC.TL_photos_photo photos_photo = (TLRPC.TL_photos_photo) response; - TLRPC.User user1 = getUser(getUserConfig().getClientUserId()); - if (user1 == null) { - user1 = getUserConfig().getCurrentUser(); - putUser(user1, false); - } else { - getUserConfig().setCurrentUser(user1); - } - if (user1 == null) { - return; - } - getMessagesStorage().clearUserPhotos(user1.id); - ArrayList users = new ArrayList<>(); - users.add(user1); - getMessagesStorage().putUsersAndChats(users, null, false, true); - if (photos_photo.photo instanceof TLRPC.TL_photo) { - user1.photo = new TLRPC.TL_userProfilePhoto(); - user1.photo.has_video = !photos_photo.photo.video_sizes.isEmpty(); - user1.photo.photo_id = photos_photo.photo.id; - user1.photo.photo_small = FileLoader.getClosestPhotoSizeWithSize(photos_photo.photo.sizes, 150).location; - user1.photo.photo_big = FileLoader.getClosestPhotoSizeWithSize(photos_photo.photo.sizes, 800).location; - user1.photo.dc_id = photos_photo.photo.dc_id; - } else { - user1.photo = new TLRPC.TL_userProfilePhotoEmpty(); - } AndroidUtilities.runOnUIThread(() -> { + TLRPC.TL_photos_photo photos_photo = (TLRPC.TL_photos_photo) response; + TLRPC.User user1 = getUser(getUserConfig().getClientUserId()); + if (user1 == null) { + user1 = getUserConfig().getCurrentUser(); + putUser(user1, false); + } else { + getUserConfig().setCurrentUser(user1); + } + if (user1 == null) { + return; + } + ArrayList users = new ArrayList<>(); + users.add(user1); + getMessagesStorage().putUsersAndChats(users, null, false, true); + if (photos_photo.photo instanceof TLRPC.TL_photo) { + user1.photo = new TLRPC.TL_userProfilePhoto(); + user1.photo.has_video = !photos_photo.photo.video_sizes.isEmpty(); + user1.photo.photo_id = photos_photo.photo.id; + user1.photo.photo_small = FileLoader.getClosestPhotoSizeWithSize(photos_photo.photo.sizes, 150).location; + user1.photo.photo_big = FileLoader.getClosestPhotoSizeWithSize(photos_photo.photo.sizes, 800).location; + user1.photo.dc_id = photos_photo.photo.dc_id; + } else { + user1.photo = new TLRPC.TL_userProfilePhotoEmpty(); + } + + TLRPC.UserFull userFull = getUserFull(getUserConfig().getClientUserId()); + userFull.profile_photo = photos_photo.photo; + getMessagesStorage().updateUserInfo(userFull, false); + + getUserConfig().getCurrentUser().photo = user1.photo; + putUser(user1, false); + getNotificationCenter().postNotificationName(NotificationCenter.mainUserInfoChanged); getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_ALL); + getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_AVATAR); getUserConfig().saveConfig(true); }); } @@ -6336,6 +6391,7 @@ public void loadChannelParticipants(Long chatId) { public void putChatFull(TLRPC.ChatFull chatFull) { fullChats.put(chatFull.id, chatFull); + getTranslateController().updateDialogFull(-chatFull.id); } public void processChatInfo(long chatId, TLRPC.ChatFull info, ArrayList usersArr, boolean fromCache, boolean force, boolean byChannelUsers, ArrayList pinnedMessages, HashMap pinnedMessagesMap, int totalPinnedCount, boolean pinnedEndReached) { @@ -6349,6 +6405,7 @@ public void processChatInfo(long chatId, TLRPC.ChatFull info, ArrayList 0 || isEncryptedChat || arr.size() == 1) { PrintingUser pu = arr.get(0); TLRPC.User user = getUser(pu.userId); if (user == null) { continue; } + final boolean isGroup = key < 0 && !isEncryptedChat; if (pu.action instanceof TLRPC.TL_sendMessageRecordAudioAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsRecordingAudio", R.string.IsRecordingAudio, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsRecordingAudio", R.string.IsRecordingAudio, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("RecordingAudio", R.string.RecordingAudio)); + text = LocaleController.getString("RecordingAudio", R.string.RecordingAudio); } - newPrintingStringsTypes.put(threadId, 1); + type = 1; } else if (pu.action instanceof TLRPC.TL_sendMessageRecordRoundAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsRecordingRound", R.string.IsRecordingRound, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsRecordingRound", R.string.IsRecordingRound, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("RecordingRound", R.string.RecordingRound)); + text = LocaleController.getString("RecordingRound", R.string.RecordingRound); } - newPrintingStringsTypes.put(threadId, 4); + type = 4; } else if (pu.action instanceof TLRPC.TL_sendMessageUploadRoundAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsSendingVideo", R.string.IsSendingVideo, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsSendingVideo", R.string.IsSendingVideo, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("SendingVideoStatus", R.string.SendingVideoStatus)); + text = LocaleController.getString("SendingVideoStatus", R.string.SendingVideoStatus); } - newPrintingStringsTypes.put(threadId, 4); + type = 4; } else if (pu.action instanceof TLRPC.TL_sendMessageUploadAudioAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsSendingAudio", R.string.IsSendingAudio, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsSendingAudio", R.string.IsSendingAudio, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("SendingAudio", R.string.SendingAudio)); + text = LocaleController.getString("SendingAudio", R.string.SendingAudio); } - newPrintingStringsTypes.put(threadId, 2); + type = 2; } else if (pu.action instanceof TLRPC.TL_sendMessageUploadVideoAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsSendingVideo", R.string.IsSendingVideo, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsSendingVideo", R.string.IsSendingVideo, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("SendingVideoStatus", R.string.SendingVideoStatus)); + text = LocaleController.getString("SendingVideoStatus", R.string.SendingVideoStatus); } - newPrintingStringsTypes.put(threadId, 2); + type = 2; } else if (pu.action instanceof TLRPC.TL_sendMessageRecordVideoAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsRecordingVideo", R.string.IsRecordingVideo, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsRecordingVideo", R.string.IsRecordingVideo, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("RecordingVideoStatus", R.string.RecordingVideoStatus)); + text = LocaleController.getString("RecordingVideoStatus", R.string.RecordingVideoStatus); } - newPrintingStringsTypes.put(threadId, 2); + type = 2; } else if (pu.action instanceof TLRPC.TL_sendMessageUploadDocumentAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsSendingFile", R.string.IsSendingFile, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsSendingFile", R.string.IsSendingFile, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("SendingFile", R.string.SendingFile)); + text = LocaleController.getString("SendingFile", R.string.SendingFile); } - newPrintingStringsTypes.put(threadId, 2); + type = 2; } else if (pu.action instanceof TLRPC.TL_sendMessageUploadPhotoAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsSendingPhoto", R.string.IsSendingPhoto, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsSendingPhoto", R.string.IsSendingPhoto, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("SendingPhoto", R.string.SendingPhoto)); + text = LocaleController.getString("SendingPhoto", R.string.SendingPhoto); } - newPrintingStringsTypes.put(threadId, 2); + type = 2; } else if (pu.action instanceof TLRPC.TL_sendMessageGamePlayAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsSendingGame", R.string.IsSendingGame, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsSendingGame", R.string.IsSendingGame, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("SendingGame", R.string.SendingGame)); + text = LocaleController.getString("SendingGame", R.string.SendingGame); } - newPrintingStringsTypes.put(threadId, 3); + type = 3; } else if (pu.action instanceof TLRPC.TL_sendMessageGeoLocationAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsSelectingLocation", R.string.IsSelectingLocation, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsSelectingLocation", R.string.IsSelectingLocation, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("SelectingLocation", R.string.SelectingLocation)); + text = LocaleController.getString("SelectingLocation", R.string.SelectingLocation); } - newPrintingStringsTypes.put(threadId, 0); + type = 0; } else if (pu.action instanceof TLRPC.TL_sendMessageChooseContactAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsSelectingContact", R.string.IsSelectingContact, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsSelectingContact", R.string.IsSelectingContact, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("SelectingContact", R.string.SelectingContact)); + text = LocaleController.getString("SelectingContact", R.string.SelectingContact); } - newPrintingStringsTypes.put(threadId, 0); + type = 0; } else if (pu.action instanceof TLRPC.TL_sendMessageEmojiInteractionSeen) { - String emoji = ((TLRPC.TL_sendMessageEmojiInteractionSeen) pu.action).emoticon; - String printingString; - if (key < 0 && !isEncryptedChat) { - printingString = LocaleController.formatString("IsEnjoyngAnimations", R.string.IsEnjoyngAnimations, getUserNameForTyping(user), emoji); + final String emoji = ((TLRPC.TL_sendMessageEmojiInteractionSeen) pu.action).emoticon; + if (isGroup) { + text = LocaleController.formatString("IsEnjoyngAnimations", R.string.IsEnjoyngAnimations, getUserNameForTyping(user), emoji); } else { - printingString = LocaleController.formatString("EnjoyngAnimations", R.string.EnjoyngAnimations, emoji); + text = LocaleController.formatString("EnjoyngAnimations", R.string.EnjoyngAnimations, emoji); } - newPrintingStrings.put(threadId, printingString); - newPrintingStringsTypes.put(threadId, 5); + type = 5; } else if (pu.action instanceof TLRPC.TL_sendMessageChooseStickerAction) { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsChoosingSticker", R.string.IsChoosingSticker, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsChoosingSticker", R.string.IsChoosingSticker, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("ChoosingSticker", R.string.ChoosingSticker)); + text = LocaleController.getString("ChoosingSticker", R.string.ChoosingSticker); } - newPrintingStringsTypes.put(threadId, 5); + type = 5; } else { - if (key < 0 && !isEncryptedChat) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsTypingGroup", R.string.IsTypingGroup, getUserNameForTyping(user))); + if (isGroup) { + text = LocaleController.formatString("IsTypingGroup", R.string.IsTypingGroup, getUserNameForTyping(user)); } else { - newPrintingStrings.put(threadId, LocaleController.getString("Typing", R.string.Typing)); + text = LocaleController.getString("Typing", R.string.Typing); } - newPrintingStringsTypes.put(threadId, 0); + type = 0; } } else { int count = 0; @@ -7188,22 +7248,30 @@ private void updatePrintingStrings() { } if (label.length() != 0) { if (count == 1) { - newPrintingStrings.put(threadId, LocaleController.formatString("IsTypingGroup", R.string.IsTypingGroup, label.toString())); + text = LocaleController.formatString("IsTypingGroup", R.string.IsTypingGroup, label.toString()); } else { if (arr.size() > 2) { String plural = LocaleController.getPluralString("AndMoreTypingGroup", arr.size() - 2); try { - newPrintingStrings.put(threadId, String.format(plural, label.toString(), arr.size() - 2)); + text = String.format(plural, label.toString(), arr.size() - 2); } catch (Exception e) { - newPrintingStrings.put(threadId, "LOC_ERR: AndMoreTypingGroup"); + text = "LOC_ERR: AndMoreTypingGroup"; } } else { - newPrintingStrings.put(threadId, LocaleController.formatString("AreTypingGroup", R.string.AreTypingGroup, label.toString())); + text = LocaleController.formatString("AreTypingGroup", R.string.AreTypingGroup, label.toString()); } } - newPrintingStringsTypes.put(threadId, 0); + type = 0; } } + if (text != null && ApplicationLoader.applicationContext != null) { + if (Theme.dialogs_messageNamePaint == null) { + Theme.createDialogsResources(ApplicationLoader.applicationContext); + } + text = Emoji.replaceEmoji(text, Theme.dialogs_messageNamePaint.getFontMetricsInt(), false); + newPrintingStrings.put(threadId, text); + newPrintingStringsTypes.put(threadId, type); + } } } @@ -8085,7 +8153,7 @@ public void loadDialogs(final int folderId, int offset, int count, boolean fromC getConnectionsManager().sendRequest(req, (response, error) -> { if (error == null) { TLRPC.messages_Dialogs dialogsRes = (TLRPC.messages_Dialogs) response; - processLoadedDialogs(dialogsRes, null, folderId, 0, count, 0, false, false, false); + processLoadedDialogs(dialogsRes, null, null, folderId, 0, count, 0, false, false, false); if (onEmptyCallback != null && dialogsRes.dialogs.isEmpty()) { AndroidUtilities.runOnUIThread(onEmptyCallback); } @@ -8258,7 +8326,7 @@ protected void loadUnknownDialog(final TLRPC.InputPeer peer, long taskId) { dialogs.messages.addAll(res.messages); dialogs.users.addAll(res.users); dialogs.chats.addAll(res.chats); - processLoadedDialogs(dialogs, null, dialog.folder_id, 0, 1, DIALOGS_LOAD_TYPE_UNKNOWN, false, false, false); + processLoadedDialogs(dialogs, null, null, dialog.folder_id, 0, 1, DIALOGS_LOAD_TYPE_UNKNOWN, false, false, false); } } if (newTaskId != 0) { @@ -8544,6 +8612,7 @@ protected void completeDialogsReset(final TLRPC.messages_Dialogs dialogsRes, int } } } + getTranslateController().checkDialogMessages(key); } allDialogs.clear(); @@ -8764,7 +8833,7 @@ private void migrateDialogs(int offset, int offsetDate, long offsetUser, long of } } - processLoadedDialogs(dialogsRes, null, 0, offsetId, 0, 0, false, true, false); + processLoadedDialogs(dialogsRes, null, null, 0, offsetId, 0, 0, false, true, false); } catch (Exception e) { FileLog.e(e); AndroidUtilities.runOnUIThread(() -> migratingDialogs = false); @@ -8780,7 +8849,7 @@ private void migrateDialogs(int offset, int offsetDate, long offsetUser, long of private int DIALOGS_LOAD_TYPE_CHANNEL = 2; private int DIALOGS_LOAD_TYPE_UNKNOWN = 3; - public void processLoadedDialogs(final TLRPC.messages_Dialogs dialogsRes, ArrayList encChats, int folderId, int offset, int count, int loadType, boolean resetEnd, boolean migrate, boolean fromCache) { + public void processLoadedDialogs(final TLRPC.messages_Dialogs dialogsRes, ArrayList encChats, ArrayList fullUsers, int folderId, int offset, int count, int loadType, boolean resetEnd, boolean migrate, boolean fromCache) { Utilities.stageQueue.postRunnable(() -> { if (!firstGettingTask) { getNewDeleteTask(null, null); @@ -8794,6 +8863,13 @@ public void processLoadedDialogs(final TLRPC.messages_Dialogs dialogsRes, ArrayL if (loadType == DIALOGS_LOAD_TYPE_CACHE && dialogsRes.dialogs.size() == 0) { AndroidUtilities.runOnUIThread(() -> { putUsers(dialogsRes.users, true); + if (fullUsers != null) { + for (int i = 0; i < fullUsers.size(); i++) { + long did = fullUsers.get(i).id; + this.fullUsers.put(did, fullUsers.get(i)); + getTranslateController().updateDialogFull(did); + } + } loadingDialogs.put(folderId, false); if (resetEnd) { dialogsEndReached.put(folderId, false); @@ -9040,6 +9116,13 @@ public void processLoadedDialogs(final TLRPC.messages_Dialogs dialogsRes, ArrayL } putUsers(dialogsRes.users, loadType == DIALOGS_LOAD_TYPE_CACHE); putChats(dialogsRes.chats, loadType == DIALOGS_LOAD_TYPE_CACHE); + if (fullUsers != null) { + for (int i = 0; i < fullUsers.size(); i++) { + long did = fullUsers.get(i).id; + this.fullUsers.put(did, fullUsers.get(i)); + getTranslateController().updateDialogFull(did); + } + } if (encChats != null) { for (int a = 0; a < encChats.size(); a++) { @@ -9090,6 +9173,7 @@ public void processLoadedDialogs(final TLRPC.messages_Dialogs dialogsRes, ArrayL } } } + getTranslateController().checkDialogMessages(key); } else { if (loadType != DIALOGS_LOAD_TYPE_CACHE) { currentDialog.notify_settings = value.notify_settings; @@ -9141,6 +9225,7 @@ public void processLoadedDialogs(final TLRPC.messages_Dialogs dialogsRes, ArrayL } } } + getTranslateController().checkDialogMessages(key); } } else { // if (newMsg == null && oldMs.getId() > 0 || newMsg != null && newMsg.messageOwner.date > oldMsg.messageOwner.date) @@ -9178,6 +9263,7 @@ public void processLoadedDialogs(final TLRPC.messages_Dialogs dialogsRes, ArrayL } } } + getTranslateController().checkDialogMessages(key); } } } @@ -9635,6 +9721,7 @@ public void processDialogsUpdate(final TLRPC.messages_Dialogs dialogsRes, ArrayL FileLog.d("processDialogsUpdate new message not null"); } } + getTranslateController().checkDialogMessages(key); } else { if (BuildVars.LOGS_ENABLED) { FileLog.d("processDialogsUpdate dialog not null"); @@ -9694,6 +9781,7 @@ public void processDialogsUpdate(final TLRPC.messages_Dialogs dialogsRes, ArrayL } } } + getTranslateController().checkDialogMessages(key); } if (fromCache && newMsgs == null) { checkLastDialogMessage(value, null, 0); @@ -9740,6 +9828,7 @@ public void processDialogsUpdate(final TLRPC.messages_Dialogs dialogsRes, ArrayL } } } + getTranslateController().checkDialogMessages(key); } } } @@ -10268,7 +10357,7 @@ public int createChat(String title, ArrayList selectedContacts, String abo if (type == ChatObject.CHAT_TYPE_CHAT && !forImport) { TLRPC.TL_messages_createChat req = new TLRPC.TL_messages_createChat(); req.title = title; - if (ttlPeriod > 0) { + if (ttlPeriod >= 0) { req.ttl_period = ttlPeriod; req.flags |= 1; } @@ -10299,16 +10388,17 @@ public int createChat(String title, ArrayList selectedContacts, String abo } }); }, ConnectionsManager.RequestFlagFailOnServerErrors); - } else if (forImport || type == ChatObject.CHAT_TYPE_CHANNEL || type == ChatObject.CHAT_TYPE_MEGAGROUP) { + } else if (forImport || type == ChatObject.CHAT_TYPE_CHANNEL || type == ChatObject.CHAT_TYPE_MEGAGROUP || type == ChatObject.CHAT_TYPE_FORUM) { TLRPC.TL_channels_createChannel req = new TLRPC.TL_channels_createChannel(); req.title = title; req.about = about != null ? about : ""; req.for_import = forImport; - if (forImport || type == ChatObject.CHAT_TYPE_MEGAGROUP) { + if (forImport || type == ChatObject.CHAT_TYPE_MEGAGROUP || type == ChatObject.CHAT_TYPE_FORUM) { req.megagroup = true; } else { req.broadcast = true; } + req.forum = type == ChatObject.CHAT_TYPE_FORUM; if (location != null) { req.geo_point = new TLRPC.TL_inputGeoPoint(); req.geo_point.lat = location.getLatitude(); @@ -10962,12 +11052,12 @@ public void changeChatTitle(long chatId, String title) { }, ConnectionsManager.RequestFlagInvokeAfter); } - public void changeChatAvatar(long chatId, TLRPC.TL_inputChatPhoto oldPhoto, TLRPC.InputFile inputPhoto, TLRPC.InputFile inputVideo, double videoStartTimestamp, String videoPath, TLRPC.FileLocation smallSize, TLRPC.FileLocation bigSize, Runnable callback) { + public void changeChatAvatar(long chatId, TLRPC.TL_inputChatPhoto oldPhoto, TLRPC.InputFile inputPhoto, TLRPC.InputFile inputVideo, TLRPC.VideoSize emojiMarkup, double videoStartTimestamp, String videoPath, TLRPC.FileLocation smallSize, TLRPC.FileLocation bigSize, Runnable callback) { TLObject request; TLRPC.InputChatPhoto inputChatPhoto; if (oldPhoto != null) { inputChatPhoto = oldPhoto; - } else if (inputPhoto != null || inputVideo != null) { + } else if (inputPhoto != null || inputVideo != null || emojiMarkup != null) { TLRPC.TL_inputChatUploadedPhoto uploadedPhoto = new TLRPC.TL_inputChatUploadedPhoto(); if (inputPhoto != null) { uploadedPhoto.file = inputPhoto; @@ -10979,6 +11069,10 @@ public void changeChatAvatar(long chatId, TLRPC.TL_inputChatPhoto oldPhoto, TLRP uploadedPhoto.video_start_ts = videoStartTimestamp; uploadedPhoto.flags |= 4; } + if (emojiMarkup != null) { + uploadedPhoto.video_emoji_markup = emojiMarkup; + uploadedPhoto.flags |= 8; + } inputChatPhoto = uploadedPhoto; } else { inputChatPhoto = new TLRPC.TL_inputChatPhotoEmpty(); @@ -11039,6 +11133,7 @@ public void changeChatAvatar(long chatId, TLRPC.TL_inputChatPhoto oldPhoto, TLRP File src = new File(videoPath); src.renameTo(destFile); } + getMessagesStorage().addDialogPhoto(-chatId, photo); } } processUpdates(updates, false); @@ -11047,6 +11142,7 @@ public void changeChatAvatar(long chatId, TLRPC.TL_inputChatPhoto oldPhoto, TLRP callback.run(); } getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_AVATAR); + getNotificationCenter().postNotificationName(NotificationCenter.reloadDialogPhotos); }); }, ConnectionsManager.RequestFlagInvokeAfter); } @@ -11076,13 +11172,8 @@ public void performLogout(int type) { getConnectionsManager().cleanup(false); AndroidUtilities.runOnUIThread(() -> { if (response instanceof TLRPC.TL_auth_loggedOut) { - TLRPC.TL_auth_loggedOut res = (TLRPC.TL_auth_loggedOut) response; if (((TLRPC.TL_auth_loggedOut) response).future_auth_token != null) { - SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("saved_tokens", Context.MODE_PRIVATE); - int count = preferences.getInt("count", 0); - SerializedData data = new SerializedData(response.getObjectSize()); - res.serializeToStream(data); - preferences.edit().putString("log_out_token_" + count, Utilities.bytesToHex(data.toByteArray())).putInt("count", count + 1).apply(); + AuthTokensHelper.addLogOutToken((TLRPC.TL_auth_loggedOut) response); } } }); @@ -11125,44 +11216,6 @@ public void performLogout(int type) { getContactsController().deleteUnknownAppAccounts(); } - public static ArrayList getSavedLogOutTokens() { - SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("saved_tokens", Context.MODE_PRIVATE); - int count = preferences.getInt("count", 0); - if (count == 0) { - return null; - } - - ArrayList tokens = new ArrayList<>(); - for (int i = 0; i < count; i++) { - String value = preferences.getString("log_out_token_" + i, ""); - SerializedData serializedData = new SerializedData(Utilities.hexToBytes(value)); - TLRPC.TL_auth_loggedOut token = TLRPC.TL_auth_loggedOut.TLdeserialize(serializedData, serializedData.readInt32(true), true); - if (token != null) { - tokens.add(token); - } - } - return tokens; - } - - public static void saveLogOutTokens(ArrayList tokens) { - SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("saved_tokens", Context.MODE_PRIVATE); - ArrayList activeTokens = new ArrayList<>(); - preferences.edit().clear().apply(); - int date = (int) (System.currentTimeMillis() / 1000L); - for (int i = 0; i < Math.min(20, tokens.size()); i++) { - activeTokens.add(tokens.get(i)); - } - if (activeTokens.size() > 0) { - SharedPreferences.Editor editor = preferences.edit(); - editor.putInt("count", activeTokens.size()); - for (int i = 0; i < activeTokens.size(); i++) { - SerializedData data = new SerializedData(activeTokens.get(i).getObjectSize()); - activeTokens.get(i).serializeToStream(data); - editor.putString("log_out_token_" + i, Utilities.bytesToHex(data.toByteArray())); - } - editor.apply(); - } - } private boolean gettingAppChangelog; @@ -11478,7 +11531,7 @@ protected void loadUnknownChannel(final TLRPC.Chat channel, long taskId) { dialogs.messages.addAll(res.messages); dialogs.users.addAll(res.users); dialogs.chats.addAll(res.chats); - processLoadedDialogs(dialogs, null, dialog.folder_id, 0, 1, DIALOGS_LOAD_TYPE_CHANNEL, false, false, false); + processLoadedDialogs(dialogs, null, null, dialog.folder_id, 0, 1, DIALOGS_LOAD_TYPE_CHANNEL, false, false, false); } } if (newTaskId != 0) { @@ -12458,6 +12511,7 @@ public void loadPinnedDialogs(final int folderId, long newDialogId, ArrayList updates, ArrayList> array; if (editingMessages == null) { @@ -15047,7 +15102,7 @@ public boolean processUpdateArray(ArrayList updates, ArrayList 0) { + if ((update.flags & 1) != 0) { getTopicsController().applyPinnedOrder(update.channel_id, update.order); } else { getTopicsController().reloadTopics(update.channel_id, false); @@ -16283,6 +16338,7 @@ public boolean updateInterfaceWithMessages(long dialogId, ArrayList chatsDict) { if (sortingDialogFilter == null) { continue; } - Collections.sort(allDialogs, dialogDateComparator); + try { + Collections.sort(allDialogs, dialogDateComparator); + } catch (Exception e) { + FileLog.e(e); + } ArrayList dialogsByFilter = sortingDialogFilter.dialogs; for (int a = 0, N = allDialogs.size(); a < N; a++) { @@ -16973,6 +17038,73 @@ public void setChatReactions(long chatId, int type, List reactions) { }); } + public boolean matchesAdminRights(TLRPC.Chat chat, TLRPC.User user, TLRPC.TL_chatAdminRights rights) { + if (rights == null) { + return true; + } + TLRPC.TL_chatAdminRights userRights = getChatAdminRightsCached(chat, user); + return ( + (!rights.change_info || userRights != null && userRights.change_info) && + (!rights.post_messages || userRights != null && userRights.post_messages) && + (!rights.edit_messages || userRights != null && userRights.edit_messages) && + (!rights.delete_messages || userRights != null && userRights.delete_messages) && + (!rights.ban_users || userRights != null && userRights.ban_users) && + (!rights.invite_users || userRights != null && userRights.invite_users) && + (!rights.pin_messages || userRights != null && userRights.pin_messages) && + (!rights.add_admins || userRights != null && userRights.add_admins) && + (!rights.anonymous || userRights != null && userRights.anonymous) && + (!rights.manage_call || userRights != null && userRights.manage_call) && + (!rights.other || userRights != null && userRights.other) && + (!rights.manage_topics || userRights != null && userRights.manage_topics) + ); + } + + public TLRPC.TL_chatAdminRights getChatAdminRightsCached(TLRPC.Chat chat, TLRPC.User user) { + if (chat == null || user == null) { + return null; + } + if (UserObject.isUserSelf(user)) { + return chat.admin_rights; + } + final TLRPC.ChatFull chatFull = getChatFull(chat.id); + if (chatFull == null || chatFull.participants == null || chatFull.participants.participants == null) { + return null; + } + final ArrayList participants = chatFull.participants.participants; + + for (int i = 0; i < participants.size(); ++i) { + TLRPC.ChatParticipant participant = participants.get(i); + if (participant != null && participant.user_id == user.id) { + if (participant instanceof TLRPC.TL_chatChannelParticipant && ((TLRPC.TL_chatChannelParticipant) participant).channelParticipant != null) { + return ((TLRPC.TL_chatChannelParticipant) participant).channelParticipant.admin_rights; + } + return null; + } + } + return null; + } + + public boolean isInChatCached(TLRPC.Chat chat, TLRPC.User user) { + if (chat == null || user == null) { + return false; + } + if (UserObject.isUserSelf(user)) { + return !ChatObject.isNotInChat(chat); + } + final TLRPC.ChatFull chatFull = getChatFull(chat.id); + if (chatFull == null || chatFull.participants == null || chatFull.participants.participants == null) { + return false; + } + final ArrayList participants = chatFull.participants.participants; + for (int i = 0; i < participants.size(); ++i) { + TLRPC.ChatParticipant participant = participants.get(i); + if (participant != null && participant.user_id == user.id) { + return true; + } + } + return false; + } + public void checkIsInChat(boolean tryCacheFirst, TLRPC.Chat chat, TLRPC.User user, IsInChatCheckedCallback callback) { if (chat == null || user == null) { if (callback != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index c6a523a9191..e19fd6d6fbd 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -15,6 +15,7 @@ import android.text.Spanned; import android.text.TextUtils; import android.text.style.ForegroundColorSpan; +import android.util.Log; import android.util.Pair; import android.util.SparseArray; import android.util.SparseIntArray; @@ -34,6 +35,7 @@ import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.DialogsSearchAdapter; +import org.telegram.ui.DialogsActivity; import org.telegram.ui.EditWidgetActivity; import java.io.File; @@ -93,7 +95,7 @@ public class MessagesStorage extends BaseController { } } - private final static int LAST_DB_VERSION = 111; + private final static int LAST_DB_VERSION = 112; private boolean databaseMigrationInProgress; public boolean showClearDatabaseAlert; private LongSparseIntArray dialogIsForum = new LongSparseIntArray(); @@ -447,6 +449,8 @@ public void openDatabase(int openTries) { database.executeFast("CREATE TABLE reaction_mentions_topics(message_id INTEGER, state INTEGER, dialog_id INTEGER, topic_id INTEGER, PRIMARY KEY(message_id, dialog_id, topic_id))").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS reaction_mentions_topics_did ON reaction_mentions_topics(dialog_id, topic_id);").stepThis().dispose(); + database.executeFast("CREATE TABLE emoji_groups(type INTEGER PRIMARY KEY, data BLOB)").stepThis().dispose(); + //version database.executeFast("PRAGMA user_version = " + LAST_DB_VERSION).stepThis().dispose(); } else { @@ -502,9 +506,9 @@ public void openDatabase(int openTries) { } } catch (Exception e) { FileLog.e(e); - if (BuildVars.DEBUG_PRIVATE_VERSION) { - throw new RuntimeException(e); - } +// if (BuildVars.DEBUG_PRIVATE_VERSION) { +// throw new RuntimeException(e); +// } if (openTries < 3 && e.getMessage() != null && e.getMessage().contains("malformed")) { if (openTries == 2) { cleanupInternal(true); @@ -3917,68 +3921,82 @@ public void putDialogPhotos(long did, TLRPC.photos_Photos photos, ArrayList { - SQLitePreparedStatement state = null; - try { - database.executeFast("DELETE FROM user_photos WHERE uid = " + did).stepThis().dispose(); - state = database.executeFast("REPLACE INTO user_photos VALUES(?, ?, ?)"); - for (int a = 0, N = photos.photos.size(); a < N; a++) { - TLRPC.Photo photo = photos.photos.get(a); - if (photo instanceof TLRPC.TL_photoEmpty) { - continue; - } - if (photo.file_reference == null) { - photo.file_reference = new byte[0]; - } - state.requery(); - int size = photo.getObjectSize(); - if (messages != null) { - size += messages.get(a).getObjectSize(); - } - NativeByteBuffer data = new NativeByteBuffer(size); - photo.serializeToStream(data); - if (messages != null) { - messages.get(a).serializeToStream(data); - } - state.bindLong(1, did); - state.bindLong(2, photo.id); - state.bindByteBuffer(3, data); - state.step(); - data.reuse(); - } - state.dispose(); - state = null; - } catch (Exception e) { - FileLog.e(e); - } finally { - if (state != null) { - state.dispose(); - } - } + putDialogPhotosInternal(did, photos, messages); }); } - public void addDialogPhoto(long did, TLRPC.Photo photo) { - storageQueue.postRunnable(() -> { - SQLitePreparedStatement state = null; - try { - state = database.executeFast("REPLACE INTO user_photos VALUES(?, ?, ?)"); - + private void putDialogPhotosInternal(long did, TLRPC.photos_Photos photos, ArrayList messages) { + SQLitePreparedStatement state = null; + try { + database.executeFast("DELETE FROM user_photos WHERE uid = " + did).stepThis().dispose(); + state = database.executeFast("REPLACE INTO user_photos VALUES(?, ?, ?)"); + for (int a = 0, N = photos.photos.size(); a < N; a++) { + TLRPC.Photo photo = photos.photos.get(a); + if (photo instanceof TLRPC.TL_photoEmpty || photo == null) { + continue; + } + if (photo.file_reference == null) { + photo.file_reference = new byte[0]; + } state.requery(); int size = photo.getObjectSize(); + if (messages != null && messages.get(a) != null) { + size += messages.get(a).getObjectSize(); + } NativeByteBuffer data = new NativeByteBuffer(size); photo.serializeToStream(data); + if (messages != null && messages.get(a) != null) { + messages.get(a).serializeToStream(data); + } state.bindLong(1, did); state.bindLong(2, photo.id); state.bindByteBuffer(3, data); state.step(); data.reuse(); + } + state.dispose(); + state = null; + } catch (Exception e) { + FileLog.e(e); + } finally { + if (state != null) { state.dispose(); - state = null; + } + } + } + + public void addDialogPhoto(long did, TLRPC.Photo photoToAdd) { + storageQueue.postRunnable(() -> { + SQLiteCursor cursor = null; + try { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM user_photos WHERE uid = %d ORDER BY rowid ASC", did)); + + TLRPC.photos_Photos res = new TLRPC.TL_photos_photos(); + ArrayList messages = new ArrayList<>(); + + while (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + TLRPC.Photo photo = TLRPC.Photo.TLdeserialize(data, data.readInt32(false), false); + if (data.remaining() > 0) { + messages.add(TLRPC.Message.TLdeserialize(data, data.readInt32(false), false)); + } else { + messages.add(null); + } + data.reuse(); + res.photos.add(photo); + messages.add(null); + } + } + cursor.dispose(); + cursor = null; + res.photos.add(0, photoToAdd); + putDialogPhotosInternal(did, res, messages); } catch (Exception e) { FileLog.e(e); } finally { - if (state != null) { - state.dispose(); + if (cursor != null) { + cursor.dispose(); } } }); @@ -4260,7 +4278,7 @@ public void updateMessageVoiceTranscriptionOpen(long dialogId, int msgId, TLRPC. SQLitePreparedStatement state = null; try { database.beginTransaction(); - TLRPC.Message message = getMessageWithCustomParamsOnly(msgId, dialogId); + TLRPC.Message message = getMessageWithCustomParamsOnlyInternal(msgId, dialogId); message.voiceTranscriptionOpen = saveFromMessage.voiceTranscriptionOpen; message.voiceTranscriptionRated = saveFromMessage.voiceTranscriptionRated; message.voiceTranscriptionFinal = saveFromMessage.voiceTranscriptionFinal; @@ -4308,7 +4326,7 @@ public void updateMessageVoiceTranscription(long dialogId, int messageId, String SQLitePreparedStatement state = null; try { database.beginTransaction(); - TLRPC.Message message = getMessageWithCustomParamsOnly(messageId, dialogId); + TLRPC.Message message = getMessageWithCustomParamsOnlyInternal(messageId, dialogId); message.voiceTranscriptionFinal = isFinal; message.voiceTranscriptionId = transcriptionId; message.voiceTranscription = text; @@ -4348,7 +4366,7 @@ public void updateMessageVoiceTranscription(long dialogId, int messageId, String SQLitePreparedStatement state = null; try { database.beginTransaction(); - TLRPC.Message message = getMessageWithCustomParamsOnly(messageId, dialogId); + TLRPC.Message message = getMessageWithCustomParamsOnlyInternal(messageId, dialogId); message.voiceTranscriptionOpen = saveFromMessage.voiceTranscriptionOpen; message.voiceTranscriptionRated = saveFromMessage.voiceTranscriptionRated; message.voiceTranscriptionFinal = saveFromMessage.voiceTranscriptionFinal; @@ -4397,7 +4415,7 @@ public void updateMessageCustomParams(long dialogId, TLRPC.Message saveFromMessa SQLitePreparedStatement state = null; try { database.beginTransaction(); - TLRPC.Message message = getMessageWithCustomParamsOnly(saveFromMessage.id, dialogId); + TLRPC.Message message = getMessageWithCustomParamsOnlyInternal(saveFromMessage.id, dialogId); MessageCustomParamsHelper.copyParams(saveFromMessage, message); for (int i = 0; i < 2; i++) { @@ -4436,7 +4454,7 @@ public void updateMessageCustomParams(long dialogId, TLRPC.Message saveFromMessa }); } - private TLRPC.Message getMessageWithCustomParamsOnly(int messageId, long dialogId) { + public TLRPC.Message getMessageWithCustomParamsOnlyInternal(int messageId, long dialogId) { TLRPC.Message message = new TLRPC.TL_message(); SQLiteCursor cursor = null; try { @@ -5838,6 +5856,29 @@ public void getBotCache(String key, RequestDelegate requestDelegate) { }); } + public ArrayList loadUserInfos(HashSet uids) { + ArrayList arrayList = new ArrayList<>(); + try { + String ids = TextUtils.join(",", uids); + SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM user_settings WHERE uid IN(" + ids + ")"); + while (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + TLRPC.UserFull info = TLRPC.UserFull.TLdeserialize(data, data.readInt32(false), false); + info.pinned_msg_id = cursor.intValue(1); + arrayList.add(info); + data.reuse(); + + } + } + cursor.dispose(); + cursor = null; + } catch (Exception e) { + FileLog.e(e); + } + return arrayList; + } + public void loadUserInfo(TLRPC.User user, boolean force, int classGuid, int fromMessageId) { if (user == null) { return; @@ -10705,7 +10746,7 @@ private void putMessagesInternal(ArrayList messages, boolean with state_download.bindInteger(2, type); state_download.bindInteger(3, message.date); state_download.bindByteBuffer(4, data); - state_download.bindString(5, "sent_" + (message.peer_id != null ? message.peer_id.channel_id : 0) + "_" + message.id + "_" + DialogObject.getPeerDialogId(message.peer_id) + "_" + messageObject.type); + state_download.bindString(5, "sent_" + (message.peer_id != null ? message.peer_id.channel_id : 0) + "_" + message.id + "_" + DialogObject.getPeerDialogId(message.peer_id) + "_" + messageObject.type + "_" + messageObject.getSize()); state_download.step(); data.reuse(); } @@ -13715,6 +13756,7 @@ public void getDialogs(int folderId, int offset, int count, boolean loadDraftsPe SQLiteCursor cursor = null; try { ArrayList usersToLoad = new ArrayList<>(); + HashSet dialogUsers = new HashSet<>(); usersToLoad.add(getUserConfig().getClientUserId()); ArrayList chatsToLoad = new ArrayList<>(); ArrayList encryptedToLoad = new ArrayList<>(); @@ -13856,6 +13898,7 @@ public void getDialogs(int folderId, int offset, int count, boolean loadDraftsPe if (!usersToLoad.contains(dialogId)) { usersToLoad.add(dialogId); } + dialogUsers.add(dialogId); } else if (DialogObject.isChatDialog(dialogId)) { if (!chatsToLoad.contains(-dialogId)) { chatsToLoad.add(-dialogId); @@ -13998,14 +14041,18 @@ public void getDialogs(int folderId, int offset, int count, boolean loadDraftsPe if (!usersToLoad.isEmpty()) { getUsersInternal(TextUtils.join(",", usersToLoad), dialogs.users); } - getMessagesController().processLoadedDialogs(dialogs, encryptedChats, folderId, offset, count, 1, false, false, true); + ArrayList fullUsers = null; + if (!dialogUsers.isEmpty()) { + fullUsers = loadUserInfos(dialogUsers); + } + getMessagesController().processLoadedDialogs(dialogs, encryptedChats, fullUsers, folderId, offset, count, 1, false, false, true); } catch (Exception e) { dialogs.dialogs.clear(); dialogs.users.clear(); dialogs.chats.clear(); encryptedChats.clear(); FileLog.e(e); - getMessagesController().processLoadedDialogs(dialogs, encryptedChats, folderId, 0, 100, 1, true, false, true); + getMessagesController().processLoadedDialogs(dialogs, encryptedChats, null, folderId, 0, 100, 1, true, false, true); checkMalformed(e); } finally { if (cursor != null) { @@ -14040,6 +14087,41 @@ public static void createFirstHoles(long did, SQLitePreparedStatement state5, SQ } } + public void updateDialogData(TLRPC.Dialog dialog) { + if (dialog == null) { + return; + } + storageQueue.postRunnable(() -> { + SQLiteCursor cursor = null; + SQLitePreparedStatement state = null; + try { + cursor = database.queryFinalized("SELECT data FROM dialogs WHERE did = " + dialog.id); + if (!cursor.next()) { + return; + } + + state = database.executeFast("UPDATE dialogs SET data = ? WHERE did = ?"); + NativeByteBuffer data = new NativeByteBuffer(dialog.getObjectSize()); + dialog.serializeToStream(data); + state.bindByteBuffer(1, data); + state.bindLong(2, dialog.id); + state.step(); + state.dispose(); + state = null; + data.reuse(); + } catch (Exception e) { + FileLog.e(e); + } finally { + if (cursor != null) { + cursor.dispose(); + } + if (state != null) { + state.dispose(); + } + } + }); + } + private void putDialogsInternal(TLRPC.messages_Dialogs dialogs, int check) { SQLitePreparedStatement state_messages = null; SQLitePreparedStatement state_dialogs = null; @@ -14777,7 +14859,7 @@ public TLRPC.EncryptedChat getEncryptedChat(long chatId) { } - public void localSearch(int dialogsType, String query, ArrayList resultArray, ArrayList resultArrayNames, ArrayList encUsers, int folderId) { + public void localSearch(int dialogsType, String query, ArrayList resultArray, ArrayList resultArrayNames, ArrayList encUsers, ArrayList onlyDialogIds, int folderId) { long selfUserId = UserConfig.getInstance(currentAccount).getClientUserId(); SQLiteCursor cursor = null; try { @@ -14816,23 +14898,30 @@ public void localSearch(int dialogsType, String query, ArrayList resultA dialogSearchResult.date = cursor.intValue(1); dialogsResult.put(id, dialogSearchResult); + if (dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER && (onlyDialogIds == null || !onlyDialogIds.contains(id))) { + continue; + } + if (!DialogObject.isEncryptedDialog(id)) { if (DialogObject.isUserDialog(id)) { - if (dialogsType == 4 && id == selfUserId) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_USERS_ONLY && id == selfUserId) { + continue; + } + if (dialogsType == DialogsActivity.DIALOGS_TYPE_GROUPS_ONLY || dialogsType == DialogsActivity.DIALOGS_TYPE_CHANNELS_ONLY) { continue; } - if (dialogsType != 2 && !usersToLoad.contains(id)) { + if (dialogsType != DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO && !usersToLoad.contains(id)) { usersToLoad.add(id); } } else { - if (dialogsType == 4) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_USERS_ONLY) { continue; } if (!chatsToLoad.contains(-id)) { chatsToLoad.add(-id); } } - } else if (dialogsType == 0 || dialogsType == 3) { + } else if (dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT || dialogsType == DialogsActivity.DIALOGS_TYPE_FORWARD) { int encryptedChatId = DialogObject.getEncryptedChatId(id); if (!encryptedToLoad.contains(encryptedChatId)) { encryptedToLoad.add(encryptedChatId); @@ -14892,6 +14981,9 @@ public void localSearch(int dialogsType, String query, ArrayList resultA if (data != null) { TLRPC.User user = TLRPC.User.TLdeserialize(data, data.readInt32(false), false); data.reuse(); + if (dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER && (onlyDialogIds == null || !onlyDialogIds.contains(user.id))) { + continue; + } DialogsSearchAdapter.DialogSearchResult dialogSearchResult = dialogsResult.get(user.id); if (user.status != null) { user.status.expires = cursor.intValue(1); @@ -14926,6 +15018,15 @@ public void localSearch(int dialogsType, String query, ArrayList resultA if (data != null) { TLRPC.Chat chat = TLRPC.Chat.TLdeserialize(data, data.readInt32(false), false); data.reuse(); + if (dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER && (onlyDialogIds == null || !onlyDialogIds.contains(-chat.id))) { + continue; + } + if (dialogsType == DialogsActivity.DIALOGS_TYPE_GROUPS_ONLY && ChatObject.isChannelAndNotMegaGroup(chat)) { + continue; + } + if (dialogsType == DialogsActivity.DIALOGS_TYPE_CHANNELS_ONLY && !ChatObject.isChannelAndNotMegaGroup(chat)) { + continue; + } if (!(chat == null || chat.deactivated || ChatObject.isChannel(chat) && ChatObject.isNotInChat(chat))) { long dialog_id = -chat.id; DialogsSearchAdapter.DialogSearchResult dialogSearchResult = dialogsResult.get(dialog_id); @@ -14942,7 +15043,7 @@ public void localSearch(int dialogsType, String query, ArrayList resultA cursor = null; } - if (!encryptedToLoad.isEmpty()) { + if (!encryptedToLoad.isEmpty() && dialogsType != DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { cursor = getDatabase().queryFinalized(String.format(Locale.US, "SELECT q.data, u.name, q.user, q.g, q.authkey, q.ttl, u.data, u.status, q.layer, q.seq_in, q.seq_out, q.use_count, q.exchange_id, q.key_date, q.fprint, q.fauthkey, q.khash, q.in_seq_no, q.admin_id, q.mtproto_seq FROM enc_chats as q INNER JOIN users as u ON q.user = u.uid WHERE q.uid IN(%s)", TextUtils.join(",", encryptedToLoad))); while (cursor.next()) { String name = cursor.stringValue(1); @@ -15046,7 +15147,7 @@ public void localSearch(int dialogsType, String query, ArrayList resultA resultArrayNames.add(dialogSearchResult.name); } - if (dialogsType != 2) { + if (dialogsType != DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO && dialogsType != DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER && dialogsType != DialogsActivity.DIALOGS_TYPE_GROUPS_ONLY && dialogsType != DialogsActivity.DIALOGS_TYPE_CHANNELS_ONLY) { cursor = getDatabase().queryFinalized("SELECT u.data, u.status, u.name, u.uid FROM users as u INNER JOIN contacts as c ON u.uid = c.uid"); while (cursor.next()) { long uid = cursor.longValue(3); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java index 944693535f4..b577bcd4667 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java @@ -72,6 +72,7 @@ public class NotificationCenter { public static final int updateMessageMedia = totalEvents++; public static final int replaceMessagesObjects = totalEvents++; public static final int didSetPasscode = totalEvents++; + public static final int passcodeDismissed = totalEvents++; public static final int twoStepPasswordChanged = totalEvents++; public static final int didSetOrRemoveTwoStepPassword = totalEvents++; public static final int didRemoveTwoStepPassword = totalEvents++; @@ -136,6 +137,11 @@ public class NotificationCenter { public static final int recentEmojiStatusesUpdate = totalEvents++; public static final int updateSearchSettings = totalEvents++; + public static final int messageTranslated = totalEvents++; + public static final int messageTranslating = totalEvents++; + public static final int dialogIsTranslatable = totalEvents++; + public static final int dialogTranslate = totalEvents++; + public static final int didGenerateFingerprintKeyPair = totalEvents++; public static final int walletPendingTransactionsChanged = totalEvents++; @@ -231,6 +237,7 @@ public class NotificationCenter { public static final int didSetNewWallpapper = totalEvents++; public static final int proxySettingsChanged = totalEvents++; public static final int proxyCheckDone = totalEvents++; + public static final int proxyChangedByRotation = totalEvents++; public static final int liveLocationsChanged = totalEvents++; public static final int newLocationAvailable = totalEvents++; public static final int liveLocationsCacheChanged = totalEvents++; @@ -735,7 +742,7 @@ public T remove(int index) { @Override public boolean remove(@Nullable Object o) { - if (set.remove(0)) { + if (set.remove(o)) { return super.remove(o); } return false; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java index 20fa6ebcc16..26999fb3590 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java @@ -4084,6 +4084,7 @@ void call() { long selfUserId = getUserConfig().getClientUserId(); boolean waitingForPasscode = AndroidUtilities.needShowPasscode() || SharedConfig.isWaitingForPasscodeEnter; + boolean passcode = SharedConfig.passcodeHash.length() > 0; int maxCount = 7; LongSparseArray personCache = new LongSparseArray<>(); @@ -4148,6 +4149,7 @@ void call() { } else { chat = getMessagesController().getChat(-dialogId); if (chat == null) { + canReply = false; if (lastMessageObject.isFcmMessage()) { isSupergroup = lastMessageObject.isSupergroup(); name = lastMessageObject.localName; @@ -4172,7 +4174,9 @@ void call() { name = topic.title + " in " + name; } } - + if (canReply) { + canReply = ChatObject.canSendPlain(chat); + } } } } else { @@ -4207,6 +4211,9 @@ void call() { photoPath = null; canReply = false; } + if (passcode) { + canReply = false; + } if (photoPath != null) { avatalFile = getFileLoader().getPathToAttach(photoPath, true); @@ -4521,6 +4528,7 @@ void call() { } else { intent.putExtra("chatId", -dialogId); } + FileLog.d("show extra notifications chatId " + dialogId + " topicId " + topicId); if (topicId != 0) { intent.putExtra("topicId", topicId); } @@ -4596,7 +4604,7 @@ void call() { if (wearReplyAction != null) { builder.addAction(wearReplyAction); } - if (!waitingForPasscode) { + if (!passcode) { builder.addAction(readAction); } if (sortedDialogs.size() == 1 && !TextUtils.isEmpty(summary)) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ProxyRotationController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ProxyRotationController.java new file mode 100644 index 00000000000..9b5fb771319 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ProxyRotationController.java @@ -0,0 +1,128 @@ +package org.telegram.messenger; + +import android.content.SharedPreferences; +import android.os.SystemClock; + +import org.telegram.tgnet.ConnectionsManager; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class ProxyRotationController implements NotificationCenter.NotificationCenterDelegate { + private final static ProxyRotationController INSTANCE = new ProxyRotationController(); + + public final static int DEFAULT_TIMEOUT_INDEX = 1; + public final static List ROTATION_TIMEOUTS = Arrays.asList( + 5, 10, 15, 30, 60 + ); + + private boolean isCurrentlyChecking; + private Runnable checkProxyAndSwitchRunnable = () -> { + isCurrentlyChecking = true; + + int currentAccount = UserConfig.selectedAccount; + boolean startedCheck = false; + for (int i = 0; i < SharedConfig.proxyList.size(); i++) { + SharedConfig.ProxyInfo proxyInfo = SharedConfig.proxyList.get(i); + if (proxyInfo.checking || SystemClock.elapsedRealtime() - proxyInfo.availableCheckTime < 2 * 60 * 1000) { + continue; + } + startedCheck = true; + proxyInfo.checking = true; + proxyInfo.proxyCheckPingId = ConnectionsManager.getInstance(currentAccount).checkProxy(proxyInfo.address, proxyInfo.port, proxyInfo.username, proxyInfo.password, proxyInfo.secret, time -> AndroidUtilities.runOnUIThread(() -> { + proxyInfo.availableCheckTime = SystemClock.elapsedRealtime(); + proxyInfo.checking = false; + if (time == -1) { + proxyInfo.available = false; + proxyInfo.ping = 0; + } else { + proxyInfo.ping = time; + proxyInfo.available = true; + } + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxyCheckDone, proxyInfo); + })); + } + + if (!startedCheck) { + isCurrentlyChecking = false; + switchToAvailable(); + } + }; + + public static void init() { + INSTANCE.initInternal(); + } + + @SuppressWarnings("ComparatorCombinators") + private void switchToAvailable() { + isCurrentlyChecking = false; + + if (!SharedConfig.proxyRotationEnabled) { + return; + } + + List sortedList = new ArrayList<>(SharedConfig.proxyList); + Collections.sort(sortedList, (o1, o2) -> Long.compare(o1.ping, o2.ping)); + for (SharedConfig.ProxyInfo info : sortedList) { + if (info == SharedConfig.currentProxy || info.checking || !info.available) { + continue; + } + + SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit(); + editor.putString("proxy_ip", info.address); + editor.putString("proxy_pass", info.password); + editor.putString("proxy_user", info.username); + editor.putInt("proxy_port", info.port); + editor.putString("proxy_secret", info.secret); + editor.putBoolean("proxy_enabled", true); + + if (!info.secret.isEmpty()) { + editor.putBoolean("proxy_enabled_calls", false); + } + editor.apply(); + + SharedConfig.currentProxy = info; + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxySettingsChanged); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.proxyChangedByRotation); + ConnectionsManager.setProxySettings(true, SharedConfig.currentProxy.address, SharedConfig.currentProxy.port, SharedConfig.currentProxy.username, SharedConfig.currentProxy.password, SharedConfig.currentProxy.secret); + break; + } + } + + private void initInternal() { + for (int i = 0; i < UserConfig.MAX_ACCOUNT_COUNT; i++) { + NotificationCenter.getInstance(i).addObserver(this, NotificationCenter.didUpdateConnectionState); + } + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.proxyCheckDone); + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.proxySettingsChanged); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.proxyCheckDone) { + if (!SharedConfig.isProxyEnabled() || !SharedConfig.proxyRotationEnabled || SharedConfig.proxyList.size() <= 1 || !isCurrentlyChecking) { + return; + } + + switchToAvailable(); + } else if (id == NotificationCenter.proxySettingsChanged) { + AndroidUtilities.cancelRunOnUIThread(checkProxyAndSwitchRunnable); + } else if (id == NotificationCenter.didUpdateConnectionState && account == UserConfig.selectedAccount) { + if (!SharedConfig.isProxyEnabled() && !SharedConfig.proxyRotationEnabled || SharedConfig.proxyList.size() <= 1) { + return; + } + + int state = ConnectionsManager.getInstance(account).getConnectionState(); + + if (state == ConnectionsManager.ConnectionStateConnectingToProxy) { + if (!isCurrentlyChecking) { + AndroidUtilities.runOnUIThread(checkProxyAndSwitchRunnable, ROTATION_TIMEOUTS.get(SharedConfig.proxyRotationTimeout) * 1000L); + } + } else { + AndroidUtilities.cancelRunOnUIThread(checkProxyAndSwitchRunnable); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/PushListenerController.java b/TMessagesProj/src/main/java/org/telegram/messenger/PushListenerController.java index 486cfcb6e58..130f1d17750 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/PushListenerController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/PushListenerController.java @@ -3,6 +3,7 @@ import android.os.SystemClock; import android.text.TextUtils; import android.util.Base64; +import android.util.Log; import android.util.SparseBooleanArray; import androidx.annotation.IntDef; @@ -286,8 +287,9 @@ public static void processRemoteMessage(@PushType int pushType, String data, lon chat_id = 0; } if (custom.has("topic_id")) { - topicId =custom.getInt("topic_id"); + topicId = custom.getInt("topic_id"); } + FileLog.d( "recived push notification chatId " + chat_id + " custom topicId " + topicId); if (custom.has("encryption_id")) { dialogId = DialogObject.makeEncryptedDialogId(custom.getInt("encryption_id")); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SaveToGallerySettingsHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SaveToGallerySettingsHelper.java new file mode 100644 index 00000000000..9a5c10105d0 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SaveToGallerySettingsHelper.java @@ -0,0 +1,252 @@ +package org.telegram.messenger; + +import static org.telegram.messenger.SharedConfig.SAVE_TO_GALLERY_FLAG_CHANNELS; +import static org.telegram.messenger.SharedConfig.SAVE_TO_GALLERY_FLAG_GROUP; +import static org.telegram.messenger.SharedConfig.SAVE_TO_GALLERY_FLAG_PEER; + +import android.app.Activity; +import android.content.SharedPreferences; +import android.util.LongSparseArray; + +public class SaveToGallerySettingsHelper { + + //shared settings + public static SharedSettings user; + public static SharedSettings groups; + public static SharedSettings channels; + + public static String USERS_PREF_NAME = "users_save_gallery_exceptions"; + public static String CHANNELS_PREF_NAME = "channels_save_gallery_exceptions"; + public static String GROUPS_PREF_NAME = "groups_save_gallery_exceptions"; + + public static final long DEFAULT_VIDEO_LIMIT = 100 * 1024 * 1024;//100 MB + public static final long MAX_VIDEO_LIMIT = 4L * 1000 * 1024 * 1024;//100 MB + + public static void load(SharedPreferences preferences) { + boolean saveToGalleryLegacy = preferences.getBoolean("save_gallery", false); + int saveToGalleryFlags; + if (saveToGalleryLegacy && BuildVars.NO_SCOPED_STORAGE) { + saveToGalleryFlags = SAVE_TO_GALLERY_FLAG_PEER + SAVE_TO_GALLERY_FLAG_CHANNELS + SAVE_TO_GALLERY_FLAG_GROUP; + } else { + saveToGalleryFlags = preferences.getInt("save_gallery_flags", -1); + } + //migration + if (saveToGalleryFlags != -1) { + preferences.edit().remove("save_gallery").remove("save_gallery_flags").apply(); + user = new SharedSettings(); + user.savePhoto = user.saveVideo = (saveToGalleryFlags & SAVE_TO_GALLERY_FLAG_PEER) != 0; + user.limitVideo = DEFAULT_VIDEO_LIMIT; + user.save("user", preferences); + + groups = new SharedSettings(); + groups.savePhoto = user.saveVideo = (saveToGalleryFlags & SAVE_TO_GALLERY_FLAG_GROUP) != 0; + groups.limitVideo = DEFAULT_VIDEO_LIMIT; + groups.save("groups", preferences); + + channels = new SharedSettings(); + channels.savePhoto = channels.saveVideo = (saveToGalleryFlags & SAVE_TO_GALLERY_FLAG_CHANNELS) != 0; + channels.limitVideo = DEFAULT_VIDEO_LIMIT; + channels.save("channels", preferences); + + } else { + user = SharedSettings.read("user", preferences); + groups = SharedSettings.read("groups", preferences); + channels = SharedSettings.read("channels", preferences); + } + user.type = SAVE_TO_GALLERY_FLAG_PEER; + groups.type = SAVE_TO_GALLERY_FLAG_GROUP; + channels.type = SAVE_TO_GALLERY_FLAG_CHANNELS; + } + + public static boolean needSave(int flag, FilePathDatabase.FileMeta metaData, MessageObject messageObject, int currentAccount) { + SharedSettings settings; + if (flag == SharedConfig.SAVE_TO_GALLERY_FLAG_PEER) { + settings = user; + } else if (flag == SharedConfig.SAVE_TO_GALLERY_FLAG_CHANNELS) { + settings = channels; + } else if (flag == SharedConfig.SAVE_TO_GALLERY_FLAG_GROUP) { + settings = groups; + } else { + return false; + } + return settings.needSave(metaData, messageObject, currentAccount); + } + + public static LongSparseArray loadExceptions(SharedPreferences sharedPreferences) { + LongSparseArray exceptions = new LongSparseArray<>(); + int count = sharedPreferences.getInt("count", 0); + for (int i = 0; i < count; i++) { + DialogException dialogException = new DialogException(); + dialogException.dialogId = sharedPreferences.getLong(i + "_dialog_id", 0); + dialogException.savePhoto = sharedPreferences.getBoolean(i + "_photo", false); + dialogException.saveVideo = sharedPreferences.getBoolean(i + "_video", false); + dialogException.limitVideo = sharedPreferences.getLong(i + "_limitVideo", DEFAULT_VIDEO_LIMIT); + if (dialogException.dialogId != 0) { + exceptions.put(dialogException.dialogId, dialogException); + } + } + return exceptions; + } + + public static void saveExceptions(SharedPreferences sharedPreferences, LongSparseArray exceptions) { + sharedPreferences.edit().clear().apply(); + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putInt("count", exceptions.size()); + for (int i = 0; i < exceptions.size(); i++) { + DialogException dialogException = exceptions.valueAt(i); + editor.putLong(i + "_dialog_id", dialogException.dialogId); + editor.putBoolean(i + "_photo", dialogException.savePhoto); + editor.putBoolean(i + "_video", dialogException.saveVideo); + editor.putLong(i + "_limitVideo", dialogException.limitVideo); + } + editor.apply(); + } + + public static Settings getSettings(int type) { + if (type == SAVE_TO_GALLERY_FLAG_PEER) { + return user; + } else if (type == SAVE_TO_GALLERY_FLAG_GROUP) { + return groups; + } else if (type == SAVE_TO_GALLERY_FLAG_CHANNELS) { + return channels; + } + return null; + } + + public static void saveSettings(int type) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + if (type == SAVE_TO_GALLERY_FLAG_PEER) { + user.save("user", preferences); + } else if (type == SAVE_TO_GALLERY_FLAG_GROUP) { + groups.save("group", preferences); + } else if (type == SAVE_TO_GALLERY_FLAG_CHANNELS) { + channels.save("channels", preferences); + } + } + + public static abstract class Settings { + public boolean savePhoto; + public boolean saveVideo; + public long limitVideo = 100 * 1024 * 1024; ///100 MB + + public boolean enabled() { + return savePhoto || saveVideo; + } + + public abstract CharSequence createDescription(int currentAccount); + + public void toggle() { + if (enabled()) { + saveVideo = false; + savePhoto = false; + } else { + savePhoto = true; + saveVideo = true; + } + } + } + + public static class SharedSettings extends Settings { + private int type; + + private void save(String prefix, SharedPreferences sharedPreferences) { + sharedPreferences.edit() + .putBoolean(prefix + "_save_gallery_photo", savePhoto) + .putBoolean(prefix + "_save_gallery_video", saveVideo) + .putLong(prefix + "_save_gallery_limitVideo", limitVideo) + .apply(); + + } + + private static SharedSettings read(String prefix, SharedPreferences preferences) { + SharedSettings settings = new SharedSettings(); + settings.savePhoto = preferences.getBoolean(prefix + "_save_gallery_photo", false); + settings.saveVideo = preferences.getBoolean(prefix + "_save_gallery_video", false); + settings.limitVideo = preferences.getLong(prefix + "_save_gallery_limitVideo", DEFAULT_VIDEO_LIMIT); + return settings; + } + + private boolean needSave(FilePathDatabase.FileMeta meta, MessageObject messageObject, int currentAccount) { + LongSparseArray exceptions = UserConfig.getInstance(currentAccount).getSaveGalleryExceptions(type); + DialogException exception = exceptions.get(meta.dialogId); + if (messageObject != null && messageObject.isOutOwner()) { + return false; + } + boolean isVideo = (messageObject != null && messageObject.isVideo()) || meta.messageType == MessageObject.TYPE_VIDEO; + long size = messageObject != null ? messageObject.getSize() : meta.messageSize; + boolean needSaveVideo = saveVideo; + boolean needSavePhoto = savePhoto; + long saveVideoLimit = limitVideo; + if (exception != null) { + needSaveVideo = exception.saveVideo; + needSavePhoto = exception.savePhoto; + saveVideoLimit = exception.limitVideo; + } + if (isVideo) { + if (needSaveVideo && (saveVideoLimit == -1 || size < saveVideoLimit)) { + return true; + } + } else { + if (needSavePhoto) { + return true; + } + } + return false; + } + + public CharSequence createDescription(int currentAccount) { + StringBuilder builder = new StringBuilder(); + if (enabled()) { + if (savePhoto) { + builder.append(LocaleController.getString("SaveToGalleryPhotos", R.string.SaveToGalleryPhotos)); + } + if (saveVideo) { + if (builder.length() != 0) { + builder.append(", "); + } + builder.append(LocaleController.getString("SaveToGalleryVideos", R.string.SaveToGalleryVideos)); + if (limitVideo > 0 && limitVideo < 4L * 1000 * 1024 * 1024) { + builder.append(" (").append(AndroidUtilities.formatFileSize(limitVideo, true)).append(")"); + } + } + } else { + builder.append(LocaleController.getString("SaveToGalleryOff", R.string.SaveToGalleryOff)); + } + LongSparseArray exceptions = UserConfig.getInstance(currentAccount).getSaveGalleryExceptions(type); + if (exceptions.size() != 0) { + if (builder.length() != 0) { + builder.append(", "); + } + builder.append(LocaleController.formatPluralString("Exception", exceptions.size(), exceptions.size())); + } + return builder; + } + } + + public static class DialogException extends Settings { + public long dialogId; + + public CharSequence createDescription(int currentAccount) { + StringBuilder builder = new StringBuilder(); + if (enabled()) { + if (savePhoto) { + builder.append(LocaleController.getString("SaveToGalleryPhotos", R.string.SaveToGalleryPhotos)); + } + if (saveVideo) { + if (builder.length() != 0) { + builder.append(", "); + } + + if (limitVideo > 0 && limitVideo < 4L * 1000 * 1024 * 1024) { + builder.append(LocaleController.formatString("SaveToGalleryVideosUpTo", R.string.SaveToGalleryVideosUpTo, AndroidUtilities.formatFileSize(limitVideo, true))); + } else { + builder.append(LocaleController.formatString("SaveToGalleryVideos", R.string.SaveToGalleryVideos)); + } + } + } else { + builder.append(LocaleController.getString("SaveToGalleryOff", R.string.SaveToGalleryOff)); + } + return builder; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java index 21ce755ecae..0bc11624e7f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java @@ -519,6 +519,7 @@ public static class SendingMediaInfo { public boolean forceImage; public boolean updateStickersOrder; public boolean hasMediaSpoilers; + public TLRPC.VideoSize emojiMarkup; } @SuppressLint("MissingPermission") @@ -1454,7 +1455,7 @@ public void processForwardFromMyName(MessageObject messageObject, long did) { HashMap params = null; if (DialogObject.isEncryptedDialog(did) && messageObject.messageOwner.peer_id != null && (messageObject.messageOwner.media.photo instanceof TLRPC.TL_photo || messageObject.messageOwner.media.document instanceof TLRPC.TL_document)) { params = new HashMap<>(); - params.put("parentObject", "sent_" + messageObject.messageOwner.peer_id.channel_id + "_" + messageObject.getId() + "_" + messageObject.getDialogId() + "_" + messageObject.type); + params.put("parentObject", "sent_" + messageObject.messageOwner.peer_id.channel_id + "_" + messageObject.getId() + "_" + messageObject.getDialogId() + "_" + messageObject.type + "_" + messageObject.getSize()); } if (messageObject.messageOwner.media.photo instanceof TLRPC.TL_photo) { sendMessage((TLRPC.TL_photo) messageObject.messageOwner.media.photo, null, did, messageObject.replyMessageObject, null, messageObject.messageOwner.message, messageObject.messageOwner.entities, null, params, true, 0, messageObject.messageOwner.media.ttl_seconds, messageObject, false); @@ -1674,10 +1675,14 @@ public int sendMessage(ArrayList messages, final long peer, boole final TLRPC.Peer peer_id = getMessagesController().getPeer(peer); boolean isSignature = false; boolean canSendStickers = true; - boolean canSendMedia = true; + boolean canSendPhoto = true; + boolean canSendVideo = true; + boolean canSendDocument = true; + boolean canSendMusic = true; boolean canSendPolls = true; boolean canSendPreview = true; boolean canSendVoiceMessages = true; + boolean canSendVoiceRound = true; String rank = null; long linkedToGroup = 0; TLRPC.Chat chat; @@ -1690,7 +1695,7 @@ public int sendMessage(ArrayList messages, final long peer, boole TLRPC.UserFull userFull = getMessagesController().getUserFull(peer); if (userFull != null) { - canSendVoiceMessages = !userFull.voice_messages_forbidden; + canSendVoiceRound = canSendVoiceMessages = !userFull.voice_messages_forbidden; } } else { chat = getMessagesController().getChat(-peer); @@ -1709,9 +1714,14 @@ public int sendMessage(ArrayList messages, final long peer, boole rank = getMessagesController().getAdminRank(chat.id, myId); } canSendStickers = ChatObject.canSendStickers(chat); - canSendMedia = ChatObject.canSendMedia(chat); + canSendPhoto = ChatObject.canSendPhoto(chat); + canSendVideo = ChatObject.canSendVideo(chat); + canSendDocument = ChatObject.canSendDocument(chat); canSendPreview = ChatObject.canSendEmbed(chat); canSendPolls = ChatObject.canSendPolls(chat); + canSendVoiceRound = ChatObject.canSendRoundVideo(chat); + canSendVoiceMessages = ChatObject.canSendVoice(chat); + canSendMusic = ChatObject.canSendMusic(chat); } LongSparseArray groupsMap = new LongSparseArray<>(); @@ -1739,9 +1749,19 @@ public int sendMessage(ArrayList messages, final long peer, boole sendResult = ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_STICKERS) ? 4 : 1; } continue; - } else if (!canSendMedia && (msgObj.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto || msgObj.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) && !mediaIsSticker) { + } else if (!canSendPhoto && msgObj.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && !msgObj.isVideo() && !mediaIsSticker) { if (sendResult == 0) { - sendResult = ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_MEDIA) ? 5 : 2; + sendResult = ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_PHOTO) ? 10 : 12; + } + continue; + } else if (!canSendMusic && msgObj.isMusic()) { + if (sendResult == 0) { + sendResult = ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_MUSIC) ? 19 : 20; + } + continue; + } else if (!canSendVideo && msgObj.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && msgObj.isVideo() && !mediaIsSticker) { + if (sendResult == 0) { + sendResult = ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_VIDEO) ? 9 : 11; } continue; } else if (!canSendPolls && msgObj.messageOwner.media instanceof TLRPC.TL_messageMediaPoll) { @@ -1750,13 +1770,30 @@ public int sendMessage(ArrayList messages, final long peer, boole } continue; } else if (!canSendVoiceMessages && MessageObject.isVoiceMessage(msgObj.messageOwner)) { - if (sendResult == 0) { - sendResult = 7; + if (chat != null) { + if (sendResult == 0) { + sendResult = ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_VOICE) ? 13 : 14; + } + } else { + if (sendResult == 0) { + sendResult = 7; + } } continue; - } else if (!canSendVoiceMessages && MessageObject.isRoundVideoMessage(msgObj.messageOwner)) { + } else if (!canSendVoiceRound && MessageObject.isRoundVideoMessage(msgObj.messageOwner)) { + if (chat != null) { + if (sendResult == 0) { + sendResult = ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_ROUND) ? 15 : 16; + } + } else { + if (sendResult == 0) { + sendResult = 8; + } + } + continue; + } else if (!canSendDocument && msgObj.messageOwner.media instanceof TLRPC.TL_messageMediaDocument && !mediaIsSticker) { if (sendResult == 0) { - sendResult = 8; + sendResult = ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_DOCUMENTS) ? 17 : 18; } continue; } @@ -2220,6 +2257,38 @@ public int sendMessage(ArrayList messages, final long peer, boole return sendResult; } + public static int canSendMessageToChat(TLRPC.Chat chat, MessageObject msgObj) { + boolean canSendStickers = ChatObject.canSendStickers(chat); + boolean canSendPhoto = ChatObject.canSendPhoto(chat); + boolean canSendVideo = ChatObject.canSendVideo(chat); + boolean canSendDocument = ChatObject.canSendDocument(chat); + boolean canSendPreview = ChatObject.canSendEmbed(chat); + boolean canSendPolls = ChatObject.canSendPolls(chat); + boolean canSendVoiceRound = ChatObject.canSendRoundVideo(chat); + boolean canSendVoiceMessages = ChatObject.canSendVoice(chat); + boolean canSendMusic = ChatObject.canSendMusic(chat); + + boolean mediaIsSticker = (msgObj.isSticker() || msgObj.isAnimatedSticker() || msgObj.isGif() || msgObj.isGame()); + if (!canSendStickers && mediaIsSticker) { + return ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_STICKERS) ? 4 : 1; + } else if (!canSendPhoto && msgObj.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && !msgObj.isVideo() && !mediaIsSticker) { + return ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_PHOTO) ? 10 : 12; + } else if (!canSendMusic && msgObj.isMusic()) { + return ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_MUSIC) ? 19 : 20; + } else if (!canSendVideo && msgObj.isVideo() && !mediaIsSticker) { + return ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_VIDEO) ? 9 : 11; + } else if (!canSendPolls && msgObj.messageOwner.media instanceof TLRPC.TL_messageMediaPoll) { + return ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_POLLS) ? 6 : 3; + } else if (!canSendVoiceMessages && MessageObject.isVoiceMessage(msgObj.messageOwner)) { + return ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_VOICE) ? 13 : 14; + } else if (!canSendVoiceRound && MessageObject.isRoundVideoMessage(msgObj.messageOwner)) { + return ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_ROUND) ? 15 : 16; + } else if (!canSendDocument && msgObj.messageOwner.media instanceof TLRPC.TL_messageMediaDocument && !mediaIsSticker) { + return ChatObject.isActionBannedByDefault(chat, ChatObject.ACTION_SEND_DOCUMENTS) ? 17 : 18; + } + return 0; + } + private void writePreviousMessageData(TLRPC.Message message, SerializedData data) { if (message.media == null) { TLRPC.TL_messageMediaEmpty media = new TLRPC.TL_messageMediaEmpty(); @@ -5822,7 +5891,7 @@ private void updateMediaPaths(MessageObject newMsgObj, TLRPC.Message sentMessage } if (sentMessage.media instanceof TLRPC.TL_messageMediaPhoto && sentMessage.media.photo != null && newMsg.media instanceof TLRPC.TL_messageMediaPhoto && newMsg.media.photo != null) { if (sentMessage.media.ttl_seconds == 0 && !newMsgObj.scheduled) { - getMessagesStorage().putSentFile(originalPath, sentMessage.media.photo, 0, "sent_" + sentMessage.peer_id.channel_id + "_" + sentMessage.id + "_" + DialogObject.getPeerDialogId(sentMessage.peer_id) + "_" + MessageObject.TYPE_PHOTO); + getMessagesStorage().putSentFile(originalPath, sentMessage.media.photo, 0, "sent_" + sentMessage.peer_id.channel_id + "_" + sentMessage.id + "_" + DialogObject.getPeerDialogId(sentMessage.peer_id) + "_" + MessageObject.TYPE_PHOTO + "_" + newMsgObj.getSize()); } if (newMsg.media.photo.sizes.size() == 1 && newMsg.media.photo.sizes.get(0).location instanceof TLRPC.TL_fileLocationUnavailable) { @@ -5883,14 +5952,14 @@ private void updateMediaPaths(MessageObject newMsgObj, TLRPC.Message sentMessage if ((isVideo || MessageObject.isGifMessage(sentMessage)) && MessageObject.isGifDocument(sentMessage.media.document) == MessageObject.isGifDocument(newMsg.media.document)) { if (!newMsgObj.scheduled) { MessageObject messageObject = new MessageObject(currentAccount, sentMessage, false, false); - getMessagesStorage().putSentFile(originalPath, sentMessage.media.document, 2, "sent_" + sentMessage.peer_id.channel_id + "_" + sentMessage.id + "_" + DialogObject.getPeerDialogId(sentMessage.peer_id) + "_" + messageObject.type); + getMessagesStorage().putSentFile(originalPath, sentMessage.media.document, 2, "sent_" + sentMessage.peer_id.channel_id + "_" + sentMessage.id + "_" + DialogObject.getPeerDialogId(sentMessage.peer_id) + "_" + messageObject.type + "_" + messageObject.getSize()); } if (isVideo) { sentMessage.attachPath = newMsg.attachPath; } } else if (!MessageObject.isVoiceMessage(sentMessage) && !MessageObject.isRoundVideoMessage(sentMessage) && !newMsgObj.scheduled) { MessageObject messageObject = new MessageObject(currentAccount, sentMessage, false, false); - getMessagesStorage().putSentFile(originalPath, sentMessage.media.document, 1, "sent_" + sentMessage.peer_id.channel_id + "_" + sentMessage.id + "_" + DialogObject.getPeerDialogId(sentMessage.peer_id) + "_" + messageObject.type); + getMessagesStorage().putSentFile(originalPath, sentMessage.media.document, 1, "sent_" + sentMessage.peer_id.channel_id + "_" + sentMessage.id + "_" + DialogObject.getPeerDialogId(sentMessage.peer_id) + "_" + messageObject.type + "_" + messageObject.getSize()); } } @@ -7144,6 +7213,7 @@ public static void prepareSendingText(AccountInstance accountInstance, String te TLRPC.TL_forumTopic topic = accountInstance.getMessagesController().getTopicsController().findTopic(-dialogId, topicId); if (topic != null && topic.topicStartMessage != null) { replyToMsg = new MessageObject(accountInstance.getCurrentAccount(), topic.topicStartMessage, false, false); + replyToMsg.isTopicMainMessage = true; } } for (int a = 0; a < count; a++) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java index 2384918ee9b..782480a6bdf 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java @@ -41,9 +41,16 @@ import java.util.Collections; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Locale; public class SharedConfig { + /** + * V2: Ping and check time serialized + */ + private final static int PROXY_SCHEMA_V2 = 2; + private final static int PROXY_CURRENT_SCHEMA_VERSION = PROXY_SCHEMA_V2; + public final static int PASSCODE_TYPE_PIN = 0, PASSCODE_TYPE_PASSWORD = 1; @@ -125,7 +132,7 @@ public static boolean loopStickers() { private static final Object sync = new Object(); private static final Object localIdSync = new Object(); - public static int saveToGalleryFlags; +// public static int saveToGalleryFlags; public static int mapPreviewType = 2; public static boolean chatBubbles = Build.VERSION.SDK_INT >= 30; public static boolean autoplayGifs = true; @@ -142,7 +149,7 @@ public static boolean loopStickers() { public static boolean streamMkv = false; public static boolean saveStreamMedia = true; public static boolean smoothKeyboard = true; - public static boolean pauseMusicOnRecord = true; + public static boolean pauseMusicOnRecord = false; public static boolean chatBlur = true; public static boolean noiseSupression; public static boolean noStatusBar = true; @@ -161,6 +168,8 @@ public static boolean loopStickers() { public static boolean fontSizeIsDefault; public static int bubbleRadius = 17; public static int ivFontSize = 16; + public static boolean proxyRotationEnabled; + public static int proxyRotationTimeout; public static int messageSeenHintCount; public static int emojiInteractionsHintCount; public static int dayNightThemeSwitchHintCount; @@ -184,6 +193,8 @@ public static boolean loopStickers() { public static int fastScrollHintCount = 3; public static boolean dontAskManageStorage; + public static boolean translateChats = true; + public static boolean isFloatingDebugActive; public static LiteMode liteMode; @@ -205,23 +216,23 @@ public static class ProxyInfo { public boolean available; public long availableCheckTime; - public ProxyInfo(String a, int p, String u, String pw, String s) { - address = a; - port = p; - username = u; - password = pw; - secret = s; - if (address == null) { - address = ""; + public ProxyInfo(String address, int port, String username, String password, String secret) { + this.address = address; + this.port = port; + this.username = username; + this.password = password; + this.secret = secret; + if (this.address == null) { + this.address = ""; } - if (password == null) { - password = ""; + if (this.password == null) { + this.password = ""; } - if (username == null) { - username = ""; + if (this.username == null) { + this.username = ""; } - if (secret == null) { - secret = ""; + if (this.secret == null) { + this.secret = ""; } } @@ -279,6 +290,8 @@ public static void saveConfig() { editor.putBoolean("forwardingOptionsHintShown", forwardingOptionsHintShown); editor.putInt("lockRecordAudioVideoHint", lockRecordAudioVideoHint); editor.putString("storageCacheDir", !TextUtils.isEmpty(storageCacheDir) ? storageCacheDir : ""); + editor.putBoolean("proxyRotationEnabled", proxyRotationEnabled); + editor.putInt("proxyRotationTimeout", proxyRotationTimeout); if (pendingAppUpdate != null) { try { @@ -302,6 +315,7 @@ public static void saveConfig() { editor.putBoolean("hasEmailLogin", hasEmailLogin); editor.putBoolean("useLNavigation", useLNavigation); editor.putBoolean("floatingDebugActive", isFloatingDebugActive); + editor.putBoolean("record_via_sco", recordViaSco); editor.apply(); } catch (Exception e) { FileLog.e(e); @@ -345,6 +359,8 @@ public static void loadConfig() { passportConfigJson = preferences.getString("passportConfigJson", ""); passportConfigHash = preferences.getInt("passportConfigHash", 0); storageCacheDir = preferences.getString("storageCacheDir", null); + proxyRotationEnabled = preferences.getBoolean("proxyRotationEnabled", false); + proxyRotationTimeout = preferences.getInt("proxyRotationTimeout", ProxyRotationController.DEFAULT_TIMEOUT_INDEX); String authKeyString = preferences.getString("pushAuthKey", null); if (!TextUtils.isEmpty(authKeyString)) { pushAuthKey = Base64.decode(authKeyString, Base64.DEFAULT); @@ -399,13 +415,7 @@ public static void loadConfig() { } preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); - boolean saveToGalleryLegacy = preferences.getBoolean("save_gallery", false); - if (saveToGalleryLegacy && BuildVars.NO_SCOPED_STORAGE) { - saveToGalleryFlags = SAVE_TO_GALLERY_FLAG_PEER + SAVE_TO_GALLERY_FLAG_CHANNELS + SAVE_TO_GALLERY_FLAG_GROUP; - preferences.edit().remove("save_gallery").putInt("save_gallery_flags", saveToGalleryFlags).apply(); - } else { - saveToGalleryFlags = preferences.getInt("save_gallery_flags", 0); - } + SaveToGallerySettingsHelper.load(preferences); autoplayGifs = preferences.getBoolean("autoplay_gif", true); autoplayVideo = preferences.getBoolean("autoplay_video", true); mapPreviewType = preferences.getInt("mapPreviewType", 2); @@ -1036,17 +1046,17 @@ public static void setRepeatMode(int mode) { } public static void toggleSaveToGalleryFlag(int flag) { - if ((saveToGalleryFlags & flag) != 0) { - saveToGalleryFlags &= ~flag; - } else { - saveToGalleryFlags |= flag; - } - SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - preferences.edit().putInt("save_gallery_flags", saveToGalleryFlags).apply(); - ImageLoader.getInstance().checkMediaPaths(); - ImageLoader.getInstance().getCacheOutQueue().postRunnable(() -> { - checkSaveToGalleryFiles(); - }); +// if ((saveToGalleryFlags & flag) != 0) { +// saveToGalleryFlags &= ~flag; +// } else { +// saveToGalleryFlags |= flag; +// } +// SharedPreferences preferences = MessagesController.getGlobalMainSettings(); +// preferences.edit().putInt("save_gallery_flags", saveToGalleryFlags).apply(); +// ImageLoader.getInstance().checkMediaPaths(); +// ImageLoader.getInstance().getCacheOutQueue().postRunnable(() -> { +// checkSaveToGalleryFiles(); +// }); } public static void toggleAutoplayGifs() { @@ -1256,17 +1266,46 @@ public static void loadProxyList() { byte[] bytes = Base64.decode(list, Base64.DEFAULT); SerializedData data = new SerializedData(bytes); int count = data.readInt32(false); - for (int a = 0; a < count; a++) { - ProxyInfo info = new ProxyInfo( - data.readString(false), - data.readInt32(false), - data.readString(false), - data.readString(false), - data.readString(false)); - proxyList.add(info); - if (currentProxy == null && !TextUtils.isEmpty(proxyAddress)) { - if (proxyAddress.equals(info.address) && proxyPort == info.port && proxyUsername.equals(info.username) && proxyPassword.equals(info.password)) { - currentProxy = info; + if (count == -1) { // V2 or newer + int version = data.readByte(false); + + if (version == PROXY_SCHEMA_V2) { + count = data.readInt32(false); + + for (int i = 0; i < count; i++) { + ProxyInfo info = new ProxyInfo( + data.readString(false), + data.readInt32(false), + data.readString(false), + data.readString(false), + data.readString(false)); + + info.ping = data.readInt64(false); + info.availableCheckTime = data.readInt64(false); + + proxyList.add(info); + if (currentProxy == null && !TextUtils.isEmpty(proxyAddress)) { + if (proxyAddress.equals(info.address) && proxyPort == info.port && proxyUsername.equals(info.username) && proxyPassword.equals(info.password)) { + currentProxy = info; + } + } + } + } else { + FileLog.e("Unknown proxy schema version: " + version); + } + } else { + for (int a = 0; a < count; a++) { + ProxyInfo info = new ProxyInfo( + data.readString(false), + data.readInt32(false), + data.readString(false), + data.readString(false), + data.readString(false)); + proxyList.add(info); + if (currentProxy == null && !TextUtils.isEmpty(proxyAddress)) { + if (proxyAddress.equals(info.address) && proxyPort == info.port && proxyUsername.equals(info.username) && proxyPassword.equals(info.password)) { + currentProxy = info; + } } } } @@ -1279,16 +1318,33 @@ public static void loadProxyList() { } public static void saveProxyList() { + List infoToSerialize = new ArrayList<>(proxyList); + Collections.sort(infoToSerialize, (o1, o2) -> { + long bias1 = SharedConfig.currentProxy == o1 ? -200000 : 0; + if (!o1.available) { + bias1 += 100000; + } + long bias2 = SharedConfig.currentProxy == o2 ? -200000 : 0; + if (!o2.available) { + bias2 += 100000; + } + return Long.compare(o1.ping + bias1, o2.ping + bias2); + }); SerializedData serializedData = new SerializedData(); - int count = proxyList.size(); + serializedData.writeInt32(-1); + serializedData.writeByte(PROXY_CURRENT_SCHEMA_VERSION); + int count = infoToSerialize.size(); serializedData.writeInt32(count); for (int a = 0; a < count; a++) { - ProxyInfo info = proxyList.get(a); + ProxyInfo info = infoToSerialize.get(a); serializedData.writeString(info.address != null ? info.address : ""); serializedData.writeInt32(info.port); serializedData.writeString(info.username != null ? info.username : ""); serializedData.writeString(info.password != null ? info.password : ""); serializedData.writeString(info.secret != null ? info.secret : ""); + + serializedData.writeInt64(info.ping); + serializedData.writeInt64(info.availableCheckTime); } SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); preferences.edit().putString("proxy_list", Base64.encodeToString(serializedData.toByteArray(), Base64.NO_WRAP)).commit(); @@ -1309,6 +1365,10 @@ public static ProxyInfo addProxy(ProxyInfo proxyInfo) { return proxyInfo; } + public static boolean isProxyEnabled() { + return MessagesController.getGlobalMainSettings().getBoolean("proxy_enabled", false) && currentProxy != null; + } + public static void deleteProxy(ProxyInfo proxyInfo) { if (currentProxy == proxyInfo) { currentProxy = null; @@ -1340,7 +1400,7 @@ public static void checkSaveToGalleryFiles() { File videoPath = new File(telegramPath, "Telegram Video"); videoPath.mkdir(); - if (saveToGalleryFlags != 0 || !BuildVars.NO_SCOPED_STORAGE) { + if (!BuildVars.NO_SCOPED_STORAGE) { if (imagePath.isDirectory()) { new File(imagePath, ".nomedia").delete(); } @@ -1484,6 +1544,14 @@ public static long getLastCheckedBackgroundActivity() { public static void setLastCheckedBackgroundActivity(long l) { prefs.edit().putLong("last_checked", l).apply(); } + + public static int getDismissedCount() { + return prefs.getInt("dismissed_count", 0); + } + + public static void increaseDismissedCount() { + prefs.edit().putInt("dismissed_count", getDismissedCount() + 1).apply(); + } } private static Boolean animationsEnabled; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/StatsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/StatsController.java index 6b681510ee7..8e33394cb86 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/StatsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/StatsController.java @@ -27,7 +27,9 @@ public class StatsController extends BaseController { public static final int TYPE_PHOTOS = 4; public static final int TYPE_FILES = 5; public static final int TYPE_TOTAL = 6; - private static final int TYPES_COUNT = 7; + public static final int TYPE_MUSIC = 7; + private static final int OLD_TYPES_COUNT = 7; + private static final int TYPES_COUNT = 8; private byte[] buffer = new byte[8]; @@ -87,7 +89,7 @@ public void run() { try { statsFile.seek(0); for (int a = 0; a < 3; a++) { - for (int b = 0; b < TYPES_COUNT; b++) { + for (int b = 0; b < OLD_TYPES_COUNT; b++) { statsFile.write(longToBytes(sentBytes[a][b]), 0, 8); statsFile.write(longToBytes(receivedBytes[a][b]), 0, 8); statsFile.write(intToBytes(sentItems[a][b]), 0, 4); @@ -96,6 +98,14 @@ public void run() { statsFile.write(intToBytes(callsTotalTime[a]), 0, 4); statsFile.write(longToBytes(resetStatsDate[a]), 0, 8); } + for (int b = OLD_TYPES_COUNT; b < TYPES_COUNT; ++b) { + for (int a = 0; a < 3; ++a) { + statsFile.write(longToBytes(sentBytes[a][b]), 0, 8); + statsFile.write(longToBytes(receivedBytes[a][b]), 0, 8); + statsFile.write(intToBytes(sentItems[a][b]), 0, 4); + statsFile.write(intToBytes(receivedItems[a][b]), 0, 4); + } + } statsFile.getFD().sync(); } catch (Exception ignore) { @@ -132,7 +142,7 @@ private StatsController(int account) { if (statsFile.length() > 0) { boolean save = false; for (int a = 0; a < 3; a++) { - for (int b = 0; b < TYPES_COUNT; b++) { + for (int b = 0; b < OLD_TYPES_COUNT; b++) { statsFile.readFully(buffer, 0, 8); sentBytes[a][b] = bytesToLong(buffer); statsFile.readFully(buffer, 0, 8); @@ -151,6 +161,18 @@ private StatsController(int account) { resetStatsDate[a] = System.currentTimeMillis(); } } + for (int b = OLD_TYPES_COUNT; b < TYPES_COUNT; ++b) { + for (int a = 0; a < 3; ++a) { + statsFile.readFully(buffer, 0, 8); + sentBytes[a][b] = bytesToLong(buffer); + statsFile.readFully(buffer, 0, 8); + receivedBytes[a][b] = bytesToLong(buffer); + statsFile.readFully(buffer, 0, 4); + sentItems[a][b] = bytesToInt(buffer); + statsFile.readFully(buffer, 0, 4); + receivedItems[a][b] = bytesToInt(buffer); + } + } if (save) { saveStats(); } @@ -222,14 +244,14 @@ public int getSentItemsCount(int networkType, int dataType) { public long getSentBytesCount(int networkType, int dataType) { if (dataType == TYPE_MESSAGES) { - return sentBytes[networkType][TYPE_TOTAL] - sentBytes[networkType][TYPE_FILES] - sentBytes[networkType][TYPE_AUDIOS] - sentBytes[networkType][TYPE_VIDEOS] - sentBytes[networkType][TYPE_PHOTOS]; + return sentBytes[networkType][TYPE_TOTAL] - sentBytes[networkType][TYPE_FILES] - sentBytes[networkType][TYPE_AUDIOS] - sentBytes[networkType][TYPE_VIDEOS] - sentBytes[networkType][TYPE_PHOTOS] - sentBytes[networkType][TYPE_MUSIC]; } return sentBytes[networkType][dataType]; } public long getReceivedBytesCount(int networkType, int dataType) { if (dataType == TYPE_MESSAGES) { - return receivedBytes[networkType][TYPE_TOTAL] - receivedBytes[networkType][TYPE_FILES] - receivedBytes[networkType][TYPE_AUDIOS] - receivedBytes[networkType][TYPE_VIDEOS] - receivedBytes[networkType][TYPE_PHOTOS]; + return receivedBytes[networkType][TYPE_TOTAL] - receivedBytes[networkType][TYPE_FILES] - receivedBytes[networkType][TYPE_AUDIOS] - receivedBytes[networkType][TYPE_VIDEOS] - receivedBytes[networkType][TYPE_PHOTOS] - receivedBytes[networkType][TYPE_MUSIC]; } return receivedBytes[networkType][dataType]; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java index 92841bb4a29..54a95735685 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java @@ -204,10 +204,8 @@ public void processTopics(long chatId, ArrayList newTopics, } } - - if (topicsToReload != null && loadType != LOAD_TYPE_LOAD_UNKNOWN) { - reloadTopics(chatId, topicsToReload); + reloadTopics(chatId, topicsToReload, null); } else if (((loadType == LOAD_TYPE_PRELOAD && !fromCache) || loadType == LOAD_TYPE_LOAD_NEXT) && topics.size() >= totalCount && totalCount >= 0) { endIsReached.put(chatId, 1); getUserConfig().getPreferences().edit().putBoolean("topics_end_reached_" + chatId, true).apply(); @@ -244,7 +242,6 @@ public void sortTopics(long chatId, boolean notify) { ArrayList topics = topicsByChatId.get(chatId); if (topics != null) { if (openedTopicsBuChatId.get(chatId, 0) > 0) { -// Comparator.comparingInt(o -> o.topMessage == null ? Integer.MAX_VALUE : -(o.pinned ? Integer.MAX_VALUE - o.pinnedOrder : o.topMessage.date)) Collections.sort(topics, (a, b) -> { if (a.hidden != b.hidden) { return a.hidden ? -1 : 1; @@ -351,7 +348,7 @@ public void updateTopicsWithDeletedMessages(long dialogId, ArrayList me sortTopics(chatId); } if (topicsToReload != null) { - reloadTopics(chatId, topicsToReload); + reloadTopics(chatId, topicsToReload, null); } }); } @@ -359,7 +356,7 @@ public void updateTopicsWithDeletedMessages(long dialogId, ArrayList me }); } - private void reloadTopics(long chatId, ArrayList topicsToReload) { + public void reloadTopics(long chatId, ArrayList topicsToReload, Runnable callback) { TLRPC.TL_channels_getForumTopicsByID req = new TLRPC.TL_channels_getForumTopicsByID(); for (int i = 0; i < topicsToReload.size(); i++) { req.topics.add(topicsToReload.get(i).id); @@ -379,6 +376,9 @@ private void reloadTopics(long chatId, ArrayList topicsToRe processTopics(chatId, topics.topics, messagesMap, false, LOAD_TYPE_LOAD_UNKNOWN, -1); getMessagesStorage().putMessages(topics.messages, false, true, false, 0, false, 0); getMessagesStorage().saveTopics(-chatId, topicsByChatId.get(chatId), true, true); + if (callback != null) { + callback.run(); + } }); } })); @@ -820,7 +820,7 @@ public void processUpdate(List topicUpdates) { for (int i = 0; i < topicsToReload.size(); i++) { long dialogId = topicsToReload.keyAt(i); ArrayList topics = topicsToReload.valueAt(i); - reloadTopics(-dialogId, topics); + reloadTopics(-dialogId, topics, null); } } @@ -872,14 +872,9 @@ public void reloadTopics(long chatId, boolean fromCache) { endIsReached.delete(chatId); clearLoadingOffset(chatId); - TLRPC.Chat chat = getMessagesController().getChat(chatId); if (chat != null && chat.forum) { - if (fromCache) { - preloadTopics(chatId); - } else { - loadTopics(chatId, false, LOAD_TYPE_PRELOAD); - } + loadTopics(chatId, fromCache, LOAD_TYPE_PRELOAD); } sortTopics(chatId); }); @@ -979,6 +974,27 @@ public void processEditedMessage(TLRPC.Message newMsg) { } } + public void loadTopic(long chatId, int topicId, Runnable runnable) { + getMessagesStorage().loadTopics(-chatId, topics -> { + AndroidUtilities.runOnUIThread(() -> { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("loaded from cache " + chatId + " topics_count=" + (topics == null ? 0 : topics.size())); + } + + processTopics(chatId, topics, null, true, LOAD_TYPE_PRELOAD, -1); + sortTopics(chatId); + if (findTopic(chatId, topicId) != null) { + runnable.run(); + } else { + ArrayList topicToReload = new ArrayList<>(); + TLRPC.TL_forumTopic topic = new TLRPC.TL_forumTopic(); + topic.id = topicId; + reloadTopics(chatId, topicToReload, runnable); + } + }); + }); + } + private class TopicsLoadOffset { int lastMessageId; int lastMessageDate; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TranslateController.java b/TMessagesProj/src/main/java/org/telegram/messenger/TranslateController.java new file mode 100644 index 00000000000..a9e721ede20 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TranslateController.java @@ -0,0 +1,980 @@ +package org.telegram.messenger; + +import android.content.Context; +import android.content.res.Resources; +import android.icu.text.Collator; +import android.text.TextUtils; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.InputMethodSubtype; + +import androidx.annotation.Nullable; + +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.Bulletin; +import org.telegram.ui.Components.TranslateAlert2; +import org.telegram.ui.RestrictedLanguagesSelectActivity; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.Set; + +public class TranslateController extends BaseController { + + public static final String UNKNOWN_LANGUAGE = "und"; + + private static final int REQUIRED_TOTAL_MESSAGES_CHECKED = 8; + private static final float REQUIRED_PERCENTAGE_MESSAGES_TRANSLATABLE = .60F; + private static final float REQUIRED_MIN_PERCENTAGE_MESSAGES_UNKNOWN = .65F; + + private static final int MAX_SYMBOLS_PER_REQUEST = 25000; + private static final int MAX_MESSAGES_PER_REQUEST = 20; + private static final int GROUPING_TRANSLATIONS_TIMEOUT = 200; + + private final Set translatingDialogs = new HashSet<>(); + private final Set translatableDialogs = new HashSet<>(); + private final HashMap translatableDialogMessages = new HashMap<>(); + private final HashMap translateDialogLanguage = new HashMap<>(); + private final HashMap detectedDialogLanguage = new HashMap<>(); + private final HashMap> keptReplyMessageObjects = new HashMap<>(); + private final Set hideTranslateDialogs = new HashSet<>(); + + class TranslatableDecision { + Set certainlyTranslatable = new HashSet<>(); + Set unknown = new HashSet<>(); + Set certainlyNotTranslatable = new HashSet<>(); + } + + private MessagesController messagesController; + + public TranslateController(MessagesController messagesController) { + super(messagesController.currentAccount); + this.messagesController = messagesController; + + AndroidUtilities.runOnUIThread(this::loadTranslatingDialogsCached, 150); + } + + public boolean isFeatureAvailable() { + return UserConfig.getInstance(currentAccount).isPremium() && isChatTranslateEnabled(); + } + + public boolean isChatTranslateEnabled() { + return MessagesController.getMainSettings(currentAccount).getBoolean("translate_chat_button", true); + } + + public boolean isContextTranslateEnabled() { + return MessagesController.getMainSettings(currentAccount).getBoolean("translate_button", MessagesController.getGlobalMainSettings().getBoolean("translate_button", false)); + } + + public void setContextTranslateEnabled(boolean enable) { + MessagesController.getMainSettings(currentAccount).edit().putBoolean("translate_button", enable).apply(); + } + + public static boolean isTranslatable(MessageObject messageObject) { + return ( + messageObject != null && messageObject.messageOwner != null && + !messageObject.isOutOwner() && + ( + messageObject.type == MessageObject.TYPE_TEXT || + messageObject.type == MessageObject.TYPE_VIDEO || + messageObject.type == MessageObject.TYPE_PHOTO || + messageObject.type == MessageObject.TYPE_VOICE || + messageObject.type == MessageObject.TYPE_FILE || + messageObject.type == MessageObject.TYPE_MUSIC + ) && !TextUtils.isEmpty(messageObject.messageOwner.message) + ); + } + + public boolean isDialogTranslatable(long dialogId) { + return ( + isFeatureAvailable() && + !DialogObject.isEncryptedDialog(dialogId) && + getUserConfig().getClientUserId() != dialogId && + /* DialogObject.isChatDialog(dialogId) &&*/ + translatableDialogs.contains(dialogId) + ); + } + + public boolean isTranslateDialogHidden(long dialogId) { + if (hideTranslateDialogs.contains(dialogId)) { + return true; + } + TLRPC.ChatFull chatFull = getMessagesController().getChatFull(-dialogId); + if (chatFull != null) { + return chatFull.translations_disabled; + } + TLRPC.UserFull userFull = getMessagesController().getUserFull(dialogId); + if (userFull != null) { + return userFull.translations_disabled; + } + return false; + } + + public boolean isTranslatingDialog(long dialogId) { + return isFeatureAvailable() && translatingDialogs.contains(dialogId); + } + + public void toggleTranslatingDialog(long dialogId) { + toggleTranslatingDialog(dialogId, !isTranslatingDialog(dialogId)); + } + + public boolean toggleTranslatingDialog(long dialogId, boolean value) { + boolean currentValue = isTranslatingDialog(dialogId), notified = false; + if (value && !currentValue) { + translatingDialogs.add(dialogId); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogTranslate, dialogId, true); + notified = true; + } else if (!value && currentValue) { + translatingDialogs.remove((Long) dialogId); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogTranslate, dialogId, false); + cancelTranslations(dialogId); + notified = true; + } + saveTranslatingDialogsCache(); + return notified; + } + + private int hash(MessageObject messageObject) { + if (messageObject == null) { + return 0; + } + return Objects.hash(messageObject.getDialogId(), messageObject.getId()); + } + + private String currentLanguage() { + String lang = LocaleController.getInstance().getCurrentLocaleInfo().pluralLangCode; + if (lang != null) { + lang = lang.split("_")[0]; + } + return lang; + } + + public String getDialogTranslateTo(long dialogId) { + String lang = translateDialogLanguage.get(dialogId); + if (lang == null) { + lang = TranslateAlert2.getToLanguage(); + if (lang == null || lang.equals(getDialogDetectedLanguage(dialogId))) { + lang = currentLanguage(); + } + } + if ("nb".equals(lang)) { + lang = "no"; + } + return lang; + } + + public void setDialogTranslateTo(long dialogId, String language) { + if (TextUtils.equals(getDialogTranslateTo(dialogId), language)) { + return; + } + + boolean wasTranslating = isTranslatingDialog(dialogId); + + if (wasTranslating) { + AndroidUtilities.runOnUIThread(() -> { + synchronized (TranslateController.this) { + translateDialogLanguage.put(dialogId, language); + translatingDialogs.add(dialogId); + saveTranslatingDialogsCache(); + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogTranslate, dialogId, true); + }, 150); + } else { + synchronized (TranslateController.this) { + translateDialogLanguage.put(dialogId, language); + } + } + + cancelTranslations(dialogId); + synchronized (this) { + translatingDialogs.remove(dialogId); + } + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogTranslate, dialogId, false); + + TranslateAlert2.setToLanguage(language); + } + + public void updateDialogFull(long dialogId) { + if (!isFeatureAvailable() || !isDialogTranslatable(dialogId)) { + return; + } + + final boolean wasHidden = hideTranslateDialogs.contains(dialogId); + + boolean hidden = false; + TLRPC.ChatFull chatFull = getMessagesController().getChatFull(-dialogId); + if (chatFull != null) { + hidden = chatFull.translations_disabled; + } else { + TLRPC.UserFull userFull = getMessagesController().getUserFull(dialogId); + if (userFull != null) { + hidden = userFull.translations_disabled; + } + } + + synchronized (this) { + if (hidden) { + hideTranslateDialogs.add(dialogId); + } else { + hideTranslateDialogs.remove(dialogId); + } + } + + if (wasHidden != hidden) { + saveTranslatingDialogsCache(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogTranslate, dialogId, isTranslatingDialog(dialogId)); + } + } + + public void setHideTranslateDialog(long dialogId, boolean hide) { + setHideTranslateDialog(dialogId, hide, false); + } + + public void setHideTranslateDialog(long dialogId, boolean hide, boolean doNotNotify) { + TLRPC.TL_messages_togglePeerTranslations req = new TLRPC.TL_messages_togglePeerTranslations(); + req.peer = getMessagesController().getInputPeer(dialogId); + req.disabled = hide; + getConnectionsManager().sendRequest(req, null); + + TLRPC.ChatFull chatFull = getMessagesController().getChatFull(-dialogId); + if (chatFull != null) { + chatFull.translations_disabled = hide; + getMessagesStorage().updateChatInfo(chatFull, true); + } + TLRPC.UserFull userFull = getMessagesController().getUserFull(dialogId); + if (userFull != null) { + userFull.translations_disabled = hide; + getMessagesStorage().updateUserInfo(userFull, true); + } + + synchronized (this) { + if (hide) { + hideTranslateDialogs.add(dialogId); + } else { + hideTranslateDialogs.remove(dialogId); + } + } + saveTranslatingDialogsCache(); + + if (!doNotNotify) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogTranslate, dialogId, isTranslatingDialog(dialogId)); + } + } + + private static List languagesOrder = Arrays.asList( + "en", "ar", "zh", "fr", "de", "it", "ja", "ko", "pt", "ru", "es", "uk" + ); + + private static List allLanguages = Arrays.asList( + "af", "sq", "am", "ar", "hy", "az", "eu", "be", "bn", "bs", "bg", "ca", "ceb", "zh", "co", "hr", "cs", "da", "nl", "en", "eo", "et", "fi", "fr", "fy", "gl", "ka", "de", "el", "gu", "ht", "ha", "haw", "he", "iw", "hi", "hmn", "hu", "is", "ig", "id", "ga", "it", "ja", "jv", "kn", "kk", "km", "rw", "ko", "ku", "ky", "lo", "la", "lv", "lt", "lb", "mk", "mg", "ms", "ml", "mt", "mi", "mr", "mn", "my", "ne", "no", "ny", "or", "ps", "fa", "pl", "pt", "pa", "ro", "ru", "sm", "gd", "sr", "st", "sn", "sd", "si", "sk", "sl", "so", "es", "su", "sw", "sv", "tl", "tg", "ta", "tt", "te", "th", "tr", "tk", "uk", "ur", "ug", "uz", "vi", "cy", "xh", "yi", "yo", "zu" + ); + + public static class Language { + public String code; + public String displayName; + } + + public static ArrayList getLanguages() { + ArrayList result = new ArrayList<>(); + for (int i = 0; i < allLanguages.size(); ++i) { + Language language = new Language(); + language.code = allLanguages.get(i); + language.displayName = TranslateAlert2.capitalFirst(TranslateAlert2.languageName(language.code)); + if (language.displayName == null) { + continue; + } + result.add(language); + } + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + Collator collator = Collator.getInstance(Locale.getDefault()); + Collections.sort(result, (lng1, lng2) -> collator.compare(lng1.displayName, lng2.displayName)); + } else { + Collections.sort(result, Comparator.comparing(lng -> lng.displayName)); + } + return result; + } + + private static LinkedHashSet suggestedLanguageCodes = null; + public static void invalidateSuggestedLanguageCodes() { + suggestedLanguageCodes = null; + } + public static void analyzeSuggestedLanguageCodes() { + LinkedHashSet langs = new LinkedHashSet<>(); + try { + langs.add(LocaleController.getInstance().getCurrentLocaleInfo().pluralLangCode); + } catch (Exception e1) { + FileLog.e(e1); + } + try { + langs.add(Resources.getSystem().getConfiguration().locale.getLanguage()); + } catch (Exception e2) { + FileLog.e(e2); + } + try { + langs.addAll(RestrictedLanguagesSelectActivity.getRestrictedLanguages()); + } catch (Exception e3) { + FileLog.e(e3); + } + try { + InputMethodManager imm = (InputMethodManager) ApplicationLoader.applicationContext.getSystemService(Context.INPUT_METHOD_SERVICE); + List ims = imm.getEnabledInputMethodList(); + for (InputMethodInfo method : ims) { + List submethods = imm.getEnabledInputMethodSubtypeList(method, true); + for (InputMethodSubtype submethod : submethods) { + if ("keyboard".equals(submethod.getMode())) { + String currentLocale = submethod.getLocale(); + if (currentLocale != null && currentLocale.contains("_")) { + currentLocale = currentLocale.split("_")[0]; + } + if (TranslateAlert2.languageName(currentLocale) != null) { + langs.add(currentLocale); + } + } + } + } + } catch (Exception e4) { + FileLog.e(e4); + } + suggestedLanguageCodes = langs; + } + + public static ArrayList getSuggestedLanguages(String except) { + ArrayList result = new ArrayList<>(); + if (suggestedLanguageCodes == null) { + analyzeSuggestedLanguageCodes(); + if (suggestedLanguageCodes == null) { + return result; + } + } + Iterator i = suggestedLanguageCodes.iterator(); + while (i.hasNext()) { + final String code = i.next(); + if (TextUtils.equals(code, except) || "no".equals(except) && "nb".equals(code) || "nb".equals(except) && "no".equals(code)) { + continue; + } + Language language = new Language(); + language.code = code; + language.displayName = TranslateAlert2.capitalFirst(TranslateAlert2.languageName(language.code)); + if (language.displayName == null) { + continue; + } + result.add(language); + } + return result; + } + + public static ArrayList getLocales() { + HashMap languages = LocaleController.getInstance().languagesDict; + ArrayList locales = new ArrayList<>(languages.values()); + for (int i = 0; i < locales.size(); ++i) { + LocaleController.LocaleInfo locale = locales.get(i); + if (locale == null || locale.shortName != null && locale.shortName.endsWith("_raw") || !"remote".equals(locale.pathToFile)) { + locales.remove(i); + i--; + } + } + + final LocaleController.LocaleInfo currentLocale = LocaleController.getInstance().getCurrentLocaleInfo(); + Comparator comparator = (o, o2) -> { + if (o == currentLocale) { + return -1; + } else if (o2 == currentLocale) { + return 1; + } + final int index1 = languagesOrder.indexOf(o.pluralLangCode); + final int index2 = languagesOrder.indexOf(o2.pluralLangCode); + if (index1 >= 0 && index2 >= 0) { + return index1 - index2; + } else if (index1 >= 0) { + return -1; + } else if (index2 >= 0) { + return 1; + } + if (o.serverIndex == o2.serverIndex) { + return o.name.compareTo(o2.name); + } + if (o.serverIndex > o2.serverIndex) { + return 1; + } else if (o.serverIndex < o2.serverIndex) { + return -1; + } + return 0; + }; + Collections.sort(locales, comparator); + + return locales; + } + + public void checkRestrictedLanguagesUpdate() { + synchronized (this) { + translatableDialogMessages.clear(); + + ArrayList toNotify = new ArrayList<>(); + HashSet languages = RestrictedLanguagesSelectActivity.getRestrictedLanguages(); + for (long dialogId : translatableDialogs) { + String language = detectedDialogLanguage.get(dialogId); + if (language != null && languages.contains(language)) { + cancelTranslations(dialogId); + translatingDialogs.remove(dialogId); + toNotify.add(dialogId); + } + } + translatableDialogs.clear(); + saveTranslatingDialogsCache(); + + for (long dialogId : toNotify) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogTranslate, dialogId, false); + } + } + } + + @Nullable + public String getDialogDetectedLanguage(long dialogId) { + return detectedDialogLanguage.get(dialogId); + } + + public void checkTranslation(MessageObject messageObject, boolean onScreen) { + checkTranslation(messageObject, onScreen, false); + } + + private void checkTranslation(MessageObject messageObject, boolean onScreen, boolean keepReply) { + if (!isFeatureAvailable()) { + return; + } + if (messageObject == null || messageObject.messageOwner == null) { + return; + } + + long dialogId = messageObject.getDialogId(); + + if (!keepReply && messageObject.replyMessageObject != null) { + checkTranslation(messageObject.replyMessageObject, onScreen, true); + } + + if (!isTranslatable(messageObject)) { + return; + } + + if (!isTranslatingDialog(dialogId)) { + checkLanguage(messageObject); + return; + } + + final String language = getDialogTranslateTo(dialogId); + MessageObject potentialReplyMessageObject; + if (!keepReply && (messageObject.messageOwner.translatedText == null || !language.equals(messageObject.messageOwner.translatedToLanguage)) && (potentialReplyMessageObject = findReplyMessageObject(dialogId, messageObject.getId())) != null) { + messageObject.messageOwner.translatedToLanguage = potentialReplyMessageObject.messageOwner.translatedToLanguage; + messageObject.messageOwner.translatedText = potentialReplyMessageObject.messageOwner.translatedText; + messageObject = potentialReplyMessageObject; + } + + if (onScreen && isTranslatingDialog(dialogId)) { + final MessageObject finalMessageObject = messageObject; + if (finalMessageObject.messageOwner.translatedText == null || !language.equals(finalMessageObject.messageOwner.translatedToLanguage)) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageTranslating, finalMessageObject); + pushToTranslate(finalMessageObject, language, (text, lang) -> { + finalMessageObject.messageOwner.translatedToLanguage = lang; + finalMessageObject.messageOwner.translatedText = text; + if (keepReply) { + keepReplyMessage(finalMessageObject); + } + + getMessagesStorage().updateMessageCustomParams(dialogId, finalMessageObject.messageOwner); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageTranslated, finalMessageObject); + + ArrayList dialogMessages = messagesController.dialogMessage.get(dialogId); + if (dialogMessages != null) { + for (int i = 0; i < dialogMessages.size(); ++i) { + MessageObject dialogMessage = dialogMessages.get(i); + if (dialogMessage != null && dialogMessage.getId() == finalMessageObject.getId()) { + dialogMessage.messageOwner.translatedToLanguage = lang; + dialogMessage.messageOwner.translatedText = text; + if (dialogMessage.updateTranslation()) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, 0); + } + break; + } + } + } + }); + } else if (keepReply) { + keepReplyMessage(messageObject); + } + } + } + + public void invalidateTranslation(MessageObject messageObject) { + if (!isFeatureAvailable()) { + return; + } + if (messageObject == null || messageObject.messageOwner == null) { + return; + } + final long dialogId = messageObject.getDialogId(); + messageObject.messageOwner.translatedToLanguage = null; + messageObject.messageOwner.translatedText = null; + getMessagesStorage().updateMessageCustomParams(dialogId, messageObject.messageOwner); + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.messageTranslated, messageObject, isTranslatingDialog(dialogId)); + }); + } + + public void checkDialogMessages(long dialogId) { + if (!isFeatureAvailable()) { + return; + } + getMessagesStorage().getStorageQueue().postRunnable(() -> { + final ArrayList dialogMessages = messagesController.dialogMessage.get(dialogId); + if (dialogMessages == null) { + return; + } + ArrayList customProps = new ArrayList<>(); + for (int i = 0; i < dialogMessages.size(); ++i) { + MessageObject dialogMessage = dialogMessages.get(i); + if (dialogMessage == null || dialogMessage.messageOwner == null) { + customProps.add(null); + continue; + } + customProps.add(getMessagesStorage().getMessageWithCustomParamsOnlyInternal(dialogMessage.getId(), dialogMessage.getDialogId())); + } + AndroidUtilities.runOnUIThread(() -> { + boolean updated = false; + for (int i = 0; i < Math.min(customProps.size(), dialogMessages.size()); ++i) { + MessageObject dialogMessage = dialogMessages.get(i); + TLRPC.Message props = customProps.get(i); + if (dialogMessage == null || dialogMessage.messageOwner == null || props == null) { + continue; + } + dialogMessage.messageOwner.translatedText = props.translatedText; + dialogMessage.messageOwner.translatedToLanguage = props.translatedToLanguage; + if (dialogMessage.updateTranslation(false)) { + updated = true; + } + } + if (updated) { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, 0); + } + }); + }); + } + + + public void cleanup() { + cancelAllTranslations(); + resetTranslatingDialogsCache(); + + translatingDialogs.clear(); + translatableDialogs.clear(); + translatableDialogMessages.clear(); + translateDialogLanguage.clear(); + detectedDialogLanguage.clear(); + keptReplyMessageObjects.clear(); + hideTranslateDialogs.clear(); + loadingTranslations.clear(); + } + + private ArrayList pendingLanguageChecks = new ArrayList<>(); + private void checkLanguage(MessageObject messageObject) { + if (!LanguageDetector.hasSupport()) { + return; + } + if (!isTranslatable(messageObject) || messageObject.messageOwner == null || TextUtils.isEmpty(messageObject.messageOwner.message)) { + return; + } + if (messageObject.messageOwner.originalLanguage != null) { + checkDialogTranslatable(messageObject); + return; + } + + final long dialogId = messageObject.getDialogId(); + final int hash = hash(messageObject); + if (isDialogTranslatable(dialogId)) { + return; + } + if (pendingLanguageChecks.contains(hash)) { + return; + } + + pendingLanguageChecks.add(hash); + + LanguageDetector.detectLanguage(messageObject.messageOwner.message, lng -> AndroidUtilities.runOnUIThread(() -> { + String detectedLanguage = lng; + if (detectedLanguage == null) { + detectedLanguage = UNKNOWN_LANGUAGE; + } + messageObject.messageOwner.originalLanguage = detectedLanguage; + getMessagesStorage().updateMessageCustomParams(dialogId, messageObject.messageOwner); + pendingLanguageChecks.remove((Integer) hash); + checkDialogTranslatable(messageObject); + }), err -> AndroidUtilities.runOnUIThread(() -> { + messageObject.messageOwner.originalLanguage = UNKNOWN_LANGUAGE; + getMessagesStorage().updateMessageCustomParams(dialogId, messageObject.messageOwner); + pendingLanguageChecks.remove((Integer) hash); + })); + } + + private void checkDialogTranslatable(MessageObject messageObject) { + if (messageObject == null || messageObject.messageOwner == null) { + return; + } + + final long dialogId = messageObject.getDialogId(); + TranslatableDecision translatableMessages = translatableDialogMessages.get(dialogId); + if (translatableMessages == null) { + translatableDialogMessages.put(dialogId, translatableMessages = new TranslatableDecision()); + } + + final boolean isUnknown = isTranslatable(messageObject) && ( + messageObject.messageOwner.originalLanguage == null || + UNKNOWN_LANGUAGE.equals(messageObject.messageOwner.originalLanguage) + ); + final boolean translatable = ( + isTranslatable(messageObject) && + messageObject.messageOwner.originalLanguage != null && + !UNKNOWN_LANGUAGE.equals(messageObject.messageOwner.originalLanguage) && + !RestrictedLanguagesSelectActivity.getRestrictedLanguages().contains(messageObject.messageOwner.originalLanguage) && + !TextUtils.equals(getDialogTranslateTo(dialogId), messageObject.messageOwner.originalLanguage) + ); + + if (isUnknown) { + translatableMessages.unknown.add(messageObject.getId()); + } else { + (translatable ? translatableMessages.certainlyTranslatable : translatableMessages.certainlyNotTranslatable).add(messageObject.getId()); + } + + if (!isUnknown) { + detectedDialogLanguage.put(dialogId, messageObject.messageOwner.originalLanguage); + } + + final int translatableCount = translatableMessages.certainlyTranslatable.size(); + final int unknownCount = translatableMessages.unknown.size(); + final int notTranslatableCount = translatableMessages.certainlyNotTranslatable.size(); + final int totalCount = translatableCount + unknownCount + notTranslatableCount; + if ( + totalCount >= REQUIRED_TOTAL_MESSAGES_CHECKED && + (translatableCount / (float) (translatableCount + notTranslatableCount)) >= REQUIRED_PERCENTAGE_MESSAGES_TRANSLATABLE && + (unknownCount / (float) totalCount) < REQUIRED_MIN_PERCENTAGE_MESSAGES_UNKNOWN + ) { + translatableDialogs.add(dialogId); + translatableDialogMessages.remove((Long) dialogId); + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.dialogIsTranslatable, dialogId); + }, 450); + } + } + + private final Set loadingTranslations = new HashSet<>(); + private final HashMap> pendingTranslations = new HashMap<>(); + + private static class PendingTranslation { + Runnable runnable; + ArrayList messageIds = new ArrayList<>(); + ArrayList messageTexts = new ArrayList<>(); + ArrayList> callbacks = new ArrayList<>(); + String language; + + int symbolsCount; + + int reqId = -1; + } + + private void pushToTranslate( + MessageObject message, + String language, + Utilities.Callback2 callback + ) { + if (message == null || callback == null) { + return; + } + + long dialogId = message.getDialogId(); + + PendingTranslation pendingTranslation; + synchronized (this) { + ArrayList dialogPendingTranslations = pendingTranslations.get(dialogId); + if (dialogPendingTranslations == null) { + pendingTranslations.put(dialogId, dialogPendingTranslations = new ArrayList<>()); + } + + if (dialogPendingTranslations.isEmpty()) { + dialogPendingTranslations.add(pendingTranslation = new PendingTranslation()); + } else { + pendingTranslation = dialogPendingTranslations.get(dialogPendingTranslations.size() - 1); + } + + if (pendingTranslation.messageIds.contains(message.getId())) { + return; + } + + int messageSymbolsCount = 0; + if (message.messageOwner != null && message.messageOwner.message != null) { + messageSymbolsCount = message.messageOwner.message.length(); + } else if (message.caption != null) { + messageSymbolsCount = message.caption.length(); + } else if (message.messageText != null) { + messageSymbolsCount = message.messageText.length(); + } + + if (pendingTranslation.symbolsCount + messageSymbolsCount >= MAX_SYMBOLS_PER_REQUEST || + pendingTranslation.messageIds.size() + 1 >= MAX_MESSAGES_PER_REQUEST) { + dialogPendingTranslations.add(pendingTranslation = new PendingTranslation()); + } + + if (pendingTranslation.runnable != null) { + AndroidUtilities.cancelRunOnUIThread(pendingTranslation.runnable); + } + loadingTranslations.add(message.getId()); + pendingTranslation.messageIds.add(message.getId()); + TLRPC.TL_textWithEntities source = null; + if (message.messageOwner != null) { + source = new TLRPC.TL_textWithEntities(); + source.text = message.messageOwner.message; + source.entities = message.messageOwner.entities; + } + pendingTranslation.messageTexts.add(source); + pendingTranslation.callbacks.add(callback); + pendingTranslation.language = language; + pendingTranslation.symbolsCount += messageSymbolsCount; + final PendingTranslation pendingTranslation1 = pendingTranslation; + pendingTranslation.runnable = () -> { + synchronized (TranslateController.this) { + ArrayList dialogPendingTranslations1 = pendingTranslations.get(dialogId); + if (dialogPendingTranslations1 != null) { + dialogPendingTranslations1.remove(pendingTranslation1); + if (dialogPendingTranslations1.isEmpty()) { + pendingTranslations.remove(dialogId); + } + } + } + + TLRPC.TL_messages_translateText req = new TLRPC.TL_messages_translateText(); + req.flags |= 1; + req.peer = getMessagesController().getInputPeer(dialogId); + req.id = pendingTranslation1.messageIds; + req.to_lang = pendingTranslation1.language; + + final int reqId = getConnectionsManager().sendRequest(req, (res, err) -> AndroidUtilities.runOnUIThread(() -> { + final ArrayList ids; + final ArrayList> callbacks; + final ArrayList texts; + synchronized (TranslateController.this) { + ids = pendingTranslation1.messageIds; + callbacks = pendingTranslation1.callbacks; + texts = pendingTranslation1.messageTexts; + } + if (res instanceof TLRPC.TL_messages_translateResult) { + ArrayList translated = ((TLRPC.TL_messages_translateResult) res).result; + final int count = Math.min(callbacks.size(), translated.size()); + for (int i = 0; i < count; ++i) { + callbacks.get(i).run(TranslateAlert2.preprocess(texts.get(i), translated.get(i)), pendingTranslation1.language); + } + } else if (err != null && "TO_LANG_INVALID".equals(err.text)) { + toggleTranslatingDialog(dialogId, false); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_ERROR, LocaleController.getString("TranslationFailedAlert2", R.string.TranslationFailedAlert2)); + } else { + for (int i = 0; i < callbacks.size(); ++i) { + callbacks.get(i).run(null, pendingTranslation1.language); + } + } + synchronized (TranslateController.this) { + for (int i = 0; i < ids.size(); ++i) { + loadingTranslations.remove(ids.get(i)); + } + } + })); + synchronized (TranslateController.this) { + pendingTranslation1.reqId = reqId; + } + }; + AndroidUtilities.runOnUIThread(pendingTranslation.runnable, GROUPING_TRANSLATIONS_TIMEOUT); + } + } + + public boolean isTranslating(MessageObject messageObject) { + synchronized (this) { + return messageObject != null && isTranslatingDialog(messageObject.getDialogId()) && loadingTranslations.contains(messageObject.getId()); + } + } + + public boolean isTranslating(MessageObject messageObject, MessageObject.GroupedMessages group) { + if (messageObject == null) { + return false; + } + if (!isTranslatingDialog(messageObject.getDialogId())) { + return false; + } + synchronized (this) { + if (loadingTranslations.contains(messageObject.getId())) { + return true; + } + if (group != null) { + for (MessageObject message : group.messages) { + if (loadingTranslations.contains(message.getId())) { + return true; + } + } + } + } + return false; + } + + public void cancelAllTranslations() { + synchronized (this) { + for (ArrayList translations : pendingTranslations.values()) { + if (translations != null) { + for (PendingTranslation pendingTranslation : translations) { + AndroidUtilities.cancelRunOnUIThread(pendingTranslation.runnable); + if (pendingTranslation.reqId != -1) { + getConnectionsManager().cancelRequest(pendingTranslation.reqId, true); + for (Integer messageId : pendingTranslation.messageIds) { + loadingTranslations.remove(messageId); + } + } + } + } + } + } + } + + public void cancelTranslations(long dialogId) { + synchronized (this) { + ArrayList translations = pendingTranslations.get(dialogId); + if (translations != null) { + for (PendingTranslation pendingTranslation : translations) { + AndroidUtilities.cancelRunOnUIThread(pendingTranslation.runnable); + if (pendingTranslation.reqId != -1) { + getConnectionsManager().cancelRequest(pendingTranslation.reqId, true); + for (Integer messageId : pendingTranslation.messageIds) { + loadingTranslations.remove(messageId); + } + } + } + pendingTranslations.remove((Long) dialogId); + } + } + } + + private void keepReplyMessage(MessageObject messageObject) { + if (messageObject == null) { + return; + } + HashMap map = keptReplyMessageObjects.get(messageObject.getDialogId()); + if (map == null) { + keptReplyMessageObjects.put(messageObject.getDialogId(), map = new HashMap<>()); + } + map.put(messageObject.getId(), messageObject); + } + + public MessageObject findReplyMessageObject(long dialogId, int messageId) { + HashMap map = keptReplyMessageObjects.get(dialogId); + if (map == null) { + return null; + } + return map.get(messageId); + } + + private void clearAllKeptReplyMessages(long dialogId) { + keptReplyMessageObjects.remove(dialogId); + } + + + private void loadTranslatingDialogsCached() { + if (!isFeatureAvailable()) { + return; + } + + String translatingDialogsCache = messagesController.getMainSettings().getString("translating_dialog_languages2", null); + if (translatingDialogsCache == null) { + return; + } + String[] dialogs = translatingDialogsCache.split(";"); + + HashSet restricted = RestrictedLanguagesSelectActivity.getRestrictedLanguages(); + for (int i = 0; i < dialogs.length; ++i) { + String[] keyval = dialogs[i].split("="); + if (keyval.length < 2) { + continue; + } + long did = Long.parseLong(keyval[0]); + String[] langs = keyval[1].split(">"); + if (langs.length != 2) { + continue; + } + String from = langs[0], to = langs[1]; + if ("null".equals(from)) from = null; + if ("null".equals(to)) to = null; + if (from != null) { + detectedDialogLanguage.put(did, from); + if (!restricted.contains(from)) { + translatingDialogs.add(did); + translatableDialogs.add(did); + } + if (to != null) { + translateDialogLanguage.put(did, to); + } + } + } + + Set hidden = messagesController.getMainSettings().getStringSet("hidden_translation_at", null); + if (hidden != null) { + Iterator i = hidden.iterator(); + while (i.hasNext()) { + try { + hideTranslateDialogs.add(Long.parseLong(i.next())); + } catch (Exception e) { + FileLog.e(e); + } + } + } + } + + private void saveTranslatingDialogsCache() { + StringBuilder langset = new StringBuilder(); + Iterator i = translatingDialogs.iterator(); + boolean first = true; + while (i.hasNext()) { + try { + long did = i.next(); + if (!first) { + langset.append(";"); + } + if (first) { + first = false; + } + String lang = detectedDialogLanguage.get(did); + if (lang == null) { + lang = "null"; + } + String tolang = getDialogTranslateTo(did); + if (tolang == null) { + tolang = "null"; + } + langset.append(did).append("=").append(lang).append(">").append(tolang); + } catch (Exception e) {} + } + + Set hidden = new HashSet<>(); + i = hideTranslateDialogs.iterator(); + while (i.hasNext()) { + try { + hidden.add("" + i.next()); + } catch (Exception e) { + FileLog.e(e); + } + } + MessagesController.getMainSettings(currentAccount).edit().putString("translating_dialog_languages2", langset.toString()).putStringSet("hidden_translation_at", hidden).apply(); + } + + private void resetTranslatingDialogsCache() { + MessagesController.getMainSettings(currentAccount).edit().remove("translating_dialog_languages2").remove("hidden_translation_at").apply(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java index 253bdd2b145..ed023fc61e2 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java @@ -12,6 +12,9 @@ import android.content.SharedPreferences; import android.os.SystemClock; import android.util.Base64; +import android.util.LongSparseArray; +import android.util.SparseArray; +import android.util.SparseLongArray; import org.telegram.tgnet.SerializedData; import org.telegram.tgnet.TLRPC; @@ -78,6 +81,10 @@ public class UserConfig extends BaseController { public volatile byte[] savedPasswordHash; public volatile byte[] savedSaltedPassword; public volatile long savedPasswordTime; + LongSparseArray userSaveGalleryExceptions; + LongSparseArray chanelSaveGalleryExceptions; + LongSparseArray groupsSaveGalleryExceptions; + private static volatile UserConfig[] Instance = new UserConfig[UserConfig.MAX_ACCOUNT_COUNT]; public static UserConfig getInstance(int num) { @@ -415,6 +422,48 @@ public SharedPreferences getPreferences() { } } + public LongSparseArray getSaveGalleryExceptions(int type) { + if (type == SharedConfig.SAVE_TO_GALLERY_FLAG_PEER) { + if (userSaveGalleryExceptions == null) { + userSaveGalleryExceptions = SaveToGallerySettingsHelper.loadExceptions(ApplicationLoader.applicationContext.getSharedPreferences(SaveToGallerySettingsHelper.USERS_PREF_NAME + "_" + currentAccount, Context.MODE_PRIVATE)); + } + return userSaveGalleryExceptions; + } else if (type == SharedConfig.SAVE_TO_GALLERY_FLAG_GROUP) { + if (groupsSaveGalleryExceptions == null) { + groupsSaveGalleryExceptions = SaveToGallerySettingsHelper.loadExceptions(ApplicationLoader.applicationContext.getSharedPreferences(SaveToGallerySettingsHelper.GROUPS_PREF_NAME + "_" + currentAccount, Context.MODE_PRIVATE)); + } + return groupsSaveGalleryExceptions; + } else if (type == SharedConfig.SAVE_TO_GALLERY_FLAG_CHANNELS) { + if (chanelSaveGalleryExceptions == null) { + chanelSaveGalleryExceptions = SaveToGallerySettingsHelper.loadExceptions(ApplicationLoader.applicationContext.getSharedPreferences(SaveToGallerySettingsHelper.CHANNELS_PREF_NAME + "_" + currentAccount, Context.MODE_PRIVATE)); + } + return chanelSaveGalleryExceptions; + } + return null; + } + + public void updateSaveGalleryExceptions(int type, LongSparseArray exceptions) { + if (type == SharedConfig.SAVE_TO_GALLERY_FLAG_PEER) { + userSaveGalleryExceptions = exceptions; + SaveToGallerySettingsHelper.saveExceptions( + ApplicationLoader.applicationContext.getSharedPreferences(SaveToGallerySettingsHelper.USERS_PREF_NAME + "_" + currentAccount, Context.MODE_PRIVATE), + userSaveGalleryExceptions + ); + } else if (type == SharedConfig.SAVE_TO_GALLERY_FLAG_GROUP) { + groupsSaveGalleryExceptions = exceptions; + SaveToGallerySettingsHelper.saveExceptions( + ApplicationLoader.applicationContext.getSharedPreferences(SaveToGallerySettingsHelper.GROUPS_PREF_NAME + "_" + currentAccount, Context.MODE_PRIVATE), + groupsSaveGalleryExceptions + ); + } else if (type == SharedConfig.SAVE_TO_GALLERY_FLAG_CHANNELS) { + chanelSaveGalleryExceptions = exceptions; + SaveToGallerySettingsHelper.saveExceptions( + ApplicationLoader.applicationContext.getSharedPreferences(SaveToGallerySettingsHelper.CHANNELS_PREF_NAME + "_" + currentAccount, Context.MODE_PRIVATE), + chanelSaveGalleryExceptions + ); + } + } + public void clearConfig() { getPreferences().edit().clear().apply(); @@ -516,16 +565,7 @@ public boolean isPremium() { } public Long getEmojiStatus() { - if (currentUser == null) { - return null; - } - if (currentUser.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) currentUser.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { - return ((TLRPC.TL_emojiStatusUntil) currentUser.emoji_status).document_id; - } - if (currentUser.emoji_status instanceof TLRPC.TL_emojiStatus) { - return ((TLRPC.TL_emojiStatus) currentUser.emoji_status).document_id; - } - return null; + return UserObject.getEmojiStatusDocumentId(currentUser); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java index af7af8a8f62..b7bfa661f6f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java @@ -111,4 +111,26 @@ public static TLRPC.UserProfilePhoto getPhoto(TLRPC.User user) { public static boolean hasFallbackPhoto(TLRPC.UserFull userInfo) { return userInfo != null && userInfo.fallback_photo != null && !(userInfo.fallback_photo instanceof TLRPC.TL_photoEmpty); } + + public static Long getEmojiStatusDocumentId(TLRPC.User user) { + if (user == null) { + return null; + } + return getEmojiStatusDocumentId(user.emoji_status); + } + + public static Long getEmojiStatusDocumentId(TLRPC.EmojiStatus emojiStatus) { + if (emojiStatus == null) { + return null; + } + if (emojiStatus instanceof TLRPC.TL_emojiStatus) + return ((TLRPC.TL_emojiStatus) emojiStatus).document_id; + if (emojiStatus instanceof TLRPC.TL_emojiStatusUntil) { + TLRPC.TL_emojiStatusUntil untilStatus = (TLRPC.TL_emojiStatusUntil) emojiStatus; + if (untilStatus.until > (int) (System.currentTimeMillis() / 1000)) { + return untilStatus.document_id; + } + } + return null; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java index 8b140259f86..5e3dfb73d2e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java @@ -510,10 +510,18 @@ public static interface Callback { public void run(T arg); } + public static interface CallbackReturn { + public ReturnType run(Arg arg); + } + public static interface Callback2 { public void run(T arg, T2 arg2); } + public static interface Callback3 { + public void run(T arg, T2 arg2, T3 arg3); + } + public static Value getOrDefault(HashMap map, Key key, Value defaultValue) { Value v = map.get(key); if (v == null) { @@ -521,4 +529,34 @@ public static Value getOrDefault(HashMap map, Key key, } return v; } + + public static void doCallbacks(Utilities.Callback ...actions) { + doCallbacks(0, actions); + } + private static void doCallbacks(int i, Utilities.Callback ...actions) { + if (actions != null && actions.length > i) { + actions[i].run(() -> doCallbacks(i + 1, actions)); + } + } + + public static void raceCallbacks(Runnable onFinish, Utilities.Callback ...actions) { + if (actions == null || actions.length == 0) { + if (onFinish != null) { + onFinish.run(); + } + return; + } + final int[] finished = new int[] { 0 }; + Runnable checkFinish = () -> { + finished[0]++; + if (finished[0] == actions.length) { + if (onFinish != null) { + onFinish.run(); + } + } + }; + for (int i = 0; i < actions.length; ++i) { + actions[i].run(checkFinish); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java index aef8d17c4a9..d219b56c05c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java @@ -103,6 +103,7 @@ public static class MediaEntity { public int textAlign; public int viewWidth; public int viewHeight; + public float roundRadius; public float scale; public float textViewWidth; @@ -122,6 +123,7 @@ public static class MediaEntity { public View view; public Canvas canvas; public AnimatedFileDrawable animatedFileDrawable; + public Canvas roundRadiusCanvas; public MediaEntity() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java b/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java index c53c0974341..570c29f6a13 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java @@ -26,6 +26,7 @@ import org.telegram.messenger.CustomTabsCopyReceiver; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.ShareBroadcastReceiver; @@ -248,7 +249,7 @@ public static void openUrl(final Context context, Uri uri, final boolean allowCu boolean internalUri = isInternalUri(uri, forceBrowser); if (tryTelegraph) { try { - String host = uri.getHost().toLowerCase(); + String host = AndroidUtilities.getHostAuthority(uri); if (isTelegraphUrl(host, true) || uri.toString().toLowerCase().contains("telegram.org/faq") || uri.toString().toLowerCase().contains("telegram.org/privacy")) { final AlertDialog[] progressDialog = new AlertDialog[] { new AlertDialog(context, AlertDialog.ALERT_TYPE_SPINNER) @@ -307,7 +308,7 @@ public static void openUrl(final Context context, Uri uri, final boolean allowCu FileLog.e(e); } } - String host = uri.getHost() != null ? uri.getHost().toLowerCase() : ""; + String host = AndroidUtilities.getHostAuthority(uri.toString().toLowerCase()); if (AccountInstance.getInstance(currentAccount).getMessagesController().autologinDomains.contains(host)) { String token = "autologin_token=" + URLEncoder.encode(AccountInstance.getInstance(UserConfig.selectedAccount).getMessagesController().autologinToken, "UTF-8"); String url = uri.toString(); @@ -375,6 +376,13 @@ public static void openUrl(final Context context, Uri uri, final boolean allowCu } if (forceBrowser[0] || allActivities == null || allActivities.isEmpty()) { + if (MessagesController.getInstance(currentAccount).authDomains.contains(host)) { + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + ApplicationLoader.applicationContext.startActivity(intent); + return; + } + Intent share = new Intent(ApplicationLoader.applicationContext, ShareBroadcastReceiver.class); share.setAction(Intent.ACTION_SEND); @@ -441,9 +449,16 @@ public static boolean isInternalUri(Uri uri, boolean[] forceBrowser) { } public static boolean isInternalUri(Uri uri, boolean all, boolean[] forceBrowser) { - String host = uri.getHost(); + String host = AndroidUtilities.getHostAuthority(uri); host = host != null ? host.toLowerCase() : ""; + if (MessagesController.getInstance(UserConfig.selectedAccount).authDomains.contains(host)) { + if (forceBrowser != null) { + forceBrowser[0] = true; + } + return false; + } + Matcher prefixMatcher = LaunchActivity.PREFIX_T_ME_PATTERN.matcher(host); if (prefixMatcher.find()) { uri = Uri.parse("https://t.me/" + prefixMatcher.group(1) + (TextUtils.isEmpty(uri.getPath()) ? "" : "/" + uri.getPath()) + (TextUtils.isEmpty(uri.getQuery()) ? "" : "?" + uri.getQuery())); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/utils/BitmapsCache.java b/TMessagesProj/src/main/java/org/telegram/messenger/utils/BitmapsCache.java index cb6a39eb58b..2b2c7f29545 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/utils/BitmapsCache.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/utils/BitmapsCache.java @@ -42,7 +42,6 @@ public class BitmapsCache { ArrayList frameOffsets = new ArrayList<>(); - final boolean useSharedBuffers; static ConcurrentHashMap sharedBuffers = new ConcurrentHashMap(); static volatile boolean cleanupScheduled; @@ -111,6 +110,9 @@ public BitmapsCache(File sourceFile, Cacheable source, CacheOptions options, int fileExist = false; file.delete(); } else { + if (cachedFile != randomAccessFile) { + closeCachedFile(); + } cachedFile = randomAccessFile; } } @@ -179,6 +181,9 @@ public void createCache() { if (count > 0) { fillFrames(randomAccessFile, count); randomAccessFile.seek(0); + if (cachedFile != randomAccessFile) { + closeCachedFile(); + } cachedFile = randomAccessFile; fileExist = true; return; @@ -345,6 +350,7 @@ public void createCache() { this.frameOffsets.clear(); this.frameOffsets.addAll(frameOffsets); + closeCachedFile(); cachedFile = new RandomAccessFile(file, "r"); cacheCreated = true; fileExist = true; @@ -460,6 +466,9 @@ public int getFrame(int index, Bitmap bitmap) { bufferTmp = getBuffer(selectedFrame); randomAccessFile.readFully(bufferTmp, 0, selectedFrame.frameSize); if (!recycled) { + if (cachedFile != randomAccessFile) { + closeCachedFile(); + } cachedFile = randomAccessFile; } else { cachedFile = null; @@ -495,6 +504,16 @@ public int getFrame(int index, Bitmap bitmap) { return FRAME_RESULT_NO_FRAME; } + private void closeCachedFile() { + if (cachedFile != null) { + try { + cachedFile.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + private byte[] getBuffer(FrameOffset selectedFrame) { boolean useSharedBuffers = this.useSharedBuffers && Thread.currentThread().getName().startsWith(DispatchQueuePoolBackground.THREAD_PREFIX); byte[] bufferTmp; @@ -539,6 +558,10 @@ public int getFrameCount() { return frameOffsets.size(); } + public boolean isCreated() { + return cacheCreated && fileExist; + } + private class FrameOffset { final int index; int frameSize; @@ -642,6 +665,7 @@ public static class Metadata { public static class CacheOptions { public int compressQuality = 100; public boolean fallback = false; + public boolean firstFrame; } private static class CacheGeneratorSharedTools { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/utils/PhotoUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/utils/PhotoUtilities.java index 52fbac616f7..ee534ca26f5 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/utils/PhotoUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/utils/PhotoUtilities.java @@ -47,10 +47,10 @@ public static void setImageAsAvatar(MediaController.PhotoEntry entry, BaseFragme INavigationLayout layout = baseFragment.getParentLayout(); int currentAccount = baseFragment.getCurrentAccount(); - ImageUpdater imageUpdater = new ImageUpdater(true); + ImageUpdater imageUpdater = new ImageUpdater(true, ImageUpdater.FOR_TYPE_USER, true); imageUpdater.parentFragment = baseFragment; imageUpdater.processEntry(entry); - imageUpdater.setDelegate((photo, video, videoStartTimestamp, videoPath, bigSize, smallSize, isVideo) -> AndroidUtilities.runOnUIThread(() -> { + imageUpdater.setDelegate((photo, video, videoStartTimestamp, videoPath, bigSize, smallSize, isVideo, emojiMarkup) -> AndroidUtilities.runOnUIThread(() -> { TLRPC.TL_photos_uploadProfilePhoto req = new TLRPC.TL_photos_uploadProfilePhoto(); if (photo != null) { req.file = photo; @@ -62,6 +62,10 @@ public static void setImageAsAvatar(MediaController.PhotoEntry entry, BaseFragme req.video_start_ts = videoStartTimestamp; req.flags |= 4; } + if (emojiMarkup != null) { + req.video_emoji_markup = emojiMarkup; + req.flags |= 16; + } ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (response instanceof TLRPC.TL_photos_photo) { TLRPC.TL_photos_photo photos_photo = (TLRPC.TL_photos_photo) response; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java index fea4f5c0515..61bb3813b63 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/MediaCodecVideoConvertor.java @@ -354,7 +354,9 @@ private boolean convertVideoInternal(String videoPath, File cacheFile, } avatarStartTime = 0; //this encoder work with bitrate better, prevent case when result video max 2MB - encoderName = "OMX.google.h264.encoder"; + if (originalBitrate >= 15_000_000) { + encoderName = "OMX.google.h264.encoder"; + } } else if (bitrate <= 0) { bitrate = 921600; } @@ -822,7 +824,7 @@ private boolean convertVideoInternal(String videoPath, File cacheFile, long timeLeft = System.currentTimeMillis() - time; if (BuildVars.LOGS_ENABLED) { - FileLog.d("compression completed time=" + timeLeft + " needCompress=" + needCompress + " w=" + resultWidth + " h=" + resultHeight + " bitrate=" + bitrate); + FileLog.d("compression completed time=" + timeLeft + " needCompress=" + needCompress + " w=" + resultWidth + " h=" + resultHeight + " bitrate=" + bitrate + " file size=" + cacheFile.length()); } return error; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java index 57edfb8c940..c1b4a65606b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java @@ -14,6 +14,10 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.RectF; import android.graphics.SurfaceTexture; import android.graphics.Typeface; import android.opengl.GLES11Ext; @@ -52,6 +56,7 @@ import org.telegram.ui.Components.Paint.Views.EditTextOutline; import org.telegram.ui.Components.Paint.Views.PaintTextOptionsView; import org.telegram.ui.Components.RLottieDrawable; +import org.telegram.ui.Components.Rect; import java.io.File; import java.io.RandomAccessFile; @@ -143,6 +148,8 @@ public class TextureRenderer { private boolean isPhoto; private boolean firstFrame = true; + Path path; + Paint xRefPaint; public TextureRenderer(MediaController.SavedFilterState savedFilterState, String image, String paint, ArrayList entities, MediaController.CropState cropState, int w, int h, int originalWidth, int originalHeight, int rotation, float fps, boolean photo) { isPhoto = photo; @@ -404,6 +411,7 @@ public void drawFrame(SurfaceTexture st) { VideoEditedInfo.MediaEntity entity = mediaEntities.get(a); if (entity.ptr != 0) { RLottieDrawable.getFrame(entity.ptr, (int) entity.currentFrame, stickerBitmap, 512, 512, stickerBitmap.getRowBytes(), true); + applyRoundRadius(entity, stickerBitmap); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, stickerBitmap, 0); entity.currentFrame += entity.framesPerDraw; @@ -420,15 +428,21 @@ public void drawFrame(SurfaceTexture st) { currentFrame--; } Bitmap frameBitmap = entity.animatedFileDrawable.getBackgroundBitmap(); - if (stickerCanvas == null && stickerBitmap != null) { - stickerCanvas = new Canvas(stickerBitmap); - } - if (stickerBitmap != null && frameBitmap != null) { - stickerBitmap.eraseColor(Color.TRANSPARENT); - stickerCanvas.drawBitmap(frameBitmap, 0, 0, null); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]); - GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, stickerBitmap, 0); - drawTexture(false, stickerTexture[0], entity.x, entity.y, entity.width, entity.height, entity.rotation, (entity.subType & 2) != 0); + if (frameBitmap != null) { + if (stickerCanvas == null && stickerBitmap != null) { + stickerCanvas = new Canvas(stickerBitmap); + if (stickerBitmap.getHeight() != frameBitmap.getHeight() || stickerBitmap.getWidth() != frameBitmap.getWidth()) { + stickerCanvas.scale(stickerBitmap.getWidth() / (float) frameBitmap.getWidth(), stickerBitmap.getHeight() / (float) frameBitmap.getHeight()); + } + } + if (stickerBitmap != null) { + stickerBitmap.eraseColor(Color.TRANSPARENT); + stickerCanvas.drawBitmap(frameBitmap, 0, 0, null); + applyRoundRadius(entity, stickerBitmap); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]); + GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, stickerBitmap, 0); + drawTexture(false, stickerTexture[0], entity.x, entity.y, entity.width, entity.height, entity.rotation, (entity.subType & 2) != 0); + } } } else if (entity.view != null && entity.canvas != null && entity.bitmap != null) { entity.bitmap.eraseColor(Color.TRANSPARENT); @@ -438,6 +452,7 @@ public void drawFrame(SurfaceTexture st) { EditTextEffects editTextEffects = (EditTextEffects) entity.view; editTextEffects.incrementFrames(currentFrame - lastFrame); entity.view.draw(entity.canvas); + applyRoundRadius(entity, entity.bitmap); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, entity.bitmap, 0); drawTexture(false, stickerTexture[0], entity.x, entity.y, entity.width, entity.height, entity.rotation, (entity.subType & 2) != 0); @@ -453,6 +468,29 @@ public void drawFrame(SurfaceTexture st) { GLES20.glFinish(); } + private void applyRoundRadius(VideoEditedInfo.MediaEntity entity, Bitmap stickerBitmap) { + if (stickerBitmap == null || entity == null || entity.roundRadius == 0) { + return; + } + if (entity.roundRadiusCanvas == null) { + entity.roundRadiusCanvas = new Canvas(stickerBitmap); + } + if (path == null) { + path = new Path(); + } + if (xRefPaint == null) { + xRefPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + xRefPaint.setColor(0xff000000); + xRefPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + } + float rad = Math.min(stickerBitmap.getWidth(), stickerBitmap.getHeight()) * entity.roundRadius; + path.rewind(); + RectF rect = new RectF(0, 0, stickerBitmap.getWidth(), stickerBitmap.getHeight()); + path.addRoundRect(rect, rad, rad, Path.Direction.CCW); + path.toggleInverseFillType(); + entity.roundRadiusCanvas.drawPath(path, xRefPaint); + } + private void drawTexture(boolean bind, int texture) { drawTexture(bind, texture, -10000, -10000, -10000, -10000, 0, false); } diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java index d405d420b08..b5577333a03 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java @@ -69,7 +69,7 @@ public class TLRPC { public static final int MESSAGE_FLAG_HAS_BOT_ID = 0x00000800; public static final int MESSAGE_FLAG_EDITED = 0x00008000; - public static final int LAYER = 151; + public static final int LAYER = 152; public static class TL_stats_megagroupStats extends TLObject { public static int constructor = 0xef7ff916; @@ -395,11 +395,11 @@ public static class TL_account_emailVerifiedLogin extends account_EmailVerified public static int constructor = 0xe1bb0d61; public String email; - public TL_auth_sentCode sent_code; + public auth_SentCode sent_code; public void readParams(AbstractSerializedData stream, boolean exception) { email = stream.readString(exception); - sent_code = TL_auth_sentCode.TLdeserialize(stream, stream.readInt32(exception), exception); + sent_code = auth_SentCode.TLdeserialize(stream, stream.readInt32(exception), exception); } public void serializeToStream(AbstractSerializedData stream) { @@ -426,6 +426,13 @@ public static class TL_chatBannedRights extends TLObject { public boolean invite_users; public boolean pin_messages; public boolean manage_topics; + public boolean send_photos; + public boolean send_videos; + public boolean send_roundvideos; + public boolean send_audios; + public boolean send_voices; + public boolean send_docs; + public boolean send_plain; public int until_date; public static TL_chatBannedRights TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { @@ -456,11 +463,36 @@ public void readParams(AbstractSerializedData stream, boolean exception) { invite_users = (flags & 32768) != 0; pin_messages = (flags & 131072) != 0; manage_topics = (flags & 262144) != 0; + send_photos = (flags & 524288) != 0; + send_videos = (flags & 1048576) != 0; + send_roundvideos = (flags & 2097152) != 0; + send_audios = (flags & 4194304) != 0; + send_voices = (flags & 8388608) != 0; + send_docs = (flags & 16777216) != 0; + send_plain = (flags & 33554432) != 0; + if (send_media) { + send_photos = true; + send_videos = true; + send_roundvideos = true; + send_audios = true; + send_voices = true; + send_docs = true; + } until_date = stream.readInt32(exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + if (send_photos && send_videos && send_roundvideos && send_audios && send_voices && send_docs) { + send_media = true; + } else { + send_media = false; + } + if (send_plain && send_media) { + send_messages = true; + } else { + send_messages = false; + } flags = view_messages ? (flags | 1) : (flags &~ 1); flags = send_messages ? (flags | 2) : (flags &~ 2); flags = send_media ? (flags | 4) : (flags &~ 4); @@ -474,6 +506,13 @@ public void serializeToStream(AbstractSerializedData stream) { flags = invite_users ? (flags | 32768) : (flags &~ 32768); flags = pin_messages ? (flags | 131072) : (flags &~ 131072); flags = manage_topics ? (flags | 262144) : (flags &~ 262144); + flags = send_photos ? (flags | 524288) : (flags &~ 524288); + flags = send_videos ? (flags | 1048576) : (flags &~ 1048576); + flags = send_roundvideos ? (flags | 2097152) : (flags &~ 2097152); + flags = send_audios ? (flags | 4194304) : (flags &~ 4194304); + flags = send_voices ? (flags | 8388608) : (flags &~ 8388608); + flags = send_docs ? (flags | 16777216) : (flags &~ 16777216); + flags = send_plain ? (flags | 33554432) : (flags &~ 33554432); stream.writeInt32(flags); stream.writeInt32(until_date); } @@ -1265,9 +1304,12 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_premiumSubscriptionOption extends TLObject { - public static int constructor = 0xb6f11ebe; + public static int constructor = 0x5f2d1df2; public int flags; + public boolean current; + public String transaction; + public boolean can_purchase_upgrade; public int months; public String currency; public long amount; @@ -1275,18 +1317,62 @@ public static class TL_premiumSubscriptionOption extends TLObject { public String store_product; public static TL_premiumSubscriptionOption TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_premiumSubscriptionOption.constructor != constructor) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_premiumSubscriptionOption", constructor)); - } else { - return null; - } + TL_premiumSubscriptionOption result = null; + switch (constructor) { + case 0x5f2d1df2: + result = new TL_premiumSubscriptionOption(); + break; + case 0xb6f11ebe: + result = new TL_premiumSubscriptionOption_layer151(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_premiumSubscriptionOption", constructor)); + } + if (result != null) { + result.readParams(stream, exception); } - TL_premiumSubscriptionOption result = new TL_premiumSubscriptionOption(); - result.readParams(stream, exception); return result; } + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + current = (flags & 2) != 0; + if ((flags & 8) != 0) { + transaction = stream.readString(exception); + } + can_purchase_upgrade = (flags & 4) != 0; + months = stream.readInt32(exception); + currency = stream.readString(exception); + amount = stream.readInt64(exception); + bot_url = stream.readString(exception); + if ((flags & 1) != 0) { + store_product = stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = current ? (flags | 2) : (flags &~ 2); + flags = can_purchase_upgrade ? (flags | 4) : (flags &~ 4); + stream.writeInt32(flags); + if ((flags & 8) != 0) { + stream.writeString(transaction); + } + stream.writeInt32(months); + stream.writeString(currency); + stream.writeInt64(amount); + stream.writeString(bot_url); + if ((flags & 1) != 0) { + stream.writeString(store_product); + } + } + } + + public static class TL_premiumSubscriptionOption_layer151 extends TL_premiumSubscriptionOption { + public static int constructor = 0xb6f11ebe; + + public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); months = stream.readInt32(exception); @@ -2689,7 +2775,10 @@ public static auth_Authorization TLdeserialize(AbstractSerializedData stream, in case 0x44747e9a: result = new TL_auth_authorizationSignUpRequired(); break; - case 0x33fb7bb8: + case 0x33fb7bb8://TODO old constructor need remove + result = new TL_auth_authorization(); + break; + case 0x2ea2c0d4: result = new TL_auth_authorization(); break; } @@ -2726,12 +2815,13 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_auth_authorization extends auth_Authorization { - public static int constructor = 0x33fb7bb8; + public static int constructor = 0x2ea2c0d4; public int flags; public boolean setup_password_required; public int otherwise_relogin_days; public int tmp_sessions; + public byte[] future_auth_token; public User user; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -2743,6 +2833,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 1) != 0) { tmp_sessions = stream.readInt32(exception); } + if ((flags & 4) != 0) { + future_auth_token = stream.readByteArray(exception); + } user = User.TLdeserialize(stream, stream.readInt32(exception), exception); } @@ -2756,6 +2849,9 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 1) != 0) { stream.writeInt32(tmp_sessions); } + if ((flags & 4) != 0) { + stream.writeByteArray(future_auth_token); + } user.serializeToStream(stream); } } @@ -6706,6 +6802,10 @@ public static abstract class auth_SentCodeType extends TLObject { public boolean google_signin_allowed; public String email_pattern; public int next_phone_login_date; + public byte[] nonce; + public String receipt; + public int push_timeout; + public boolean verifiedFirebase; //custom public static auth_SentCodeType TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { auth_SentCodeType result = null; @@ -6734,6 +6834,9 @@ public static auth_SentCodeType TLdeserialize(AbstractSerializedData stream, int case 0xd9565c39: result = new TL_auth_sentCodeTypeFragmentSms(); break; + case 0xe57b1432: + result = new TL_auth_sentCodeTypeFirebaseSms(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in auth_SentCodeType", constructor)); @@ -6877,6 +6980,40 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_auth_sentCodeTypeFirebaseSms extends auth_SentCodeType { + public static int constructor = 0xe57b1432; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + if ((flags & 1) != 0) { + nonce = stream.readByteArray(exception); + } + if ((flags & 2) != 0) { + receipt = stream.readString(exception); + } + if ((flags & 2) != 0) { + push_timeout = stream.readInt32(exception); + } + length = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + stream.writeByteArray(nonce); + } + if ((flags & 2) != 0) { + stream.writeString(receipt); + } + if ((flags & 2) != 0) { + stream.writeInt32(push_timeout); + } + stream.writeInt32(length); + } + } + public static abstract class messages_StickerSetInstallResult extends TLObject { public ArrayList sets = new ArrayList<>(); @@ -8605,27 +8742,50 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static class TL_auth_sentCode extends TLObject { - public static int constructor = 0x5e002502; + public static abstract class auth_SentCode extends TLObject { public int flags; public auth_SentCodeType type; public String phone_code_hash; public auth_CodeType next_type; public int timeout; + public auth_Authorization authorization; - public static TL_auth_sentCode TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_auth_sentCode.constructor != constructor) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_auth_sentCode", constructor)); - } else { - return null; - } + public static auth_SentCode TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + auth_SentCode result = null; + switch (constructor) { + case 0x2390fe44: + result = new TL_auth_sentCodeSuccess(); + break; + case 0x5e002502: + result = new TL_auth_sentCode(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in auth_SentCode", constructor)); + } + if (result != null) { + result.readParams(stream, exception); } - TL_auth_sentCode result = new TL_auth_sentCode(); - result.readParams(stream, exception); return result; } + } + + public static class TL_auth_sentCodeSuccess extends auth_SentCode { + public static int constructor = 0x2390fe44; + + public void readParams(AbstractSerializedData stream, boolean exception) { + authorization = auth_Authorization.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + authorization.serializeToStream(stream); + } + } + + public static class TL_auth_sentCode extends auth_SentCode { + public static int constructor = 0x5e002502; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -12090,6 +12250,7 @@ public static abstract class ChatFull extends TLObject { public boolean can_delete_channel; public boolean antispam; public boolean participants_hidden; + public boolean translations_disabled; public ChatReactions available_reactions; public long inviterId; //custom @@ -14565,6 +14726,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { can_delete_channel = (flags2 & 1) != 0; antispam = (flags2 & 2) != 0; participants_hidden = (flags2 & 4) != 0; + translations_disabled = (flags2 & 8) != 0; id = stream.readInt64(exception); about = stream.readString(exception); if ((flags & 1) != 0) { @@ -14702,6 +14864,7 @@ public void serializeToStream(AbstractSerializedData stream) { flags2 = can_delete_channel ? (flags2 | 1) : (flags2 &~ 1); flags2 = antispam ? (flags2 | 2) : (flags2 &~ 2); flags2 = participants_hidden ? (flags2 | 4) : (flags2 &~ 4); + flags2 = translations_disabled ? (flags2 | 8) : (flags2 &~ 8); stream.writeInt32(flags2); stream.writeInt64(id); stream.writeString(about); @@ -17674,14 +17837,17 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_codeSettings extends TLObject { - public static int constructor = 0x8a6469c2; + public static int constructor = 0xad253d78; public int flags; public boolean allow_flashcall; public boolean current_number; public boolean allow_app_hash; public boolean allow_missed_call; + public boolean allow_firebase; public ArrayList logout_tokens = new ArrayList<>(); + public String token; + public boolean app_sandbox; public static TL_codeSettings TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { if (TL_codeSettings.constructor != constructor) { @@ -17702,6 +17868,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { current_number = (flags & 2) != 0; allow_app_hash = (flags & 16) != 0; allow_missed_call = (flags & 32) != 0; + allow_firebase = (flags & 128) != 0; if ((flags & 64) != 0) { int magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { @@ -17712,9 +17879,17 @@ public void readParams(AbstractSerializedData stream, boolean exception) { } int count = stream.readInt32(exception); for (int a = 0; a < count; a++) { - logout_tokens.add(stream.readByteArray(exception)); + byte[] object = stream.readByteArray(exception); + if (object == null) { + return; + } + logout_tokens.add(object); } } + if ((flags & 256) != 0) { + token = stream.readString(exception); + } + app_sandbox = (flags & 256) != 0; } public void serializeToStream(AbstractSerializedData stream) { @@ -17723,6 +17898,8 @@ public void serializeToStream(AbstractSerializedData stream) { flags = current_number ? (flags | 2) : (flags &~ 2); flags = allow_app_hash ? (flags | 16) : (flags &~ 16); flags = allow_missed_call ? (flags | 32) : (flags &~ 32); + flags = allow_firebase ? (flags | 128) : (flags &~ 128); + flags = app_sandbox ? (flags | 256) : (flags &~ 256); stream.writeInt32(flags); if ((flags & 64) != 0) { stream.writeInt32(0x1cb5c415); @@ -17732,6 +17909,9 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeByteArray(logout_tokens.get(a)); } } + if ((flags & 256) != 0) { + stream.writeString(token); + } } } @@ -18652,6 +18832,9 @@ public static KeyboardButton TLdeserialize(AbstractSerializedData stream, int co case 0x13767230: result = new TL_keyboardButtonWebView(); break; + case 0xd0b468c: + result = new TL_keyboardButtonRequestPeer(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in KeyboardButton", constructor)); @@ -18911,6 +19094,73 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_videoSizeEmojiMarkup extends VideoSize { + public static int constructor = 0xf85c413c; + + public long emoji_id; + + public void readParams(AbstractSerializedData stream, boolean exception) { + emoji_id = stream.readInt64(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + background_colors.add(stream.readInt32(exception)); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(emoji_id); + stream.writeInt32(0x1cb5c415); + int count = background_colors.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(background_colors.get(a)); + } + } + } + + public static class TL_videoSizeStickerMarkup extends VideoSize { + public static int constructor = 0xda082fe; + + public InputStickerSet stickerset; + public long sticker_id; + + public void readParams(AbstractSerializedData stream, boolean exception) { + stickerset = InputStickerSet.TLdeserialize(stream, stream.readInt32(exception), exception); + sticker_id = stream.readInt64(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + background_colors.add(stream.readInt32(exception)); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stickerset.serializeToStream(stream); + stream.writeInt64(sticker_id); + stream.writeInt32(0x1cb5c415); + int count = background_colors.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(background_colors.get(a)); + } + } + } + public static abstract class VideoSize extends TLObject { public int flags; @@ -18920,6 +19170,7 @@ public static abstract class VideoSize extends TLObject { public int h; public int size; public double video_start_ts; + public ArrayList background_colors = new ArrayList<>(); public static VideoSize TLdeserialize(long photo_id, long document_id, AbstractSerializedData stream, int constructor, boolean exception) { VideoSize result = null; @@ -18933,6 +19184,12 @@ public static VideoSize TLdeserialize(long photo_id, long document_id, AbstractS case 0xde33b094: result = new TL_videoSize(); break; + case 0xda082fe: + result = new TL_videoSizeStickerMarkup(); + break; + case 0xf85c413c: + result = new TL_videoSizeEmojiMarkup(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in VideoSize", constructor)); @@ -24148,6 +24405,9 @@ public static MessageAction TLdeserialize(AbstractSerializedData stream, int con case 0xaba0f5c6: result = new TL_messageActionGiftPremium(); break; + case 0xfe77345d: + result = new TL_messageActionRequestedPeer(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in MessageAction", constructor)); @@ -40582,6 +40842,123 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static abstract class messages_EmojiGroups extends TLObject { + + public static messages_EmojiGroups TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + messages_EmojiGroups result = null; + switch (constructor) { + case 0x6fb4ad87: + result = new TL_messages_emojiGroupsNotModified(); + break; + case 0x881fb94b: + result = new TL_messages_emojiGroups(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in messages_EmojiGroups", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_messages_emojiGroupsNotModified extends messages_EmojiGroups { + public static int constructor = 0x6fb4ad87; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messages_emojiGroups extends messages_EmojiGroups { + public static int constructor = 0x881fb94b; + + public int hash; + public ArrayList groups = new ArrayList<>(); + + public void readParams(AbstractSerializedData stream, boolean exception) { + hash = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_emojiGroup object = TL_emojiGroup.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + groups.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + stream.writeInt32(0x1cb5c415); + int count = groups.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + groups.get(a).serializeToStream(stream); + } + } + } + + public static class TL_emojiGroup extends TLObject { + public static int constructor = 0x7a9abda9; + + public String title; + public long icon_emoji_id; + public ArrayList emoticons = new ArrayList<>(); + + public static TL_emojiGroup TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_emojiGroup.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_emojiGroup", constructor)); + } else { + return null; + } + } + TL_emojiGroup result = new TL_emojiGroup(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + title = stream.readString(exception); + icon_emoji_id = stream.readInt64(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + emoticons.add(stream.readString(exception)); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(title); + stream.writeInt64(icon_emoji_id); + stream.writeInt32(0x1cb5c415); + int count = emoticons.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeString(emoticons.get(a)); + } + } + } + public static class TL_emojiKeyword extends EmojiKeyword { public static int constructor = 0xd5b3b9f9; @@ -44466,49 +44843,50 @@ public void serializeToStream(AbstractSerializedData stream) { } } - public static abstract class messages_TranslatedText extends TLObject { + public static class TL_messages_translateResult extends TLObject { + public static int constructor = 0x33db32f8; - public static messages_TranslatedText TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - messages_TranslatedText result = null; - switch (constructor) { - case 0x67ca4737: - result = new TL_messages_translateNoResult(); - break; - case 0xa214f7d0: - result = new TL_messages_translateResultText(); - break; - } - if (result == null && exception) { - throw new RuntimeException(String.format("can't parse magic %x in messages_TranslatedText", constructor)); - } - if (result != null) { - result.readParams(stream, exception); + public ArrayList result = new ArrayList<>(); + + public static TL_messages_translateResult TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_messages_translateResult.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_messages_translateResult", constructor)); + } else { + return null; + } } + TL_messages_translateResult result = new TL_messages_translateResult(); + result.readParams(stream, exception); return result; } - } - - public static class TL_messages_translateNoResult extends messages_TranslatedText { - public static int constructor = 0x67ca4737; - - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - } - } - - public static class TL_messages_translateResultText extends messages_TranslatedText { - public static int constructor = 0xa214f7d0; - - public String text; public void readParams(AbstractSerializedData stream, boolean exception) { - text = stream.readString(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_textWithEntities object = TL_textWithEntities.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + result.add(object); + } } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - stream.writeString(text); + stream.writeInt32(0x1cb5c415); + int count = result.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + result.get(a).serializeToStream(stream); + } } } @@ -46110,6 +46488,56 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_textWithEntities extends TLObject { + public static int constructor = 0x751f3146; + + public String text; + public ArrayList entities = new ArrayList<>(); + + public static TL_textWithEntities TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_textWithEntities.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_textWithEntities", constructor)); + } else { + return null; + } + } + TL_textWithEntities result = new TL_textWithEntities(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + } + public static class TL_account_webAuthorizations extends TLObject { public static int constructor = 0xed56c9fc; @@ -46346,6 +46774,7 @@ public static abstract class UserFull extends TLObject { public boolean has_scheduled; public boolean video_calls_available; public boolean voice_messages_forbidden; + public boolean translations_disabled; public User user; public String about; public TL_contacts_link_layer101 link; @@ -46422,6 +46851,7 @@ public void readParams(AbstractSerializedData stream, boolean exception) { has_scheduled = (flags & 4096) != 0; video_calls_available = (flags & 8192) != 0; voice_messages_forbidden = (flags & 1048576) != 0; + translations_disabled = (flags & 8388608) != 0; id = stream.readInt64(exception); if ((flags & 2) != 0) { about = stream.readString(exception); @@ -46490,6 +46920,7 @@ public void serializeToStream(AbstractSerializedData stream) { flags = has_scheduled ? (flags | 4096) : (flags &~ 4096); flags = video_calls_available ? (flags | 8192) : (flags &~ 8192); flags = voice_messages_forbidden ? (flags | 1048576) : (flags &~ 1048576); + flags = translations_disabled ? (flags | 8388608) : (flags &~ 8388608); stream.writeInt32(flags); stream.writeInt64(id); if ((flags & 2) != 0) { @@ -48014,7 +48445,7 @@ public static InputChatPhoto TLdeserialize(AbstractSerializedData stream, int co case 0x1ca48f57: result = new TL_inputChatPhotoEmpty(); break; - case 0xc642724e: + case 0xbdcdaec0: result = new TL_inputChatUploadedPhoto(); break; } @@ -48053,12 +48484,13 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_inputChatUploadedPhoto extends InputChatPhoto { - public static int constructor = 0xc642724e; + public static int constructor = 0xbdcdaec0; public int flags; public InputFile file; public InputFile video; public double video_start_ts; + public VideoSize video_emoji_markup; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -48071,6 +48503,9 @@ public void readParams(AbstractSerializedData stream, boolean exception) { if ((flags & 4) != 0) { video_start_ts = stream.readDouble(exception); } + if ((flags & 8) != 0) { + video_emoji_markup = VideoSize.TLdeserialize(0, 0, stream, stream.readInt32(exception), exception); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -48085,6 +48520,9 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 4) != 0) { stream.writeDouble(video_start_ts); } + if ((flags & 8) != 0) { + video_emoji_markup.serializeToStream(stream); + } } } @@ -49991,6 +50429,87 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_messages_getEmojiGroups extends TLObject { + public static int constructor = 0x7488ce5b; + + public int hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_EmojiGroups.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + } + } + + public static class TL_messages_getEmojiProfilePhotoGroups extends TLObject { + public static int constructor = 0x21a548f3; + + public int hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_EmojiGroups.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + } + } + + public static class TL_messages_getEmojiStatusGroups extends TLObject { + public static int constructor = 0x2ecd56cd; + + public int hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_EmojiGroups.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + } + } + + public static class TL_messages_searchCustomEmoji extends TLObject { + public static int constructor = 0x2c11c0d7; + + public String emoticon; + public long hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return EmojiList.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(emoticon); + stream.writeInt64(hash); + } + } + + public static class TL_messages_togglePeerTranslations extends TLObject { + public static int constructor = 0xe47cb579; + + public int flags; + public boolean disabled; + public InputPeer peer; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = disabled ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + peer.serializeToStream(stream); + } + } + public static class TL_auth_sendCode extends TLObject { public static int constructor = 0xa677244f; @@ -50206,6 +50725,33 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_auth_requestFirebaseSms extends TLObject { + public static int constructor = 0x89464b50; + + public int flags; + public String phone_number; + public String phone_code_hash; + public String safety_net_token; + public String ios_push_secret; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeString(phone_number); + stream.writeString(phone_code_hash); + if ((flags & 1) != 0) { + stream.writeString(safety_net_token); + } + if ((flags & 2) != 0) { + stream.writeString(ios_push_secret); + } + } + } + public static class TL_account_registerDevice extends TLObject { public static int constructor = 0xec86017a; @@ -51892,13 +52438,14 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_photos_uploadProfilePhoto extends TLObject { - public static int constructor = 0x89f30f69; + public static int constructor = 0x93c9a51; public int flags; public boolean fallback; public InputFile file; public InputFile video; public double video_start_ts; + public VideoSize video_emoji_markup; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return TL_photos_photo.TLdeserialize(stream, constructor, exception); @@ -51917,6 +52464,9 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 4) != 0) { stream.writeDouble(video_start_ts); } + if ((flags & 16) != 0) { + video_emoji_markup.serializeToStream(stream); + } } } @@ -55009,17 +55559,16 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_messages_translateText extends TLObject { - public static int constructor = 0x24ce6dee; + public static int constructor = 0x63183030; public int flags; public InputPeer peer; - public int msg_id; - public String text; - public String from_lang; + public ArrayList id = new ArrayList<>(); + public ArrayList text = new ArrayList<>(); public String to_lang; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return messages_TranslatedText.TLdeserialize(stream, constructor, exception); + return TL_messages_translateResult.TLdeserialize(stream, constructor, exception); } public void serializeToStream(AbstractSerializedData stream) { @@ -55029,13 +55578,20 @@ public void serializeToStream(AbstractSerializedData stream) { peer.serializeToStream(stream); } if ((flags & 1) != 0) { - stream.writeInt32(msg_id); + stream.writeInt32(0x1cb5c415); + int count = id.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(id.get(a)); + } } if ((flags & 2) != 0) { - stream.writeString(text); - } - if ((flags & 4) != 0) { - stream.writeString(from_lang); + stream.writeInt32(0x1cb5c415); + final int count = text.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + text.get(a).serializeToStream(stream); + } } stream.writeString(to_lang); } @@ -56396,16 +56952,18 @@ public void serializeToStream(AbstractSerializedData stream) { } public static class TL_channels_createChannel extends TLObject { - public static int constructor = 0x3d5fb10f; + public static int constructor = 0x91006707; public int flags; public boolean broadcast; public boolean megagroup; public boolean for_import; + public boolean forum; public String title; public String about; public InputGeoPoint geo_point; public String address; + public int ttl_period; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return Updates.TLdeserialize(stream, constructor, exception); @@ -56416,6 +56974,7 @@ public void serializeToStream(AbstractSerializedData stream) { flags = broadcast ? (flags | 1) : (flags &~ 1); flags = megagroup ? (flags | 2) : (flags &~ 2); flags = for_import ? (flags | 8) : (flags &~ 8); + flags = forum ? (flags | 32) : (flags &~ 32); stream.writeInt32(flags); stream.writeString(title); stream.writeString(about); @@ -56425,6 +56984,9 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 4) != 0) { stream.writeString(address); } + if ((flags & 16) != 0) { + stream.writeInt32(ttl_period); + } } } @@ -57876,7 +58438,7 @@ public static InputStorePaymentPurpose TLdeserialize(AbstractSerializedData stre case 0xa6751e66: result = new TL_inputStorePaymentPremiumSubscription(); break; - case 0x44618a7d: + case 0x616f7fe8: result = new TL_inputStorePaymentGiftPremium(); break; } @@ -57895,15 +58457,18 @@ public static class TL_inputStorePaymentPremiumSubscription extends InputStorePa public int flags; public boolean restore; + public boolean upgrade; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); restore = (flags & 1) != 0; + upgrade = (flags & 2) != 0; } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); flags = restore ? (flags | 1) : (flags &~ 1); + flags = upgrade ? (flags | 2) : (flags &~ 2); stream.writeInt32(flags); } } @@ -59068,6 +59633,9 @@ public static class Message extends TLObject { public boolean voiceTranscriptionForce; //custom public long voiceTranscriptionId; //custom public boolean premiumEffectWasPlayed; //custom + public String originalLanguage; //custom + public String translatedToLanguage; //custom + public TL_textWithEntities translatedText; // custom public static Message TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { Message result = null; @@ -59175,7 +59743,11 @@ public static Message TLdeserialize(AbstractSerializedData stream, int construct if (result != null) { result.readParams(stream, exception); if (result.from_id == null) { - result.from_id = result.peer_id; + if (result.id < 0 && result.random_id == 0) { + result.from_id = new TL_peerUser(); + } else { + result.from_id = result.peer_id; + } } } return result; @@ -63336,6 +63908,170 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class RequestPeerType extends TLObject { + + public int flags; + + public Boolean creator; + public TL_chatAdminRights user_admin_rights; + public TL_chatAdminRights bot_admin_rights; + public Boolean has_username; + public Boolean forum; + public Boolean bot_participant; + + public static RequestPeerType TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + RequestPeerType result = null; + switch (constructor) { + case TL_requestPeerTypeUser.constructor: + result = new TL_requestPeerTypeUser(); + break; + case TL_requestPeerTypeChat.constructor: + result = new TL_requestPeerTypeChat(); + break; + case TL_requestPeerTypeBroadcast.constructor: + result = new TL_requestPeerTypeBroadcast(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in RequestPeerType", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_requestPeerTypeUser extends RequestPeerType { + public static final int constructor = 0x5f3b8a00; + + public Boolean bot; + public Boolean premium; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + if ((flags & 1) != 0) { + bot = stream.readBool(exception); + } + if ((flags & 2) != 0) { + premium = stream.readBool(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = bot != null ? (flags | 1) : (flags &~ 1); + flags = premium != null ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + if (bot != null) { + stream.writeBool(bot); + } + if (premium != null) { + stream.writeBool(premium); + } + } + } + + public static class TL_requestPeerTypeChat extends RequestPeerType { + public static final int constructor = 0xc9f06e1b; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + bot_participant = (flags & 32) != 0; + creator = (flags & 1) != 0; + if ((flags & 8) != 0) { + has_username = stream.readBool(exception); + } + if ((flags & 16) != 0) { + forum = stream.readBool(exception); + } + if ((flags & 2) != 0) { + user_admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 4) != 0) { + bot_admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = creator != null && creator ? (flags | 1) : (flags &~ 1); + flags = user_admin_rights != null ? (flags | 2) : (flags &~ 2); + flags = bot_admin_rights != null ? (flags | 4) : (flags &~ 4); + flags = has_username != null ? (flags | 8) : (flags &~ 8); + flags = forum != null ? (flags | 16) : (flags &~ 16); + flags = bot_participant != null && bot_participant ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + if (has_username != null) { + stream.writeBool(has_username); + } + if (forum != null) { + stream.writeBool(forum); + } + if (user_admin_rights != null) { + user_admin_rights.serializeToStream(stream); + } + if (bot_admin_rights != null) { + bot_admin_rights.serializeToStream(stream); + } + } + } + + public static class TL_requestPeerTypeBroadcast extends RequestPeerType { + public static final int constructor = 0x339bef6c; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + creator = (flags & 1) != 0; + if ((flags & 8) != 0) { + has_username = stream.readBool(exception); + } + if ((flags & 2) != 0) { + user_admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 4) != 0) { + bot_admin_rights = TL_chatAdminRights.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = creator != null && creator ? (flags | 1) : (flags &~ 1); + flags = user_admin_rights != null ? (flags | 2) : (flags &~ 2); + flags = bot_admin_rights != null ? (flags | 4) : (flags &~ 4); + flags = has_username != null ? (flags | 8) : (flags &~ 8); + stream.writeInt32(flags); + if (has_username != null) { + stream.writeBool(has_username); + } + if (user_admin_rights != null) { + user_admin_rights.serializeToStream(stream); + } + if (bot_admin_rights != null) { + bot_admin_rights.serializeToStream(stream); + } + } + } + + public static class TL_keyboardButtonRequestPeer extends KeyboardButton { + public static int constructor = 0xd0b468c; + + public RequestPeerType peer_type; + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + button_id = stream.readInt32(exception); + peer_type = RequestPeerType.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + stream.writeInt32(button_id); + peer_type.serializeToStream(stream); + } + } + public static class TL_messages_getAttachMenuBots extends TLObject { public static int constructor = 0x16fcc2cb; @@ -65447,6 +66183,28 @@ public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(period); } } + + public static class TL_messages_sendBotRequestedPeer extends TLObject { + public static int constructor = 0xfe38d01b; + + public InputPeer peer; + public int msg_id; + public int button_id; + public InputPeer requested_peer; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(msg_id); + stream.writeInt32(button_id); + requested_peer.serializeToStream(stream); + } + } + public static class TL_contacts_exportContactToken extends TLObject { public static int constructor = 0xf8654027; @@ -65500,8 +66258,26 @@ public void serializeToStream(AbstractSerializedData stream) { } } + public static class TL_messageActionRequestedPeer extends MessageAction { + public static int constructor = 0xfe77345d; + + public int button_id; + public TLRPC.Peer peer; + + public void readParams(AbstractSerializedData stream, boolean exception) { + button_id = stream.readInt32(exception); + peer = TLRPC.Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(button_id); + peer.serializeToStream(stream); + } + } + public static class TL_photos_uploadContactProfilePhoto extends TLObject { - public static int constructor = 0xb91a83bf; + public static int constructor = 0xe14c4a71; public int flags; public boolean suggest; @@ -65510,6 +66286,7 @@ public static class TL_photos_uploadContactProfilePhoto extends TLObject { public InputFile file; public InputFile video; public double video_start_ts; + public VideoSize video_emoji_markup; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return TL_photos_photo.TLdeserialize(stream, constructor, exception); @@ -65530,6 +66307,103 @@ public void serializeToStream(AbstractSerializedData stream) { if ((flags & 4) != 0) { stream.writeDouble(video_start_ts); } + if ((flags & 32) != 0) { + video_emoji_markup.serializeToStream(stream); + } + } + } + + public static abstract class EmojiList extends TLObject { + + public static EmojiList TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + EmojiList result = null; + switch (constructor) { + case 0x7a1e11d1: + result = new TL_emojiList(); + break; + case 0x481eadfa: + result = new TL_emojiListNotModified(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in EmojiList", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_emojiList extends EmojiList { + public static int constructor = 0x7a1e11d1; + + public long hash; + public ArrayList document_id = new ArrayList<>(); + + public void readParams(AbstractSerializedData stream, boolean exception) { + hash = stream.readInt64(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + document_id.add(stream.readInt64(exception)); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(hash); + stream.writeInt32(0x1cb5c415); + int count = document_id.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(document_id.get(a)); + } + } + } + + public static class TL_emojiListNotModified extends EmojiList { + public static int constructor = 0x481eadfa; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_account_getDefaultProfilePhotoEmojis extends TLObject { + public static int constructor = 0xe2750328; + + public long hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return EmojiList.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(hash); + } + } + + public static class TL_account_getDefaultGroupPhotoEmojis extends TLObject { + public static int constructor = 0x915860ae; + + public long hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return EmojiList.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(hash); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java index 518a31c5702..b4ff4b9dbc9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java @@ -391,14 +391,6 @@ private void createPopupLayout() { popupWindow.dismiss(); } }); - - if (popupLayout.getSwipeBack() != null) { - popupLayout.getSwipeBack().setOnClickListener(view -> { - if (popupWindow != null) { - popupWindow.dismiss(); - } - }); - } } public void removeAllSubItems() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java index 043acef1b37..03f13920bdd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuSubItem.java @@ -43,14 +43,18 @@ public ActionBarMenuSubItem(Context context, boolean top, boolean bottom) { } public ActionBarMenuSubItem(Context context, boolean needCheck, boolean top, boolean bottom) { - this(context, needCheck, top, bottom, null); + this(context, needCheck ? 1 : 0, top, bottom, null); } public ActionBarMenuSubItem(Context context, boolean top, boolean bottom, Theme.ResourcesProvider resourcesProvider) { - this(context, false, top, bottom, resourcesProvider); + this(context, 0, top, bottom, resourcesProvider); } public ActionBarMenuSubItem(Context context, boolean needCheck, boolean top, boolean bottom, Theme.ResourcesProvider resourcesProvider) { + this(context, needCheck ? 1 : 0, top, bottom, resourcesProvider); + } + + public ActionBarMenuSubItem(Context context, int needCheck, boolean top, boolean bottom, Theme.ResourcesProvider resourcesProvider) { super(context); this.resourcesProvider = resourcesProvider; @@ -78,12 +82,17 @@ public ActionBarMenuSubItem(Context context, boolean needCheck, boolean top, boo textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL)); - if (needCheck) { + if (needCheck > 0) { checkView = new CheckBox2(context, 26, resourcesProvider); checkView.setDrawUnchecked(false); checkView.setColor(null, null, Theme.key_radioBackgroundChecked); checkView.setDrawBackgroundAsArc(-1); - addView(checkView, LayoutHelper.createFrame(26, LayoutHelper.MATCH_PARENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT))); + if (needCheck == 1) { + addView(checkView, LayoutHelper.createFrame(26, LayoutHelper.MATCH_PARENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT))); + } else { + addView(checkView, LayoutHelper.createFrame(26, LayoutHelper.MATCH_PARENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT))); + textView.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(34) : 0, 0, LocaleController.isRTL ? 0 : AndroidUtilities.dp(34), 0); + } } } @@ -206,7 +215,7 @@ public void setSubtext(String text) { subtextView.setSingleLine(true); subtextView.setGravity(Gravity.LEFT); subtextView.setEllipsize(TextUtils.TruncateAt.END); - subtextView.setTextColor(0xff7C8286); + subtextView.setTextColor(getThemedColor(Theme.key_groupcreate_sectionText)); subtextView.setVisibility(GONE); subtextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); subtextView.setPadding(LocaleController.isRTL ? 0 : AndroidUtilities.dp(43), 0, LocaleController.isRTL ? AndroidUtilities.dp(43) : 0, 0); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java index 04ec758a289..5d6066159a8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java @@ -668,6 +668,10 @@ public void setLayoutInScreen(boolean value) { } private void init() { + View contentView = getContentView(); + if (contentView instanceof ActionBarPopupWindowLayout && ((ActionBarPopupWindowLayout) contentView).getSwipeBack() != null) { + ((ActionBarPopupWindowLayout) contentView).getSwipeBack().setOnClickListener(e -> dismiss()); + } if (superListenerField != null) { try { mSuperScrollListener = (ViewTreeObserver.OnScrollChangedListener) superListenerField.get(this); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java index 28b057374f9..d274dfbc446 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java @@ -94,7 +94,7 @@ public class AlertDialog extends Dialog implements Drawable.Callback, Notificati private BitmapDrawable[] shadow = new BitmapDrawable[2]; private boolean[] shadowVisibility = new boolean[2]; private AnimatorSet[] shadowAnimation = new AnimatorSet[2]; - private int customViewOffset = 20; + private int customViewOffset = 12; private String dialogButtonColorKey = Theme.key_dialogButton; @@ -277,7 +277,7 @@ public AlertDialog(Context context, int progressStyle, Theme.ResourcesProvider r if (progressStyle != ALERT_TYPE_SPINNER || blurredBackground) { shadowDrawable = context.getResources().getDrawable(R.drawable.popup_fixed_alert3).mutate(); backgroundColor = getThemedColor(Theme.key_dialogBackground); - blurOpacity = progressStyle == ALERT_TYPE_SPINNER ? 0.55f : (AndroidUtilities.computePerceivedBrightness(backgroundColor) < 0.721f ? 0.80f : 0.92f); + blurOpacity = progressStyle == ALERT_TYPE_SPINNER ? 0.55f : (AndroidUtilities.computePerceivedBrightness(backgroundColor) < 0.721f ? 0.80f : 0.97f); shadowDrawable.setColorFilter(new PorterDuffColorFilter(backgroundColor, PorterDuff.Mode.MULTIPLY)); shadowDrawable.getPadding(backgroundPaddings); } @@ -380,7 +380,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { availableHeight -= topImageView.getMeasuredHeight(); } if (topView != null) { - int w = width - AndroidUtilities.dp(16); + int w = width; int h; if (aspectRatio == 0) { float scale = w / 936.0f; @@ -781,10 +781,6 @@ public void setText(CharSequence text, BufferType type) { } if (!TextUtils.isEmpty(message)) { messageTextView.setText(message); - if (customView != null) { - ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) messageTextView.getLayoutParams(); - params.topMargin = AndroidUtilities.dp(16); - } messageTextView.setVisibility(View.VISIBLE); } else { messageTextView.setVisibility(View.GONE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java index f8c8507b150..dfb167c2bf9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java @@ -76,6 +76,7 @@ public class BottomSheet extends Dialog { public boolean drawNavigationBar; public boolean drawDoubleNavigationBar; public boolean scrollNavBar; + protected boolean waitingKeyboard; protected boolean useSmoothKeyboard; @@ -167,13 +168,14 @@ public void setAlpha(int alpha) { private OnDismissListener onHideListener; protected Theme.ResourcesProvider resourcesProvider; protected boolean isPortrait; + public boolean pauseAllHeavyOperations = true; public void setDisableScroll(boolean b) { disableScroll = b; } private ValueAnimator keyboardContentAnimator; - protected boolean smoothKeyboardAnimationEnabled; + public boolean smoothKeyboardAnimationEnabled; private boolean openNoDelay; private float hideSystemVerticalInsetsProgress; @@ -564,11 +566,18 @@ public void onAnimationEnd(Animator animation) { child.layout(childLeft, childTop, childLeft + width, childTop + height); } } - if (layoutCount == 0 && startAnimationRunnable != null) { + if (layoutCount == 0 && startAnimationRunnable != null && !waitingKeyboard) { AndroidUtilities.cancelRunOnUIThread(startAnimationRunnable); startAnimationRunnable.run(); startAnimationRunnable = null; } + if (waitingKeyboard && keyboardVisible) { + if (startAnimationRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(startAnimationRunnable); + startAnimationRunnable.run(); + } + waitingKeyboard = false; + } keyboardChanged = false; } @@ -1206,6 +1215,10 @@ public void show() { if (Build.VERSION.SDK_INT >= 18) { layoutCount = 2; containerView.setTranslationY((Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight * (1f - hideSystemVerticalInsetsProgress) : 0) + containerView.getMeasuredHeight() + (scrollNavBar ? getBottomInset() : 0)); + long delay = openNoDelay ? 0 : 150; + if (waitingKeyboard) { + delay = 500; + } AndroidUtilities.runOnUIThread(startAnimationRunnable = new Runnable() { @Override public void run() { @@ -1215,7 +1228,7 @@ public void run() { startAnimationRunnable = null; startOpenAnimation(); } - }, openNoDelay ? 0 : 150); + }, delay); } else { startOpenAnimation(); } @@ -1345,7 +1358,7 @@ private void startOpenAnimation() { navigationBarAnimation ); currentSheetAnimation.setDuration(400); - currentSheetAnimation.setStartDelay(20); + currentSheetAnimation.setStartDelay(waitingKeyboard ? 0 : 20); currentSheetAnimation.setInterpolator(openInterpolator); currentSheetAnimation.addListener(new AnimatorListenerAdapter() { @Override @@ -1366,7 +1379,9 @@ public void onAnimationEnd(Animator animation) { getWindow().setAttributes(params); } } - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.startAllHeavyOperations, 512); + if (pauseAllHeavyOperations) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.startAllHeavyOperations, 512); + } } @Override @@ -1377,7 +1392,9 @@ public void onAnimationCancel(Animator animation) { } } }); - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 512); + if (pauseAllHeavyOperations) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 512); + } currentSheetAnimation.start(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java index 52b57bb6ece..2e7555f69c1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java @@ -95,6 +95,7 @@ public class SimpleTextView extends View implements Drawable.Callback { private boolean rightDrawableOutside; private boolean ellipsizeByGradient, ellipsizeByGradientLeft; + private Boolean forceEllipsizeByGradientLeft; private int ellipsizeByGradientWidthDp = 16; private int paddingRight; @@ -192,15 +193,24 @@ public void setScrollNonFitText(boolean value) { } public void setEllipsizeByGradient(boolean value) { + setEllipsizeByGradient(value, null); + } + + public void setEllipsizeByGradient(int value) { + setEllipsizeByGradient(value, null); + } + + public void setEllipsizeByGradient(boolean value, Boolean forceLeft) { if (scrollNonFitText == value) { return; } ellipsizeByGradient = value; + this.forceEllipsizeByGradientLeft = forceLeft; updateFadePaints(); } - public void setEllipsizeByGradient(int value) { - setEllipsizeByGradient(true); + public void setEllipsizeByGradient(int value, Boolean forceLeft) { + setEllipsizeByGradient(true, forceLeft); ellipsizeByGradientWidthDp = value; updateFadePaints(); } @@ -219,7 +229,12 @@ private void updateFadePaints() { fadePaintBack.setShader(new LinearGradient(0, 0, AndroidUtilities.dp(6), 0, new int[]{0, 0xffffffff}, new float[]{0f, 1f}, Shader.TileMode.CLAMP)); fadePaintBack.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); } - boolean ellipsizeLeft = getAlignment() == Layout.Alignment.ALIGN_NORMAL && LocaleController.isRTL || getAlignment() == Layout.Alignment.ALIGN_OPPOSITE && !LocaleController.isRTL; + boolean ellipsizeLeft; + if (forceEllipsizeByGradientLeft != null) { + ellipsizeLeft = forceEllipsizeByGradientLeft; + } else { + ellipsizeLeft = getAlignment() == Layout.Alignment.ALIGN_NORMAL && LocaleController.isRTL || getAlignment() == Layout.Alignment.ALIGN_OPPOSITE && !LocaleController.isRTL; + } if ((fadeEllpsizePaint == null || fadeEllpsizePaintWidth != AndroidUtilities.dp(ellipsizeByGradientWidthDp) || ellipsizeByGradientLeft != ellipsizeLeft) && ellipsizeByGradient) { if (fadeEllpsizePaint == null) { fadeEllpsizePaint = new Paint(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java index d47e462d583..6c1ad0973ce 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java @@ -9,6 +9,7 @@ package org.telegram.ui.ActionBar; import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; import android.annotation.SuppressLint; import android.annotation.TargetApi; @@ -143,6 +144,11 @@ public class Theme { public static final int MSG_OUT_COLOR_BLACK = 0xff212121; public static final int MSG_OUT_COLOR_WHITE = 0xffffffff; + public static final int default_shadow_color = ColorUtils.setAlphaComponent(Color.BLACK, 27); + + public static void applyDefaultShadow(Paint paint) { + paint.setShadowLayer(dpf2(1), 0, dpf2(0.33f), default_shadow_color); + } public static class BackgroundDrawableSettings { @@ -4007,6 +4013,17 @@ public void run() { public final static String key_statisticChartLine_cyan = "statisticChartLine_cyan"; public final static String key_statisticChartLineEmpty = "statisticChartLineEmpty"; + public final static String key_color_lightblue = "color_lightblue"; + public final static String key_color_blue = "color_blue"; + public final static String key_color_green = "color_green"; + public final static String key_color_lightgreen = "color_lightgreen"; + public final static String key_color_red = "color_red"; + public final static String key_color_orange = "color_orange"; + public final static String key_color_yellow = "color_yellow"; + public final static String key_color_purple = "color_purple"; + public final static String key_color_cyan = "color_cyan"; + public final static String[] keys_colors = { key_color_lightblue, key_color_blue, key_color_green, key_color_lightgreen, key_color_red, key_color_orange, key_color_yellow, key_color_purple, key_color_cyan }; + public static final String key_chat_outReactionButtonBackground = "chat_outReactionButtonBackground"; public static final String key_chat_inReactionButtonBackground = "chat_inReactionButtonBackground"; public static final String key_chat_outReactionButtonText = "chat_outReactionButtonText"; @@ -4848,6 +4865,16 @@ public void run() { defaultColors.put(key_statisticChartLineEmpty, 0xFFEEEEEE); defaultColors.put(key_actionBarTipBackground, 0xFF446F94); + defaultColors.put(key_color_blue, 0xff327FE5); + defaultColors.put(key_color_green, 0xff61C752); + defaultColors.put(key_color_red, 0xffE05356); + defaultColors.put(key_color_yellow, 0xffEBA52D); + defaultColors.put(key_color_lightblue, 0xff58A8ED); + defaultColors.put(key_color_lightgreen, 0xff8FCF39); + defaultColors.put(key_color_orange, 0xffF28C39); + defaultColors.put(key_color_purple, 0xff9F79E8); + defaultColors.put(key_color_cyan, 0xff40D0CA); + defaultColors.put(key_voipgroup_checkMenu, 0xff6BB6F9); defaultColors.put(key_voipgroup_muteButton, 0xff77E55C); defaultColors.put(key_voipgroup_muteButton2, 0xff7DDCAA); @@ -5101,9 +5128,19 @@ public void run() { fallbackKeys.put(key_avatar_background2Blue, key_avatar_backgroundBlue); fallbackKeys.put(key_avatar_background2Pink, key_avatar_backgroundPink); + fallbackKeys.put(key_statisticChartLine_orange, key_color_orange); + fallbackKeys.put(key_statisticChartLine_blue, key_color_blue); + fallbackKeys.put(key_statisticChartLine_red, key_color_red); + fallbackKeys.put(key_statisticChartLine_lightblue, key_color_lightblue); + fallbackKeys.put(key_statisticChartLine_golden, key_color_yellow); + fallbackKeys.put(key_statisticChartLine_purple, key_color_purple); + fallbackKeys.put(key_statisticChartLine_indigo, key_color_purple); + fallbackKeys.put(key_statisticChartLine_cyan, key_color_cyan); + themeAccentExclusionKeys.addAll(Arrays.asList(keys_avatar_background)); themeAccentExclusionKeys.addAll(Arrays.asList(keys_avatar_background2)); themeAccentExclusionKeys.addAll(Arrays.asList(keys_avatar_nameInMessage)); + themeAccentExclusionKeys.addAll(Arrays.asList(keys_colors)); themeAccentExclusionKeys.add(key_chat_attachFileBackground); themeAccentExclusionKeys.add(key_chat_attachGalleryBackground); themeAccentExclusionKeys.add(key_chat_attachFileText); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java index 620e73e6ae3..a75dfc9a5fa 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java @@ -39,6 +39,7 @@ import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; @@ -48,8 +49,10 @@ import org.telegram.ui.Cells.DialogCell; import org.telegram.ui.Cells.DialogMeUrlCell; import org.telegram.ui.Cells.DialogsEmptyCell; +import org.telegram.ui.Cells.DialogsRequestedEmptyCell; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.ProfileSearchCell; +import org.telegram.ui.Cells.RequestPeerRequirementsCell; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; @@ -83,7 +86,9 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements VIEW_TYPE_NEW_CHAT_HINT = 11, VIEW_TYPE_TEXT = 12, VIEW_TYPE_CONTACTS_FLICKER = 13, - VIEW_TYPE_HEADER_2 = 14; + VIEW_TYPE_HEADER_2 = 14, + VIEW_TYPE_REQUIREMENTS = 15, + VIEW_TYPE_REQUIRED_EMPTY = 16; private Context mContext; private ArchiveHintCell archiveHintCell; @@ -119,7 +124,10 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements private boolean isTransitionSupport; private boolean fromDiffUtils; - public DialogsAdapter(DialogsActivity fragment, Context context, int type, int folder, boolean onlySelect, ArrayList selected, int account) { + private TLRPC.RequestPeerType requestPeerType; + public boolean isEmpty; + + public DialogsAdapter(DialogsActivity fragment, Context context, int type, int folder, boolean onlySelect, ArrayList selected, int account, TLRPC.RequestPeerType requestPeerType) { mContext = context; parentFragment = fragment; dialogsType = type; @@ -136,6 +144,7 @@ public DialogsAdapter(DialogsActivity fragment, Context context, int type, int f if (folder == 0) { this.preloader = new DialogsPreloader(); } + this.requestPeerType = requestPeerType; } public void setRecyclerListView(RecyclerListView recyclerListView) { @@ -156,9 +165,9 @@ public int fixPosition(int position) { } if (showArchiveHint) { position -= 2; - } else if (dialogsType == 11 || dialogsType == 13) { + } else if (dialogsType == DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_GROUPS || dialogsType == DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY) { position -= 2; - } else if (dialogsType == 12) { + } else if (dialogsType == DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_USERS) { position -= 1; } return position; @@ -368,7 +377,7 @@ public ViewPager getArchiveHintCellPager() { } public void updateHasHints() { - hasHints = folderId == 0 && dialogsType == 0 && !isOnlySelect && !MessagesController.getInstance(currentAccount).hintDialogs.isEmpty(); + hasHints = folderId == 0 && dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT && !isOnlySelect && !MessagesController.getInstance(currentAccount).hintDialogs.isEmpty(); } public void updateList(RecyclerListView recyclerListView, boolean hasHiddenArchive, float tabsTranslation) { @@ -451,7 +460,8 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { int viewType = holder.getItemViewType(); return viewType != VIEW_TYPE_FLICKER && viewType != VIEW_TYPE_EMPTY && viewType != VIEW_TYPE_DIVIDER && viewType != VIEW_TYPE_SHADOW && viewType != VIEW_TYPE_HEADER && viewType != VIEW_TYPE_ARCHIVE && - viewType != VIEW_TYPE_LAST_EMPTY && viewType != VIEW_TYPE_NEW_CHAT_HINT && viewType != VIEW_TYPE_CONTACTS_FLICKER; + viewType != VIEW_TYPE_LAST_EMPTY && viewType != VIEW_TYPE_NEW_CHAT_HINT && viewType != VIEW_TYPE_CONTACTS_FLICKER && + viewType != VIEW_TYPE_REQUIREMENTS && viewType != VIEW_TYPE_REQUIRED_EMPTY; } @Override @@ -459,7 +469,8 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewT View view; switch (viewType) { case VIEW_TYPE_DIALOG: - if (dialogsType == 2) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO || + dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { view = new ProfileSearchCell(mContext); } else { DialogCell dialogCell = new DialogCell(parentFragment, mContext, true, false, currentAccount, null); @@ -469,6 +480,12 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewT dialogCell.setIsTransitionSupport(isTransitionSupport); view = dialogCell; } + if (dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + } + break; + case VIEW_TYPE_REQUIREMENTS: + view = new RequestPeerRequirementsCell(mContext); break; case VIEW_TYPE_FLICKER: case VIEW_TYPE_CONTACTS_FLICKER: @@ -524,6 +541,14 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { case VIEW_TYPE_EMPTY: view = new DialogsEmptyCell(mContext); break; + case VIEW_TYPE_REQUIRED_EMPTY: + view = new DialogsRequestedEmptyCell(mContext) { + @Override + protected void onButtonClick() { + onCreateGroupForThisClick(); + } + }; + break; case VIEW_TYPE_USER: view = new UserCell(mContext, 8, 0, false); break; @@ -611,12 +636,19 @@ protected void onTextDraw() { case VIEW_TYPE_TEXT: default: { view = new TextCell(mContext); + if (dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + } } } view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, viewType == 5 ? RecyclerView.LayoutParams.MATCH_PARENT : RecyclerView.LayoutParams.WRAP_CONTENT)); return new RecyclerListView.Holder(view); } + public void onCreateGroupForThisClick() { + + } + public int lastDialogsEmptyType = -1; public int dialogsEmptyType() { @@ -637,10 +669,11 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int i) { case VIEW_TYPE_DIALOG: { TLRPC.Dialog dialog = (TLRPC.Dialog) getItem(i); TLRPC.Dialog nextDialog = (TLRPC.Dialog) getItem(i + 1); - if (dialogsType == 2) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO || dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { ProfileSearchCell cell = (ProfileSearchCell) holder.itemView; long oldDialogId = cell.getDialogId(); + TLObject object = null; TLRPC.Chat chat = null; CharSequence title = null; CharSequence subtitle; @@ -657,6 +690,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int i) { } if (chat != null) { + object = chat; title = chat.title; if (ChatObject.isChannel(chat) && !chat.megagroup) { if (chat.participants_count != 0) { @@ -683,15 +717,27 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int i) { } } else { subtitle = ""; + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(dialog.id); + if (user != null) { + object = user; + title = UserObject.getUserName(user); + if (!UserObject.isReplyUser(user)) { + if (user.bot) { + subtitle = LocaleController.getString("Bot", R.string.Bot); + } else { + subtitle = LocaleController.formatUserStatus(currentAccount, user); + } + } + } } cell.useSeparator = nextDialog != null; - cell.setData(chat, null, title, subtitle, isRecent, false); + cell.setData(object, null, title, subtitle, isRecent, false); cell.setChecked(selectedDialogs.contains(cell.getDialogId()), oldDialogId == cell.getDialogId()); } else { DialogCell cell = (DialogCell) holder.itemView; cell.useSeparator = nextDialog != null; cell.fullSeparator = dialog.pinned && nextDialog != null && !nextDialog.pinned; - if (dialogsType == 0) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT) { if (AndroidUtilities.isTablet()) { cell.setDialogSelected(dialog.id == openedDialogId); } @@ -734,6 +780,10 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int i) { } break; } + case VIEW_TYPE_REQUIRED_EMPTY: { + ((DialogsRequestedEmptyCell) holder.itemView).set(requestPeerType); + break; + } case VIEW_TYPE_ME_URL: { DialogMeUrlCell cell = (DialogMeUrlCell) holder.itemView; cell.setRecentMeUrl((TLRPC.RecentMeUrl) getItem(i)); @@ -747,7 +797,11 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int i) { } case VIEW_TYPE_HEADER: { HeaderCell cell = (HeaderCell) holder.itemView; - if (dialogsType == 11 || dialogsType == 12 || dialogsType == 13) { + if ( + dialogsType == DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_GROUPS || + dialogsType == DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_USERS || + dialogsType == DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY + ) { if (i == 0) { cell.setText(LocaleController.getString("ImportHeader", R.string.ImportHeader)); } else { @@ -792,11 +846,24 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int i) { case VIEW_TYPE_TEXT: { TextCell cell = (TextCell) holder.itemView; cell.setColors(Theme.key_windowBackgroundWhiteBlueText4, Theme.key_windowBackgroundWhiteBlueText4); - cell.setTextAndIcon(LocaleController.getString("CreateGroupForImport", R.string.CreateGroupForImport), R.drawable.msg_groups_create, dialogsCount != 0); + if (requestPeerType != null) { + if (requestPeerType instanceof TLRPC.TL_requestPeerTypeBroadcast) { + cell.setTextAndIcon(LocaleController.getString("CreateChannelForThis", R.string.CreateChannelForThis), R.drawable.msg_channel_create, true); + } else { + cell.setTextAndIcon(LocaleController.getString("CreateGroupForThis", R.string.CreateGroupForThis), R.drawable.msg_groups_create, true); + } + } else { + cell.setTextAndIcon(LocaleController.getString("CreateGroupForImport", R.string.CreateGroupForImport), R.drawable.msg_groups_create, dialogsCount != 0); + } cell.setIsInDialogs(); cell.setOffsetFromImage(75); break; } + case VIEW_TYPE_REQUIREMENTS: { + RequestPeerRequirementsCell cell = (RequestPeerRequirementsCell) holder.itemView; + cell.set(requestPeerType); + break; + } } if (i >= dialogsCount + 1) { holder.itemView.setAlpha(1f); @@ -1098,6 +1165,7 @@ private void updateItemList() { MessagesController messagesController = MessagesController.getInstance(currentAccount); ArrayList array = parentFragment.getDialogsArray(currentAccount, dialogsType, folderId, dialogsListFrozen); dialogsCount = array.size(); + isEmpty = false; if (!hasHints && dialogsType == 0 && folderId == 0 && messagesController.isDialogsEndReached(folderId) && !forceUpdatingContacts) { if (messagesController.getAllFoldersDialogsCount() <= 10 && ContactsController.getInstance(currentAccount).doneLoadingContacts && !ContactsController.getInstance(currentAccount).contacts.isEmpty()) { @@ -1121,6 +1189,10 @@ private void updateItemList() { } } + if (requestPeerType != null) { + itemInternals.add(new ItemInternal(VIEW_TYPE_REQUIREMENTS)); + } + boolean stopUpdate = false; if (collapsedView || isTransitionSupport) { for (int k = 0; k < array.size(); k++) { @@ -1134,13 +1206,15 @@ private void updateItemList() { } if (dialogsCount == 0 && forceUpdatingContacts) { - itemInternals.add(new ItemInternal(VIEW_TYPE_EMPTY)); + isEmpty = true; + itemInternals.add(new ItemInternal(requestPeerType == null ? VIEW_TYPE_EMPTY : VIEW_TYPE_REQUIRED_EMPTY)); itemInternals.add(new ItemInternal(VIEW_TYPE_SHADOW)); itemInternals.add(new ItemInternal(VIEW_TYPE_HEADER)); itemInternals.add(new ItemInternal(VIEW_TYPE_CONTACTS_FLICKER)); } else if (onlineContacts != null) { if (dialogsCount == 0) { - itemInternals.add(new ItemInternal(VIEW_TYPE_EMPTY)); + isEmpty = true; + itemInternals.add(new ItemInternal(requestPeerType == null ? VIEW_TYPE_EMPTY : VIEW_TYPE_REQUIRED_EMPTY)); itemInternals.add(new ItemInternal(VIEW_TYPE_SHADOW)); itemInternals.add(new ItemInternal(VIEW_TYPE_HEADER)); } else { @@ -1165,16 +1239,20 @@ private void updateItemList() { } else if (showArchiveHint) { itemInternals.add(new ItemInternal(VIEW_TYPE_ARCHIVE)); itemInternals.add(new ItemInternal(VIEW_TYPE_SHADOW)); - } else if (dialogsType == 11 || dialogsType == 13) { + } else if (dialogsType == DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_GROUPS || dialogsType == DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY) { itemInternals.add(new ItemInternal(VIEW_TYPE_HEADER)); itemInternals.add(new ItemInternal(VIEW_TYPE_TEXT)); - } else if (dialogsType == 12) { + } else if (dialogsType == DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_USERS) { itemInternals.add(new ItemInternal(VIEW_TYPE_HEADER)); } + if ((requestPeerType instanceof TLRPC.TL_requestPeerTypeBroadcast || requestPeerType instanceof TLRPC.TL_requestPeerTypeChat) && dialogsCount > 0) { + itemInternals.add(new ItemInternal(VIEW_TYPE_TEXT)); + } + if (!stopUpdate) { for (int k = 0; k < array.size(); k++) { - if (dialogsType == 2 && array.get(k) instanceof DialogsActivity.DialogsHeader) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO && array.get(k) instanceof DialogsActivity.DialogsHeader) { itemInternals.add(new ItemInternal(VIEW_TYPE_HEADER_2, array.get(k))); } else { itemInternals.add(new ItemInternal(VIEW_TYPE_DIALOG, array.get(k))); @@ -1185,9 +1263,10 @@ private void updateItemList() { if (!forceShowEmptyCell && dialogsType != 7 && dialogsType != 8 && !MessagesController.getInstance(currentAccount).isDialogsEndReached(folderId)) { itemInternals.add(new ItemInternal(VIEW_TYPE_FLICKER)); } else if (dialogsCount == 0) { - itemInternals.add(new ItemInternal(VIEW_TYPE_EMPTY)); + isEmpty = true; + itemInternals.add(new ItemInternal(requestPeerType == null ? VIEW_TYPE_EMPTY : VIEW_TYPE_REQUIRED_EMPTY)); } else { - if (folderId == 0 && dialogsCount > 10 && dialogsType == 0) { + if (folderId == 0 && dialogsCount > 10 && dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT) { itemInternals.add(new ItemInternal(VIEW_TYPE_NEW_CHAT_HINT)); } itemInternals.add(new ItemInternal(VIEW_TYPE_LAST_EMPTY)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java index b825710f319..aa96322e900 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java @@ -53,6 +53,7 @@ import org.telegram.ui.Components.FlickerLoadingView; import org.telegram.ui.Components.ForegroundColorSpanThemable; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.DialogsActivity; import org.telegram.ui.FilteredSearchView; import java.util.ArrayList; @@ -109,6 +110,7 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { private long lastShowMoreUpdate; public View showMoreHeader; private Runnable cancelShowMoreAnimation; + private ArrayList filterDialogIds; private int currentAccount = UserConfig.selectedAccount; @@ -124,6 +126,10 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { private int folderId; private ArrayList allContacts; + public void setFilterDialogIds(ArrayList filterDialogIds) { + this.filterDialogIds = filterDialogIds; + } + public boolean isSearching() { return waitingResponseCount > 0; } @@ -312,6 +318,10 @@ private void searchForumMessagesInternal(final String query, int searchId) { return; } + if (dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { + return; + } + final long dialogId = delegate.getSearchForumDialogId(); final TLRPC.TL_messages_search req = new TLRPC.TL_messages_search(); @@ -432,6 +442,15 @@ private void searchMessagesInternal(final String query, int searchId) { searchAdapterHelper.mergeResults(searchResult, filtered2RecentSearchObjects); } + if (dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { + waitingResponseCount--; + if (delegate != null) { + delegate.searchStateChanged(waitingResponseCount > 0, true); + delegate.runResultsEnterAnimation(); + } + return; + } + final TLRPC.TL_messages_searchGlobal req = new TLRPC.TL_messages_searchGlobal(); req.limit = 20; req.q = query; @@ -547,7 +566,14 @@ public boolean hasRecentSearch() { } private boolean resentSearchAvailable() { - return dialogsType != 2 && dialogsType != 4 && dialogsType != 5 && dialogsType != 6 && dialogsType != 11; + return ( + dialogsType != DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO && + dialogsType != DialogsActivity.DIALOGS_TYPE_USERS_ONLY && + dialogsType != DialogsActivity.DIALOGS_TYPE_CHANNELS_ONLY && + dialogsType != DialogsActivity.DIALOGS_TYPE_GROUPS_ONLY && + dialogsType != DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_GROUPS && + dialogsType != DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER + ); } public boolean isSearchWas() { @@ -559,6 +585,9 @@ public boolean isRecentSearchDisplayed() { } public void loadRecentSearch() { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { + return; + } loadRecentSearch(currentAccount, dialogsType, (arrayList, hashMap) -> { DialogsSearchAdapter.this.setRecentSearch(arrayList, hashMap); }); @@ -581,7 +610,7 @@ public static void loadRecentSearch(int currentAccount, int dialogsType, OnRecen boolean add = false; if (DialogObject.isEncryptedDialog(did)) { - if (dialogsType == 0 || dialogsType == 3) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT || dialogsType == DialogsActivity.DIALOGS_TYPE_FORWARD) { int encryptedChatId = DialogObject.getEncryptedChatId(did); if (!encryptedToLoad.contains(encryptedChatId)) { encryptedToLoad.add(encryptedChatId); @@ -792,7 +821,8 @@ private void searchDialogsInternal(final String query, final int searchId) { ArrayList resultArrayNames = new ArrayList<>(); ArrayList encUsers = new ArrayList<>(); ArrayList contacts = new ArrayList<>(); - MessagesStorage.getInstance(currentAccount).localSearch(dialogsType, q, resultArray, resultArrayNames, encUsers, -1); + + MessagesStorage.getInstance(currentAccount).localSearch(dialogsType, q, resultArray, resultArrayNames, encUsers, filterDialogIds, -1); // if (allContacts == null) { // allContacts = new ArrayList<>(); // for (ContactsController.Contact contact : ContactsController.getInstance(currentAccount).phoneBookContacts) { @@ -947,7 +977,21 @@ public void searchDialogs(String text, int folderId) { searchResultNames.clear(); searchResultHashtags.clear(); searchAdapterHelper.mergeResults(null, null); - searchAdapterHelper.queryServerSearch(null, true, true, dialogsType != 11, dialogsType != 11, dialogsType == 2 || dialogsType == 11, 0, dialogsType == 0, 0, 0, delegate != null ? delegate.getSearchForumDialogId() : 0); + if (dialogsType != DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { + searchAdapterHelper.queryServerSearch( + null, + true, + true, + dialogsType != DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_GROUPS, + dialogsType != DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_GROUPS, + dialogsType == DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO || dialogsType == DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_GROUPS, + 0, + dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT, + 0, + 0, + delegate != null ? delegate.getSearchForumDialogId() : 0 + ); + } searchWas = false; lastSearchId = 0; waitingResponseCount = 0; @@ -956,9 +1000,11 @@ public void searchDialogs(String text, int folderId) { if (delegate != null) { delegate.searchStateChanged(false, true); } - searchTopics(null); - searchMessagesInternal(null, 0); - searchForumMessagesInternal(null, 0); + if (dialogsType != DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { + searchTopics(null); + searchMessagesInternal(null, 0); + searchForumMessagesInternal(null, 0); + } notifyDataSetChanged(); localTipDates.clear(); localTipArchive = false; @@ -1000,17 +1046,33 @@ public void searchDialogs(String text, int folderId) { Utilities.searchQueue.postRunnable(searchRunnable = () -> { searchRunnable = null; searchDialogsInternal(query, searchId); + if (dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { + waitingResponseCount -= 2; + return; + } AndroidUtilities.runOnUIThread(searchRunnable2 = () -> { searchRunnable2 = null; if (searchId != lastSearchId) { return; } - if (needMessagesSearch != 2) { - searchAdapterHelper.queryServerSearch(query, true, dialogsType != 4, true, dialogsType != 4 && dialogsType != 11, dialogsType == 2 || dialogsType == 1, 0, dialogsType == 0, 0, searchId, delegate != null ? delegate.getSearchForumDialogId() : 0); + if (needMessagesSearch != 2 && dialogsType != DialogsActivity.DIALOGS_TYPE_GROUPS_ONLY && dialogsType != DialogsActivity.DIALOGS_TYPE_CHANNELS_ONLY) { + searchAdapterHelper.queryServerSearch( + query, + true, + dialogsType != DialogsActivity.DIALOGS_TYPE_USERS_ONLY, + true, + dialogsType != DialogsActivity.DIALOGS_TYPE_USERS_ONLY && dialogsType != DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_GROUPS, + dialogsType == DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO || dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_SHARE, + 0, + dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT, + 0, + searchId, + delegate != null ? delegate.getSearchForumDialogId() : 0 + ); } else { waitingResponseCount -= 2; } - if (needMessagesSearch == 0) { + if (needMessagesSearch == 0 || dialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { waitingResponseCount--; } else { searchTopics(text); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java index 5cab8a19d2a..4a5a3e14575 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java @@ -167,7 +167,7 @@ import org.telegram.ui.Components.TextPaintSpan; import org.telegram.ui.Components.TextPaintUrlSpan; import org.telegram.ui.Components.TextPaintWebpageUrlSpan; -import org.telegram.ui.Components.TranslateAlert; +import org.telegram.ui.Components.TranslateAlert2; import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.Components.WebPlayerView; @@ -1211,7 +1211,14 @@ private void showCopyPopup(String urlFinal) { } BottomSheet.Builder builder = new BottomSheet.Builder(parentActivity); - builder.setTitle(urlFinal); + String formattedUrl = urlFinal; + try { + formattedUrl = URLDecoder.decode(urlFinal.replaceAll("\\+", "%2b"), "UTF-8"); + } catch (Exception e) { + FileLog.e(e); + } + builder.setTitle(formattedUrl); + builder.setTitleMultipleLines(true); builder.setItems(new CharSequence[]{LocaleController.getString("Open", R.string.Open), LocaleController.getString("Copy", R.string.Copy)}, (dialog, which) -> { if (parentActivity == null) { return; @@ -2648,22 +2655,24 @@ private boolean checkLayoutForLinks(WebpageAdapter adapter, MotionEvent event, V pressedEnd = end; } } - if (pressedLink != null) { - links.removeLink(pressedLink); - } - pressedLink = new LinkSpanDrawable(selectedLink, null, x, y); - pressedLink.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkSelection) & 0x33ffffff); - links.addLink(pressedLink, pressedLinkOwnerLayout); - try { - LinkPath path = pressedLink.obtainNewPath(); - path.setCurrentLayout(layout, pressedStart, 0); - TextPaint textPaint = selectedLink.getTextPaint(); - int shift = textPaint != null ? textPaint.baselineShift : 0; - path.setBaselineShift(shift != 0 ? shift + AndroidUtilities.dp(shift > 0 ? 5 : -2) : 0); - layout.getSelectionPath(pressedStart, pressedEnd, path); - parentView.invalidate(); - } catch (Exception e) { - FileLog.e(e); + if (pressedLink == null || pressedLink.getSpan() != selectedLink) { + if (pressedLink != null) { + links.removeLink(pressedLink); + } + pressedLink = new LinkSpanDrawable(selectedLink, null, x, y); + pressedLink.setColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkSelection) & 0x33ffffff); + links.addLink(pressedLink, pressedLinkOwnerLayout); + try { + LinkPath path = pressedLink.obtainNewPath(); + path.setCurrentLayout(layout, pressedStart, 0); + TextPaint textPaint = selectedLink.getTextPaint(); + int shift = textPaint != null ? textPaint.baselineShift : 0; + path.setBaselineShift(shift != 0 ? shift + AndroidUtilities.dp(shift > 0 ? 5 : -2) : 0); + layout.getSelectionPath(pressedStart, pressedEnd, path); + parentView.invalidate(); + } catch (Exception e) { + FileLog.e(e); + } } } } @@ -3671,10 +3680,8 @@ public void onDraw(Canvas canvas) { boolean isLightNavigation = navigationBrightness >= 0.721f; if (isLightNavigation && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { uiFlags |= View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; - navigationBarPaint.setColor(navigationColor); - } else if (!isLightNavigation) { - navigationBarPaint.setColor(navigationColor); } + navigationBarPaint.setColor(navigationColor); windowLayoutParams.systemUiVisibility = uiFlags; if (Build.VERSION.SDK_INT >= 21) { @@ -3688,9 +3695,9 @@ public void onDraw(Canvas canvas) { textSelectionHelper = new TextSelectionHelper.ArticleTextSelectionHelper(); textSelectionHelper.setParentView(listView[0]); - if (MessagesController.getGlobalMainSettings().getBoolean("translate_button", false)) { + if (MessagesController.getInstance(currentAccount).getTranslateController().isContextTranslateEnabled()) { textSelectionHelper.setOnTranslate((text, fromLang, toLang, onAlertDismiss) -> { - TranslateAlert.showAlert(parentActivity, parentFragment, currentAccount, fromLang, toLang, text, false, null, onAlertDismiss); + TranslateAlert2.showAlert(parentActivity, parentFragment, currentAccount, fromLang, toLang, text, null, false, null, onAlertDismiss); }); } textSelectionHelper.layoutManager = layoutManager[0]; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/BubbleActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/BubbleActivity.java index e40e1625568..ba1487ce60a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/BubbleActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/BubbleActivity.java @@ -122,7 +122,7 @@ private void showPasscodeActivity() { passcodeView.onShow(true, false); SharedConfig.isWaitingForPasscodeEnter = true; drawerLayoutContainer.setAllowOpenDrawer(false, false); - passcodeView.setDelegate(() -> { + passcodeView.setDelegate(view -> { SharedConfig.isWaitingForPasscodeEnter = false; if (passcodeSaveIntent != null) { handleIntent(passcodeSaveIntent, passcodeSaveIntentIsNew, passcodeSaveIntentIsRestore, true, passcodeSaveIntentAccount, passcodeSaveIntentState); @@ -130,6 +130,8 @@ private void showPasscodeActivity() { } drawerLayoutContainer.setAllowOpenDrawer(true, false); actionBarLayout.showLastFragment(); + + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.passcodeDismissed, view); }); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CacheChatsExceptionsFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/CacheChatsExceptionsFragment.java index 2290b737fee..feb3792555e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CacheChatsExceptionsFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CacheChatsExceptionsFragment.java @@ -81,11 +81,11 @@ public void onItemClick(int id) { args.putBoolean("onlySelect", true); args.putBoolean("checkCanWrite", false); if (currentType == CacheControlActivity.KEEP_MEDIA_TYPE_GROUP) { - args.putInt("dialogsType", 6); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_GROUPS_ONLY); } else if (currentType == CacheControlActivity.KEEP_MEDIA_TYPE_CHANNEL) { - args.putInt("dialogsType", 5); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_CHANNELS_ONLY); } else { - args.putInt("dialogsType", 4); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_USERS_ONLY); } args.putBoolean("allowGlobalSearch", false); DialogsActivity activity = new DialogsActivity(args); @@ -123,6 +123,7 @@ public void onItemClick(int id) { int finalP = p; showPopupFor(newException); } + return true; }); presentFragment(activity); } else if (items.get(position).viewType == VIEW_TYPE_CHAT) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java index a5cc6db4717..29dc170392f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java @@ -170,7 +170,7 @@ public class CacheControlActivity extends BaseFragment implements NotificationCe private CacheChartHeader cacheChartHeader; private ClearCacheButtonInternal clearCacheButton; - private volatile boolean canceled = false; + public static volatile boolean canceled = false; private View bottomSheetView; private BottomSheet bottomSheet; @@ -208,9 +208,105 @@ private void updateDatabaseItemSize() { } } + private static long lastTotalSizeCalculatedTime; + private static Long lastTotalSizeCalculated; + private static Long lastDeviceTotalSize, lastDeviceTotalFreeSize; + + public static void calculateTotalSize(Utilities.Callback onDone) { + if (onDone == null) { + return; + } + if (lastTotalSizeCalculated != null) { + onDone.run(lastTotalSizeCalculated); + if (System.currentTimeMillis() - lastTotalSizeCalculatedTime < 5000) { + return; + } + } + Utilities.globalQueue.postRunnable(() -> { + canceled = false; + long cacheSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_CACHE), 5); + long cacheTempSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_CACHE), 4); + long photoSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_IMAGE), 0); + photoSize += getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_IMAGE_PUBLIC), 0); + long videoSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_VIDEO), 0); + videoSize += getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_VIDEO_PUBLIC), 0); + long documentsSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_DOCUMENT), 1); + documentsSize += getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_FILES), 1); + long musicSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_DOCUMENT), 2); + musicSize += getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_FILES), 2); + long stickersCacheSize = getDirectorySize(new File(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_CACHE), "acache"), 0); + stickersCacheSize += getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_CACHE), 3); + long audioSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_AUDIO), 0); + final long totalSize = lastTotalSizeCalculated = cacheSize + cacheTempSize + videoSize + audioSize + photoSize + documentsSize + musicSize + stickersCacheSize; + lastTotalSizeCalculatedTime = System.currentTimeMillis(); + if (!canceled) { + AndroidUtilities.runOnUIThread(() -> { + onDone.run(totalSize); + }); + } + }); + } + + public static void getDeviceTotalSize(Utilities.Callback2 onDone) { + if (lastDeviceTotalSize != null && lastDeviceTotalFreeSize != null) { + if (onDone != null) { + onDone.run(lastDeviceTotalSize, lastDeviceTotalFreeSize); + } + return; + } + File path; + if (Build.VERSION.SDK_INT >= 19) { + ArrayList storageDirs = AndroidUtilities.getRootDirs(); + String dir = (path = storageDirs.get(0)).getAbsolutePath(); + if (!TextUtils.isEmpty(SharedConfig.storageCacheDir)) { + for (int a = 0, N = storageDirs.size(); a < N; a++) { + File file = storageDirs.get(a); + if (file.getAbsolutePath().startsWith(SharedConfig.storageCacheDir)) { + path = file; + break; + } + } + } + } else { + path = new File(SharedConfig.storageCacheDir); + } + try { + StatFs stat = new StatFs(path.getPath()); + long blockSize; + long blockSizeExternal; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + blockSize = stat.getBlockSizeLong(); + } else { + blockSize = stat.getBlockSize(); + } + long availableBlocks; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + availableBlocks = stat.getAvailableBlocksLong(); + } else { + availableBlocks = stat.getAvailableBlocks(); + } + long blocksTotal; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + blocksTotal = stat.getBlockCountLong(); + } else { + blocksTotal = stat.getBlockCount(); + } + + lastDeviceTotalSize = blocksTotal * blockSize; + lastDeviceTotalFreeSize = availableBlocks * blockSize; + if (onDone != null) { + onDone.run(lastDeviceTotalSize, lastDeviceTotalFreeSize); + } + return; + } catch (Exception e) { + FileLog.e(e); + } + } + @Override public boolean onFragmentCreate() { super.onFragmentCreate(); + canceled = false; getNotificationCenter().addObserver(this, NotificationCenter.didClearDatabase); databaseSize = MessagesStorage.getInstance(currentAccount).getDatabaseSize(); loadingDialogs = true; @@ -256,7 +352,11 @@ public boolean onFragmentCreate() { } stickersCacheSize += cacheEmojiSize; audioSize = getDirectorySize(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_AUDIO), 0); - totalSize = cacheSize + cacheTempSize + videoSize + audioSize + photoSize + documentsSize + musicSize + stickersCacheSize; + if (canceled) { + return; + } + totalSize = lastTotalSizeCalculated = cacheSize + cacheTempSize + videoSize + audioSize + photoSize + documentsSize + musicSize + stickersCacheSize; + lastTotalSizeCalculatedTime = System.currentTimeMillis(); File path; if (Build.VERSION.SDK_INT >= 19) { @@ -302,14 +402,13 @@ public boolean onFragmentCreate() { FileLog.e(e); } - long minDuration = System.currentTimeMillis() - fragmentCreateTime > 45 ? 600 : 0; AndroidUtilities.runOnUIThread(() -> { resumeDelayedFragmentAnimation(); calculating = false; updateRows(true); updateChart(); - }, Math.max(1, minDuration - (System.currentTimeMillis() - fragmentCreateTime))); + }); loadDialogEntities(); }); @@ -339,11 +438,11 @@ private void updateChart() { if (System.currentTimeMillis() - fragmentCreateTime < 80) { cacheChart.loadingFloat.set(0, true); } - cacheChart.setSegments(totalSize, segments); + cacheChart.setSegments(totalSize, true, segments); } else if (calculating) { - cacheChart.setSegments(-1); + cacheChart.setSegments(-1, true); } else { - cacheChart.setSegments(0); + cacheChart.setSegments(0, true); } } if (clearCacheButton != null && !calculating) { @@ -530,14 +629,14 @@ private String formatPercent(float k) { } private String formatPercent(float k, boolean minimize) { - float p = Math.round(k * 100f); - if (minimize && p < 0.1f) { + if (minimize && k < 0.001f) { return String.format("<%.1f%%", 0.1f); } - if (p % 1 == 0) { - return ((int) p) + "%"; + final float p = Math.round(k * 100f); + if (minimize && p <= 0) { + return String.format("<%d%%", 1); } - return String.format("%.1f%%", p); + return String.format("%d%%", (int) p); } private CharSequence getCheckBoxTitle(CharSequence header, int percent) { @@ -545,7 +644,7 @@ private CharSequence getCheckBoxTitle(CharSequence header, int percent) { } private CharSequence getCheckBoxTitle(CharSequence header, int percent, boolean addArrow) { - String percentString = percent <= 0 ? String.format("<%.1f%%", 0.1f) : String.format("%d%%", percent); + String percentString = percent <= 0 ? String.format("<%.1f%%", 1f) : String.format("%d%%", percent); SpannableString percentStr = new SpannableString(percentString); percentStr.setSpan(new RelativeSizeSpan(.834f), 0, percentStr.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); percentStr.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), 0, percentStr.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); @@ -700,7 +799,7 @@ public void onFragmentDestroy() { canceled = true; } - private long getDirectorySize(File dir, int documentsMusicType) { + private static long getDirectorySize(File dir, int documentsMusicType) { if (dir == null || canceled) { return 0; } @@ -841,7 +940,8 @@ private void cleanupFoldersInternal() { } } final boolean imagesClearedFinal = imagesCleared; - totalSize = cacheSize + cacheTempSize + videoSize + audioSize + photoSize + documentsSize + musicSize + stickersCacheSize; + totalSize = lastTotalSizeCalculated = cacheSize + cacheTempSize + videoSize + audioSize + photoSize + documentsSize + musicSize + stickersCacheSize; + lastTotalSizeCalculatedTime = System.currentTimeMillis(); Arrays.fill(selected, true); File path = Environment.getDataDirectory(); @@ -888,8 +988,10 @@ private void cleanupFoldersInternal() { } getMediaDataController().ringtoneDataStore.checkRingtoneSoundsLoaded(); - cacheRemovedTooltip.setInfoText(LocaleController.formatString("CacheWasCleared", R.string.CacheWasCleared, AndroidUtilities.formatFileSize(finalClearedSize))); - cacheRemovedTooltip.showWithAction(0, UndoView.ACTION_CACHE_WAS_CLEARED, null, null); + AndroidUtilities.runOnUIThread(() -> { + cacheRemovedTooltip.setInfoText(LocaleController.formatString("CacheWasCleared", R.string.CacheWasCleared, AndroidUtilities.formatFileSize(finalClearedSize))); + cacheRemovedTooltip.showWithAction(0, UndoView.ACTION_CACHE_WAS_CLEARED, null, null); + }, 150); MediaDataController.getInstance(currentAccount).chekAllMedia(true); loadDialogEntities(); @@ -1436,7 +1538,7 @@ public void setData(boolean hasCache, float percent, float usedPercent) { LocaleController.getString("StorageCleared", R.string.StorageCleared) ); if (hasCache) { - if (percent < 0.1f) { + if (percent < 0.01f) { subtitle[1].setText(LocaleController.formatString("StorageUsageTelegramLess", R.string.StorageUsageTelegramLess, formatPercent(percent))); } else { subtitle[1].setText(LocaleController.formatString("StorageUsageTelegram", R.string.StorageUsageTelegram, formatPercent(percent))); @@ -1640,7 +1742,7 @@ public ClearCacheButton(Context context) { @Override protected void dispatchDraw(Canvas canvas) { final int margin = AndroidUtilities.dp(8); - int x = (getMeasuredWidth() - margin - valueTextView.getCurrentWidth() + textView.getCurrentWidth()) / 2; + int x = (getMeasuredWidth() - margin - (int) valueTextView.getCurrentWidth() + (int) textView.getCurrentWidth()) / 2; if (LocaleController.isRTL) { super.dispatchDraw(canvas); @@ -2140,14 +2242,11 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } String value = CacheByChatsController.getKeepMediaString(cacheByChatsController.getKeepMedia(keepMediaType)); if (itemInners.get(position).keepMediaType == KEEP_MEDIA_TYPE_USER) { - textCell2.setTextAndValue(LocaleController.getString("PrivateChats", R.string.PrivateChats), value, true, true); - textCell2.setColorfulIcon(getThemedColor(Theme.key_statisticChartLine_lightblue), R.drawable.msg_filled_menu_users); + textCell2.setTextAndValueAndColorfulIcon(LocaleController.getString("PrivateChats", R.string.PrivateChats), value, true, R.drawable.msg_filled_menu_users, getThemedColor(Theme.key_statisticChartLine_lightblue), true); } else if (itemInners.get(position).keepMediaType == KEEP_MEDIA_TYPE_GROUP) { - textCell2.setTextAndValue(LocaleController.getString("GroupChats", R.string.GroupChats), value, true, true); - textCell2.setColorfulIcon(getThemedColor(Theme.key_statisticChartLine_green), R.drawable.msg_filled_menu_groups); + textCell2.setTextAndValueAndColorfulIcon(LocaleController.getString("GroupChats", R.string.GroupChats), value, true, R.drawable.msg_filled_menu_groups, getThemedColor(Theme.key_statisticChartLine_green), true); } else if (itemInners.get(position).keepMediaType == KEEP_MEDIA_TYPE_CHANNEL) { - textCell2.setTextAndValue(LocaleController.getString("CacheChannels", R.string.CacheChannels), value, true, false); - textCell2.setColorfulIcon(getThemedColor(Theme.key_statisticChartLine_golden), R.drawable.msg_filled_menu_channels); + textCell2.setTextAndValueAndColorfulIcon(LocaleController.getString("CacheChannels", R.string.CacheChannels), value, true, R.drawable.msg_filled_menu_channels, getThemedColor(Theme.key_statisticChartLine_golden), true); } textCell2.setSubtitle(subtitle); break; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CachedMediaLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/CachedMediaLayout.java index 77ed5dc2dd4..0038362bb3e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CachedMediaLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CachedMediaLayout.java @@ -100,7 +100,7 @@ public CachedMediaLayout(@NonNull Context context, BaseFragment parentFragment) int CacheTabChats; allPages[PAGE_TYPE_CHATS] = new Page(LocaleController.getString("Chats", R.string.Chats), PAGE_TYPE_CHATS, new DialogsAdapter()); - allPages[PAGE_TYPE_MEDIA] = new Page(LocaleController.getString("Media", R.string.Media), PAGE_TYPE_MEDIA, new MediaAdapter()); + allPages[PAGE_TYPE_MEDIA] = new Page(LocaleController.getString("MediaTab", R.string.MediaTab), PAGE_TYPE_MEDIA, new MediaAdapter()); allPages[PAGE_TYPE_DOCUMENTS] = new Page(LocaleController.getString("Files", R.string.Files), PAGE_TYPE_DOCUMENTS, new DocumentsAdapter()); allPages[PAGE_TYPE_MUSIC] = new Page(LocaleController.getString("Music", R.string.Music), PAGE_TYPE_MUSIC, new MusicAdapter()); // allPages[PAGE_TYPE_VOICE] = new Page(LocaleController.getString("Voice", R.string.Voice), PAGE_TYPE_VOICE, new VoiceAdapter()); @@ -750,7 +750,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi holder.itemView.setTag(file); long date = file.file.lastModified(); - cell.setTextAndValueAndTypeAndThumb(file.messageType == MessageObject.TYPE_ROUND_VIDEO ? LocaleController.getString("AttachRound", R.string.AttachRound) : file.file.getName(), LocaleController.formatDateAudio(date, true), Utilities.getExtension(file.file.getName()), null, 0, divider); + cell.setTextAndValueAndTypeAndThumb(file.messageType == MessageObject.TYPE_ROUND_VIDEO ? LocaleController.getString("AttachRound", R.string.AttachRound) : file.file.getName(), LocaleController.formatDateAudio(date / 1000, true), Utilities.getExtension(file.file.getName()), null, 0, divider); if (!animated) { cell.setPhoto(file.file.getPath()); } @@ -992,7 +992,7 @@ public CacheCell(@NonNull Context context) { super(context); checkBox = new CheckBox2(context, 21); checkBox.setDrawBackgroundAsArc(14); - checkBox.setColor(Theme.key_radioBackground, Theme.key_radioBackground, Theme.key_checkboxCheck); + checkBox.setColor(Theme.key_checkbox, Theme.key_radioBackground, Theme.key_checkboxCheck); addView(checkBox, LayoutHelper.createFrame(24, 24, Gravity.LEFT | Gravity.CENTER_VERTICAL, 18, 0, 0, 0)); View checkBoxClickableView = new View(getContext()); checkBoxClickableView.setOnClickListener(v -> { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CalendarActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CalendarActivity.java index ba5b0a9742b..83197df28f3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CalendarActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CalendarActivity.java @@ -9,6 +9,7 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; @@ -59,6 +60,7 @@ import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.SharedMediaLayout; +import org.telegram.ui.Components.spoilers.SpoilerEffect; import java.time.YearMonth; import java.util.ArrayList; @@ -122,6 +124,9 @@ public class CalendarActivity extends BaseFragment { private int calendarType; + private Path path = new Path(); + private SpoilerEffect mediaSpoilerEffect = new SpoilerEffect(); + public CalendarActivity(Bundle args, int photosVideosTypeFilter, int selectedDate) { super(args); this.photosVideosTypeFilter = photosVideosTypeFilter; @@ -923,6 +928,7 @@ public void setDate(int year, int monthInYear, SparseArray messagesBy PeriodDay periodDay = messagesByDays.get(key); MessageObject messageObject = periodDay.messageObject; if (messageObject != null) { + boolean hasMediaSpoilers = messageObject.hasMediaSpoilers(); if (messageObject.isVideo()) { TLRPC.Document document = messageObject.getDocument(); TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 50); @@ -932,9 +938,9 @@ public void setDate(int year, int monthInYear, SparseArray messagesBy } if (thumb != null) { if (messageObject.strippedThumb != null) { - receiver.setImage(ImageLocation.getForDocument(qualityThumb, document), "44_44", messageObject.strippedThumb, null, messageObject, 0); + receiver.setImage(ImageLocation.getForDocument(qualityThumb, document), hasMediaSpoilers ? "5_5_b" : "44_44", messageObject.strippedThumb, null, messageObject, 0); } else { - receiver.setImage(ImageLocation.getForDocument(qualityThumb, document), "44_44", ImageLocation.getForDocument(thumb, document), "b", (String) null, messageObject, 0); + receiver.setImage(ImageLocation.getForDocument(qualityThumb, document), hasMediaSpoilers ? "5_5_b" : "44_44", ImageLocation.getForDocument(thumb, document), "b", (String) null, messageObject, 0); } } } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && messageObject.messageOwner.media.photo != null && !messageObject.photoThumbs.isEmpty()) { @@ -945,9 +951,9 @@ public void setDate(int year, int monthInYear, SparseArray messagesBy currentPhotoObjectThumb = null; } if (messageObject.strippedThumb != null) { - receiver.setImage(ImageLocation.getForObject(currentPhotoObject, messageObject.photoThumbsObject), "44_44", null, null, messageObject.strippedThumb, currentPhotoObject != null ? currentPhotoObject.size : 0, null, messageObject, messageObject.shouldEncryptPhotoOrVideo() ? 2 : 1); + receiver.setImage(ImageLocation.getForObject(currentPhotoObject, messageObject.photoThumbsObject), hasMediaSpoilers ? "5_5_b" : "44_44", null, null, messageObject.strippedThumb, currentPhotoObject != null ? currentPhotoObject.size : 0, null, messageObject, messageObject.shouldEncryptPhotoOrVideo() ? 2 : 1); } else { - receiver.setImage(ImageLocation.getForObject(currentPhotoObject, messageObject.photoThumbsObject), "44_44", ImageLocation.getForObject(currentPhotoObjectThumb, messageObject.photoThumbsObject), "b", currentPhotoObject != null ? currentPhotoObject.size : 0, null, messageObject, messageObject.shouldEncryptPhotoOrVideo() ? 2 : 1); + receiver.setImage(ImageLocation.getForObject(currentPhotoObject, messageObject.photoThumbsObject), hasMediaSpoilers ? "5_5_b" : "44_44", ImageLocation.getForObject(currentPhotoObjectThumb, messageObject.photoThumbsObject), "b", currentPhotoObject != null ? currentPhotoObject.size : 0, null, messageObject, messageObject.shouldEncryptPhotoOrVideo() ? 2 : 1); } } else { if (messageObject.strippedThumb != null) { @@ -1060,6 +1066,24 @@ protected void onDraw(Canvas canvas) { imagesByDays.get(i).setImageCoords(cx - (AndroidUtilities.dp(44) - pad) / 2f, cy - (AndroidUtilities.dp(44) - pad) / 2f, AndroidUtilities.dp(44) - pad, AndroidUtilities.dp(44) - pad); imagesByDays.get(i).draw(canvas); + if (messagesByDays.get(i) != null && messagesByDays.get(i).messageObject != null && messagesByDays.get(i).messageObject.hasMediaSpoilers()) { + float rad = (AndroidUtilities.dp(44) - pad) / 2f; + path.rewind(); + path.addCircle(cx, cy, rad, Path.Direction.CW); + + canvas.save(); + canvas.clipPath(path); + + int sColor = Color.WHITE; + mediaSpoilerEffect.setColor(ColorUtils.setAlphaComponent(sColor, (int) (Color.alpha(sColor) * 0.325f * day.enterAlpha))); + mediaSpoilerEffect.setBounds((int) (cx - rad), (int) (cy - rad), (int) (cx + rad), (int) (cy + rad)); + mediaSpoilerEffect.draw(canvas); + + invalidate(); + + canvas.restore(); + } + blackoutPaint.setColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (day.enterAlpha * 80))); canvas.drawCircle(cx, cy, (AndroidUtilities.dp(44) - pad) / 2f, blackoutPaint); day.wasDrawn = true; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java index 131cecae5c5..4ab62d6a187 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java @@ -502,9 +502,11 @@ public void init() { @Override public void end(boolean replacing) { - if (thisLoading != null) { - links.removeLoading(thisLoading, true); - } + AndroidUtilities.runOnUIThread(() -> { + if (thisLoading != null) { + links.removeLoading(thisLoading, true); + } + }, replacing ? 0 : 350); } } : null; if (pressedLink instanceof URLSpanNoUnderline) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/BotHelpCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/BotHelpCell.java index 7e540d98cf7..361e96baf48 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/BotHelpCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/BotHelpCell.java @@ -12,6 +12,7 @@ import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.os.Build; import android.text.Layout; import android.text.Spannable; import android.text.SpannableStringBuilder; @@ -24,6 +25,8 @@ import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; +import androidx.annotation.NonNull; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLoader; @@ -40,6 +43,7 @@ import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.LinkPath; +import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.Components.URLSpanNoUnderline; @@ -58,8 +62,8 @@ public class BotHelpCell extends View { private int textY; public boolean wasDraw; - private ClickableSpan pressedLink; - private LinkPath urlPath = new LinkPath(); + private LinkSpanDrawable pressedLink; + private LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(this); private BotHelpCellDelegate delegate; private Theme.ResourcesProvider resourcesProvider; @@ -84,6 +88,9 @@ public BotHelpCell(Context context, Theme.ResourcesProvider resourcesProvider) { imageReceiver.setInvalidateAll(true); imageReceiver.setCrossfadeWithOldImage(true); imageReceiver.setCrossfadeDuration(300); + + selectorDrawable = Theme.createRadSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), selectorDrawableRadius = SharedConfig.bubbleRadius, SharedConfig.bubbleRadius); + selectorDrawable.setCallback(this); } public void setDelegate(BotHelpCellDelegate botHelpCellDelegate) { @@ -94,6 +101,7 @@ private void resetPressedLink() { if (pressedLink != null) { pressedLink = null; } + links.clear(); invalidate(); } @@ -195,6 +203,13 @@ public void setText(boolean bot, String text, TLObject imageOrAnimation, TLRPC.B } } + public CharSequence getText() { + if (textLayout == null) { + return null; + } + return textLayout.getText(); + } + @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); @@ -217,15 +232,18 @@ public boolean onTouchEvent(MotionEvent event) { ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); if (link.length != 0) { resetPressedLink(); - pressedLink = link[0]; + pressedLink = new LinkSpanDrawable(link[0], resourcesProvider, x2, y2); result = true; try { - int start = buffer.getSpanStart(pressedLink); - urlPath.setCurrentLayout(textLayout, start, 0); - textLayout.getSelectionPath(start, buffer.getSpanEnd(pressedLink), urlPath); + int start = buffer.getSpanStart(link[0]); + LinkPath path = pressedLink.obtainNewPath(); + path.setCurrentLayout(textLayout, start, 0); + textLayout.getSelectionPath(start, buffer.getSpanEnd(link[0]), path); } catch (Exception e) { FileLog.e(e); } + links.addLink(pressedLink); + invalidate(); } else { resetPressedLink(); } @@ -238,21 +256,20 @@ public boolean onTouchEvent(MotionEvent event) { } } else if (pressedLink != null) { try { - if (pressedLink instanceof URLSpanNoUnderline) { - String url = ((URLSpanNoUnderline) pressedLink).getURL(); + ClickableSpan span = pressedLink.getSpan(); + if (span instanceof URLSpanNoUnderline) { + String url = ((URLSpanNoUnderline) span).getURL(); if (url.startsWith("@") || url.startsWith("#") || url.startsWith("/")) { if (delegate != null) { delegate.didPressUrl(url); } } - } else { - if (pressedLink instanceof URLSpan) { - if (delegate != null) { - delegate.didPressUrl(((URLSpan) pressedLink).getURL()); - } - } else { - pressedLink.onClick(this); + } else if (span instanceof URLSpan) { + if (delegate != null) { + delegate.didPressUrl(((URLSpan) span).getURL()); } + } else if (span != null) { + span.onClick(this); } } catch (Exception e) { FileLog.e(e); @@ -264,6 +281,23 @@ public boolean onTouchEvent(MotionEvent event) { resetPressedLink(); } } + if (selectorDrawable != null) { + if (!result && y > 0 && event.getAction() == MotionEvent.ACTION_DOWN && isClickable()) { + selectorDrawable.setState(new int[]{android.R.attr.state_pressed, android.R.attr.state_enabled}); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + selectorDrawable.setHotspot(event.getX(), event.getY()); + } + invalidate(); + result = true; + } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + selectorDrawable.setState(new int[]{}); + invalidate(); + if (!result && event.getAction() == MotionEvent.ACTION_UP) { + performClick(); + } + result = true; + } + } return result || super.onTouchEvent(event); } @@ -272,6 +306,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), height + AndroidUtilities.dp(8)); } + private Drawable selectorDrawable; + private int selectorDrawableRadius; + @Override protected void onDraw(Canvas canvas) { int x = (getWidth() - width) / 2; @@ -294,6 +331,15 @@ protected void onDraw(Canvas canvas) { drawable.setBounds(x, 0, width + x, height); drawable.draw(canvas); + if (selectorDrawable != null) { + if (selectorDrawableRadius != SharedConfig.bubbleRadius) { + selectorDrawableRadius = SharedConfig.bubbleRadius; + Theme.setMaskDrawableRad(selectorDrawable, selectorDrawableRadius, selectorDrawableRadius); + } + selectorDrawable.setBounds(x + AndroidUtilities.dp(2), AndroidUtilities.dp(2), width + x - AndroidUtilities.dp(2), height - AndroidUtilities.dp(2)); + selectorDrawable.draw(canvas); + } + imageReceiver.setImageCoords(x + imagePadding, imagePadding, width - imagePadding * 2, photoHeight - imagePadding); imageReceiver.draw(canvas); @@ -301,8 +347,8 @@ protected void onDraw(Canvas canvas) { Theme.chat_msgTextPaint.linkColor = getThemedColor(Theme.key_chat_messageLinkIn); canvas.save(); canvas.translate(textX = AndroidUtilities.dp(isPhotoVisible ? 14 : 11) + x, textY = AndroidUtilities.dp(11) + y); - if (pressedLink != null) { - canvas.drawPath(urlPath, Theme.chat_urlPaint); + if (links.draw(canvas)) { + invalidate(); } if (textLayout != null) { textLayout.draw(canvas); @@ -349,4 +395,9 @@ private Drawable getThemedDrawable(String drawableKey) { Drawable drawable = resourcesProvider != null ? resourcesProvider.getDrawable(drawableKey) : null; return drawable != null ? drawable : Theme.getThemeDrawable(drawableKey); } + + @Override + protected boolean verifyDrawable(@NonNull Drawable who) { + return who == selectorDrawable || super.verifyDrawable(who); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java index abe0d94b8e8..cf0ddb654aa 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java @@ -14,6 +14,7 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; +import android.graphics.Rect; import android.graphics.RectF; import android.os.Build; import android.text.Layout; @@ -125,6 +126,11 @@ public void setSpoilersSuppressed(boolean s) { } private boolean canDrawInParent; + private View invalidateWithParent; + + public void setInvalidateWithParent(View viewToInvalidate) { + invalidateWithParent = viewToInvalidate; + } public interface ChatActionCellDelegate { default void didClickImage(ChatActionCell cell) { @@ -397,37 +403,37 @@ public void setMessageObject(MessageObject messageObject, boolean force) { hasReplyMessage = messageObject.replyMessageObject != null; DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); previousWidth = 0; + imageReceiver.setAutoRepeatCount(0); if (messageObject.type == MessageObject.TYPE_SUGGEST_PHOTO) { imageReceiver.setRoundRadius((int) (stickerSize / 2f)); imageReceiver.setAllowStartLottieAnimation(true); imageReceiver.setDelegate(null); TLRPC.TL_messageActionSuggestProfilePhoto action = (TLRPC.TL_messageActionSuggestProfilePhoto) messageObject.messageOwner.action; + TLRPC.VideoSize videoSize = FileLoader.getClosestVideoSizeWithSize(action.photo.video_sizes, 1000); ImageLocation videoLocation; if (action.photo.video_sizes != null && !action.photo.video_sizes.isEmpty()) { - videoLocation = ImageLocation.getForPhoto(action.photo.video_sizes.get(0), action.photo); + videoLocation = ImageLocation.getForPhoto(videoSize, action.photo); } else { videoLocation = null; } TLRPC.Photo photo = messageObject.messageOwner.action.photo; - TLRPC.VideoSize videoSize = null; TLRPC.PhotoSize strippedPhotoSize = null; - for (int a = 0, N = messageObject.photoThumbs.size(); a < N; a++) { - TLRPC.PhotoSize photoSize = messageObject.photoThumbs.get(a); - if (photoSize instanceof TLRPC.TL_photoStrippedSize) { - strippedPhotoSize = photoSize; - break; + if (messageObject.strippedThumb == null) { + for (int a = 0, N = messageObject.photoThumbs.size(); a < N; a++) { + TLRPC.PhotoSize photoSize = messageObject.photoThumbs.get(a); + if (photoSize instanceof TLRPC.TL_photoStrippedSize) { + strippedPhotoSize = photoSize; + break; + } } } TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 1000); if (photoSize != null) { - if (!photo.video_sizes.isEmpty()) { - videoSize = photo.video_sizes.get(0); - } if (videoSize != null) { - imageReceiver.setImage(videoLocation, ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForPhoto(photoSize, photo), "150_150", ImageLocation.getForObject(strippedPhotoSize, messageObject.photoThumbsObject), "50_50_b", null, 0, null, messageObject, 0); + imageReceiver.setImage(videoLocation, ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForPhoto(photoSize, photo), "150_150", ImageLocation.getForObject(strippedPhotoSize, messageObject.photoThumbsObject), "50_50_b", messageObject.strippedThumb, 0, null, messageObject, 0); } else { - imageReceiver.setImage(ImageLocation.getForPhoto(photoSize, photo), "150_150", ImageLocation.getForObject(strippedPhotoSize, messageObject.photoThumbsObject), "50_50_b", null, 0, null, messageObject, 0); + imageReceiver.setImage(ImageLocation.getForPhoto(photoSize, photo), "150_150", ImageLocation.getForObject(strippedPhotoSize, messageObject.photoThumbsObject), "50_50_b", messageObject.strippedThumb, 0, null, messageObject, 0); } } @@ -527,17 +533,20 @@ public void setMessageObject(MessageObject messageObject, boolean force) { imageReceiver.setAllowStartLottieAnimation(true); imageReceiver.setDelegate(null); imageReceiver.setRoundRadius(AndroidUtilities.roundMessageSize / 2); + imageReceiver.setAutoRepeatCount(1); long id = messageObject.getDialogId(); avatarDrawable.setInfo(id, null, null); if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) { imageReceiver.setImage(null, null, avatarDrawable, null, messageObject, 0); } else { TLRPC.PhotoSize strippedPhotoSize = null; - for (int a = 0, N = messageObject.photoThumbs.size(); a < N; a++) { - TLRPC.PhotoSize photoSize = messageObject.photoThumbs.get(a); - if (photoSize instanceof TLRPC.TL_photoStrippedSize) { - strippedPhotoSize = photoSize; - break; + if (messageObject.strippedThumb == null) { + for (int a = 0, N = messageObject.photoThumbs.size(); a < N; a++) { + TLRPC.PhotoSize photoSize = messageObject.photoThumbs.get(a); + if (photoSize instanceof TLRPC.TL_photoStrippedSize) { + strippedPhotoSize = photoSize; + break; + } } } TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 640); @@ -545,7 +554,7 @@ public void setMessageObject(MessageObject messageObject, boolean force) { TLRPC.Photo photo = messageObject.messageOwner.action.photo; TLRPC.VideoSize videoSize = null; if (!photo.video_sizes.isEmpty() && SharedConfig.autoplayGifs) { - videoSize = photo.video_sizes.get(0); + videoSize = FileLoader.getClosestVideoSizeWithSize(photo.video_sizes, 1000); if (!messageObject.mediaExists && !DownloadController.getInstance(currentAccount).canDownloadMedia(DownloadController.AUTODOWNLOAD_TYPE_VIDEO, videoSize.size)) { currentVideoLocation = ImageLocation.getForPhoto(videoSize, photo); String fileName = FileLoader.getAttachFileName(videoSize); @@ -554,9 +563,9 @@ public void setMessageObject(MessageObject messageObject, boolean force) { } } if (videoSize != null) { - imageReceiver.setImage(ImageLocation.getForPhoto(videoSize, photo), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(strippedPhotoSize, messageObject.photoThumbsObject), "50_50_b", avatarDrawable, 0, null, messageObject, 1); + imageReceiver.setImage(ImageLocation.getForPhoto(videoSize, photo), ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForObject(strippedPhotoSize, messageObject.photoThumbsObject), "50_50_b", messageObject.strippedThumb, 0, null, messageObject, 1); } else { - imageReceiver.setImage(ImageLocation.getForObject(photoSize, messageObject.photoThumbsObject), "150_150", ImageLocation.getForObject(strippedPhotoSize, messageObject.photoThumbsObject), "50_50_b", avatarDrawable, 0, null, messageObject, 1); + imageReceiver.setImage(ImageLocation.getForObject(photoSize, messageObject.photoThumbsObject), "150_150", ImageLocation.getForObject(strippedPhotoSize, messageObject.photoThumbsObject), "50_50_b", messageObject.strippedThumb, 0, null, messageObject, 1); } } else { imageReceiver.setImageBitmap(avatarDrawable); @@ -844,6 +853,7 @@ private void createLayout(CharSequence text, int width) { } else { paint = (TextPaint) getThemedPaint(Theme.key_paint_chatActionText); } + paint.linkColor = paint.getColor(); textLayout = new StaticLayout(text, paint, maxWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); spoilersPool.addAll(spoilers); @@ -1511,4 +1521,28 @@ public void drawOutboundsContent(Canvas canvas) { private boolean isButtonLayout(MessageObject messageObject) { return messageObject != null && (messageObject.type == MessageObject.TYPE_GIFT_PREMIUM || messageObject.type == MessageObject.TYPE_SUGGEST_PHOTO); } + + @Override + public void invalidate() { + super.invalidate(); + if (invalidateWithParent != null) { + invalidateWithParent.invalidate(); + } + } + + @Override + public void invalidate(Rect dirty) { + super.invalidate(dirty); + if (invalidateWithParent != null) { + invalidateWithParent.invalidate(); + } + } + + @Override + public void invalidate(int l, int t, int r, int b) { + super.invalidate(l, t, r, b); + if (invalidateWithParent != null) { + invalidateWithParent.invalidate(); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java index 8f745cc9224..882cd01be71 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -53,6 +53,7 @@ import android.text.style.CharacterStyle; import android.text.style.ClickableSpan; import android.text.style.URLSpan; +import android.util.Log; import android.util.Property; import android.util.SparseArray; import android.util.StateSet; @@ -155,6 +156,7 @@ import org.telegram.ui.Components.URLSpanBrowser; import org.telegram.ui.Components.URLSpanMono; import org.telegram.ui.Components.URLSpanNoUnderline; +import org.telegram.ui.Components.VectorAvatarThumbDrawable; import org.telegram.ui.Components.VideoForwardDrawable; import org.telegram.ui.Components.spoilers.SpoilerEffect; import org.telegram.ui.PhotoViewer; @@ -242,7 +244,7 @@ private void setAvatar(MessageObject messageObject) { currentPhoto = null; } avatarDrawable.setInfo(currentUser); - avatarImage.setForUserOrChat(currentUser, avatarDrawable, null, true); + avatarImage.setForUserOrChat(currentUser, avatarDrawable, null, true, VectorAvatarThumbDrawable.TYPE_SMALL); } else if (currentChat != null) { if (currentChat.photo != null) { currentPhoto = currentChat.photo.photo_small; @@ -1052,6 +1054,12 @@ class LoadingDrawableLocation { private float replyTouchX, replyTouchY; private TLRPC.PhotoSize currentReplyPhoto; + private AnimatedFloat translationLoadingFloat; + private LinkPath translationLoadingPath; + private LoadingDrawable translationLoadingDrawable; + private ArrayList translationLoadingDrawableText; + private StaticLayout translationLoadingDrawableLayout; + private boolean drawTopic; private MessageTopicButton topicButton; @@ -1156,6 +1164,7 @@ class LoadingDrawableLocation { private int lastViewsCount; private int lastRepliesCount; private float selectedBackgroundProgress; + private boolean lastTranslated; private float viewTop; private int backgroundHeight; @@ -3043,7 +3052,7 @@ public boolean onTouchEvent(MotionEvent event) { forwardBotPressed = false; playSoundEffect(SoundEffectConstants.CLICK); if (delegate != null) { - if (currentViaBotUser.bot_inline_placeholder == null) { + if (currentViaBotUser != null && currentViaBotUser.bot_inline_placeholder == null) { delegate.didPressViaBotNotInline(this, currentViaBotUser != null ? currentViaBotUser.id : 0); } else { delegate.didPressViaBot(this, currentViaBotUser != null ? currentViaBotUser.username : currentMessageObject.messageOwner.via_bot_name); @@ -3432,6 +3441,9 @@ public void setVisiblePart(int position, int height, int parent, float parentOff this.blurredViewTopOffset = blurredViewTopOffset; this.blurredViewBottomOffset = blurredViewBottomOffset; + if (!botButtons.isEmpty() && viewTop != visibleTop) { + invalidate(); + } viewTop = visibleTop; if (parent != parentHeight || parentOffset != this.parentViewTopOffset) { @@ -4081,7 +4093,8 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe currentMessageObject == messageObject && (isUserDataChanged() || photoNotSet) || lastPostAuthor != messageObject.messageOwner.post_author || wasPinned != isPinned || - newReply != lastReplyMessage; + newReply != lastReplyMessage || + messageObject.translated != lastTranslated; boolean groupChanged = groupedMessages != currentMessagesGroup; boolean pollChanged = false; @@ -4190,6 +4203,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe photoImage.setCrossfadeDuration(ImageReceiver.DEFAULT_CROSSFADE_DURATION); photoImage.setCrossfadeByScale(0); photoImage.setGradientBitmap(null); + lastTranslated = messageObject.translated; lastSendState = messageObject.messageOwner.send_state; lastDeleteDate = messageObject.messageOwner.destroyTime; lastViewsCount = messageObject.messageOwner.views; @@ -4534,11 +4548,12 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe hasGamePreview = MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaGame && MessageObject.getMedia(messageObject.messageOwner).game instanceof TLRPC.TL_game; hasInvoicePreview = MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaInvoice; hasLinkPreview = !messageObject.isRestrictedMessage && MessageObject.getMedia(messageObject.messageOwner) instanceof TLRPC.TL_messageMediaWebPage && MessageObject.getMedia(messageObject.messageOwner).webpage instanceof TLRPC.TL_webPage; + TLRPC.WebPage webpage = hasLinkPreview ? MessageObject.getMedia(messageObject.messageOwner).webpage : null; drawInstantView = hasLinkPreview && MessageObject.getMedia(messageObject.messageOwner).webpage.cached_page != null; String siteName = hasLinkPreview ? MessageObject.getMedia(messageObject.messageOwner).webpage.site_name : null; hasEmbed = hasLinkPreview && !TextUtils.isEmpty(MessageObject.getMedia(messageObject.messageOwner).webpage.embed_url) && !messageObject.isGif() && !"instangram".equalsIgnoreCase(siteName); boolean slideshow = false; - String webpageType = hasLinkPreview ? MessageObject.getMedia(messageObject.messageOwner).webpage.type : null; + String webpageType = webpage != null ? webpage.type : null; TLRPC.Document androidThemeDocument = null; TLRPC.ThemeSettings androidThemeSettings = null; if (!drawInstantView) { @@ -4557,7 +4572,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } else if ("telegram_megagroup".equals(webpageType)) { drawInstantView = true; drawInstantViewType = 2; - } else if ("telegram_message".equals(webpageType)) { + } else if ("telegram_message".equals(webpageType) || "photo".equals(webpageType) && webpage != null && webpage.url != null && Browser.isInternalUri(Uri.parse(webpage.url), null)) { drawInstantView = true; drawInstantViewType = 3; } else if ("telegram_theme".equals(webpageType)) { @@ -4868,6 +4883,12 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } boolean titleIsRTL = false; + if (!titleIsRTL && author != null) { + titleIsRTL = AndroidUtilities.isRTL(author); + } + if (!titleIsRTL && messageObject.linkDescription != null) { + titleIsRTL = AndroidUtilities.isRTL(messageObject.linkDescription); + } if (title != null) { try { titleX = Integer.MAX_VALUE; @@ -4915,9 +4936,9 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } catch (Exception e) { FileLog.e(e); } - if (titleIsRTL && isSmallImage) { - linkPreviewMaxWidth -= AndroidUtilities.dp(48); - } + } + if (titleIsRTL && isSmallImage) { + linkPreviewMaxWidth -= AndroidUtilities.dp(48); } boolean authorIsRTL = false; @@ -5649,7 +5670,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe } } } - if (user != null) { + if (user != null || !TextUtils.isEmpty(messageObject.vCardData)) { drawInstantView = true; drawInstantViewType = 5; } @@ -7483,7 +7504,20 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe int buttonWidth = (widthForButtons - AndroidUtilities.dp(5) * (buttonsCount - 1) - AndroidUtilities.dp(2)) / buttonsCount; for (int b = 0; b < row.buttons.size(); b++) { BotButton botButton = new BotButton(); - botButton.button = row.buttons.get(b); + TLRPC.TL_keyboardButtonRequestPeer button = new TLRPC.TL_keyboardButtonRequestPeer(); + button.button_id = 0; + button.text = "Request peer"; + button.peer_type = new TLRPC.TL_requestPeerTypeChat(); + ((TLRPC.TL_requestPeerTypeChat) button.peer_type).forum = true; +// ((TLRPC.TL_requestPeerTypeChat) button.peer_type).user_admin_rights = new TLRPC.TL_chatAdminRights(); +// ((TLRPC.TL_requestPeerTypeChat) button.peer_type).user_admin_rights.change_info = true; +// ((TLRPC.TL_requestPeerTypeChat) button.peer_type).user_admin_rights.delete_messages = true; +// ((TLRPC.TL_requestPeerTypeChat) button.peer_type).user_admin_rights.pin_messages = true; +// ((TLRPC.TL_requestPeerTypeChat) button.peer_type).user_admin_rights.anonymous = true; +// ((TLRPC.TL_requestPeerTypeChat) button.peer_type).user_admin_rights.post_messages = true; +// ((TLRPC.TL_requestPeerTypeChat) button.peer_type).premium = false; +// botButton.button = button; + botButton.button = row.buttons.get(b); String key = Utilities.bytesToHex(botButton.button.data); String position = a + "" + b; BotButton oldButton; @@ -7671,6 +7705,17 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe statusDrawableAnimator.removeAllListeners(); statusDrawableAnimator.cancel(); } + if (translationLoadingFloat != null) { + translationLoadingFloat.set(0, true); + } + if (translationLoadingPath != null) { + translationLoadingPath.reset(); + translationLoadingPath = null; + } + if (translationLoadingDrawable != null) { + translationLoadingDrawable.reset(); + translationLoadingDrawable = null; + } transitionParams.lastStatusDrawableParams = -1; statusDrawableAnimationInProgress = false; @@ -8149,7 +8194,20 @@ private void updateWaveform() { if (seekBarWaveform != null) { seekBarWaveform.setWaveform(waveform); } - useTranscribeButton = currentMessageObject != null && (!currentMessageObject.isOutOwner() || currentMessageObject.isSent()) && (UserConfig.getInstance(currentAccount).isPremium() || !MessagesController.getInstance(currentAccount).didPressTranscribeButtonEnough() && (currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.voiceTranscriptionForce || currentMessageObject.getDuration() >= 60) && !MessagesController.getInstance(currentAccount).premiumLocked) && (currentMessageObject.isVoice() && useSeekBarWaveform || currentMessageObject.isRoundVideo()) && currentMessageObject.messageOwner != null && !(MessageObject.getMedia(currentMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaWebPage); + useTranscribeButton = ( + currentMessageObject != null && + (!currentMessageObject.isOutOwner() || currentMessageObject.isSent()) && + ( + UserConfig.getInstance(currentAccount).isPremium() || + !MessagesController.getInstance(currentAccount).didPressTranscribeButtonEnough() && ( + currentMessageObject.messageOwner != null && currentMessageObject.messageOwner.voiceTranscriptionForce || + currentMessageObject.getDuration() >= 60 + ) && !MessagesController.getInstance(currentAccount).premiumLocked + ) && ( + currentMessageObject.isVoice() && useSeekBarWaveform || + currentMessageObject.isRoundVideo() + ) && currentMessageObject.messageOwner != null && !(MessageObject.getMedia(currentMessageObject.messageOwner) instanceof TLRPC.TL_messageMediaWebPage) + ); updateSeekBarWaveformWidth(null); } @@ -9346,11 +9404,11 @@ private void drawContent(Canvas canvas) { ); } } - drawMessageText(canvas, transitionParams.animateOutTextBlocks, false, (1.0f - transitionParams.animateChangeProgress), false); - drawMessageText(canvas, currentMessageObject.textLayoutBlocks, true, transitionParams.animateChangeProgress, false); + drawMessageText(canvas, transitionParams.animateOutTextBlocks, transitionParams.animateOutTextXOffset, false, (1.0f - transitionParams.animateChangeProgress), false); + drawMessageText(canvas, currentMessageObject.textLayoutBlocks, currentMessageObject.textXOffset, true, transitionParams.animateChangeProgress, false); canvas.restore(); } else { - drawMessageText(canvas, currentMessageObject.textLayoutBlocks, true, 1.0f, false); + drawMessageText(canvas, currentMessageObject.textLayoutBlocks, currentMessageObject.textXOffset, true, 1.0f, false); } } @@ -9369,7 +9427,10 @@ private void drawContent(Canvas canvas) { canvas.drawCircle(photoImage.getCenterX(), photoImage.getCenterY(), photoImage.getImageWidth() / 2f, drillHolePaint); } if (isRoundVideo && ( - MediaController.getInstance().isPlayingMessage(currentMessageObject) && MediaController.getInstance().isVideoDrawingReady() && canvas.isHardwareAccelerated() && (currentMessageObject == null || !currentMessageObject.isVoiceTranscriptionOpen() || pipFloat >= 1) + MediaController.getInstance().isPlayingMessage(currentMessageObject) && + MediaController.getInstance().isVideoDrawingReady() && + canvas.isHardwareAccelerated() && + (currentMessageObject == null || !currentMessageObject.isVoiceTranscriptionOpen() || pipFloat >= 1) )) { imageDrawn = true; drawTime = true; @@ -9807,8 +9868,8 @@ protected void onOpen() { } else { linkX = backgroundDrawableLeft + AndroidUtilities.dp(currentMessageObject.isOutOwner() ? 11 : 17); } - int startY = totalHeight - AndroidUtilities.dp(drawPinnedTop ? 9 : 10) - linkPreviewHeight - AndroidUtilities.dp(8); - int linkPreviewY = startY; + float startY = totalHeight - AndroidUtilities.dp(drawPinnedTop ? 9 : 10) - linkPreviewHeight - AndroidUtilities.dp(8); + float linkPreviewY = startY; Theme.chat_replyLinePaint.setColor(getThemedColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outPreviewLine : Theme.key_chat_inPreviewLine)); AndroidUtilities.rectTmp.set(linkX, linkPreviewY - AndroidUtilities.dp(3), linkX + AndroidUtilities.dp(3), linkPreviewY + linkPreviewHeight); @@ -9850,7 +9911,7 @@ protected void onOpen() { if (linkPreviewY != startY) { linkPreviewY += AndroidUtilities.dp(2); } - descriptionY = linkPreviewY - AndroidUtilities.dp(3); + descriptionY = (int) linkPreviewY - AndroidUtilities.dp(3); canvas.save(); canvas.translate(linkX + AndroidUtilities.dp(10) + descriptionX, descriptionY); descriptionLayout.draw(canvas); @@ -10154,6 +10215,7 @@ public void drawLinkPreview(Canvas canvas, float alpha) { startY = textY + currentMessageObject.textHeight + AndroidUtilities.dp(8); linkX = unmovedTextX + AndroidUtilities.dp(1); } + startY += (int) transitionParams.deltaBottom; int linkPreviewY = startY; int smallImageStartY = 0; @@ -10502,10 +10564,6 @@ public void drawLinkPreview(Canvas canvas, float alpha) { } instantButtonRect.set(linkX, instantY, linkX + instantWidth, instantY + AndroidUtilities.dp(36)); - if (instantButtonLoading != null) { - instantButtonLoading.setBounds(instantButtonRect); - instantButtonLoading.setRadiiDp(6); - } if (instantButtonPressed && instantButtonPressProgress != 1f) { instantButtonPressProgress += (float) Math.min(40, 1000f / AndroidUtilities.screenRefreshRate) / 100f; instantButtonPressProgress = Utilities.clamp(instantButtonPressProgress, 1f, 0); @@ -10522,6 +10580,8 @@ public void drawLinkPreview(Canvas canvas, float alpha) { selectorDrawable[0].draw(canvas); } if (instantButtonLoading != null && !instantButtonLoading.isDisappeared()) { + instantButtonLoading.setBounds(instantButtonRect); + instantButtonLoading.setRadiiDp(6); instantButtonLoading.draw(canvas); invalidate(); } @@ -10546,7 +10606,7 @@ private boolean shouldDrawMenuDrawable() { return currentMessagesGroup == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0; } - private void drawBotButtons(Canvas canvas, ArrayList botButtons, float alpha) { + private void drawBotButtons(Canvas canvas, ArrayList botButtons, int alpha) { int addX; if (currentMessageObject.isOutOwner()) { addX = getMeasuredWidth() - widthForButtons - AndroidUtilities.dp(10); @@ -10563,8 +10623,8 @@ private void drawBotButtons(Canvas canvas, ArrayList botButtons, floa } } rect.set(0, top, getMeasuredWidth(), top + height); - if (alpha != 1f) { - canvas.saveLayerAlpha(rect, (int) (255 * alpha), Canvas.ALL_SAVE_FLAG); + if (alpha != 0xFF) { + canvas.saveLayerAlpha(rect, alpha, Canvas.ALL_SAVE_FLAG); } else { canvas.save(); } @@ -10612,14 +10672,14 @@ private void drawBotButtons(Canvas canvas, ArrayList botButtons, floa Theme.multAlpha(Theme.getColor(Theme.key_chat_serviceBackgroundSelector, resourcesProvider), 3f), Theme.multAlpha(Theme.getColor(Theme.key_chat_serviceBackgroundSelector, resourcesProvider), 10f) ); - button.loadingDrawable.setAlpha((int) (0xFF * alpha)); + button.loadingDrawable.setAlpha(0xFF); button.loadingDrawable.draw(canvas); invalidateOutbounds(); } if (button.selectorDrawable != null) { button.selectorDrawable.setBounds(button.x + addX, (int) y, button.x + addX + button.width, (int) y + button.height); - button.selectorDrawable.setAlpha((int) (0xFF * alpha)); + button.selectorDrawable.setAlpha(0xFF); button.selectorDrawable.draw(canvas); } @@ -10642,7 +10702,7 @@ private void drawBotButtons(Canvas canvas, ArrayList botButtons, floa int x = button.x + button.width - AndroidUtilities.dp(3) - drawable.getIntrinsicWidth() + addX; setDrawableBounds(drawable, x, y + AndroidUtilities.dp(3)); drawable.draw(canvas); - } else if (button.button instanceof TLRPC.TL_keyboardButtonSwitchInline) { + } else if (button.button instanceof TLRPC.TL_keyboardButtonSwitchInline || button.button instanceof TLRPC.TL_keyboardButtonRequestPeer) { Drawable drawable = getThemedDrawable(Theme.key_drawable_botInline); int x = button.x + button.width - AndroidUtilities.dp(3) - drawable.getIntrinsicWidth() + addX; setDrawableBounds(drawable, x, y + AndroidUtilities.dp(3)); @@ -10662,8 +10722,12 @@ private boolean allowDrawPhotoImage() { return !currentMessageObject.hasMediaSpoilers() || currentMessageObject.isMediaSpoilersRevealed || mediaSpoilerRevealProgress != 0f || blurredPhotoImage.getBitmap() == null; } - @SuppressLint("Range") public void drawMessageText(Canvas canvas, ArrayList textLayoutBlocks, boolean origin, float alpha, boolean drawOnlyText) { + drawMessageText(canvas, textLayoutBlocks, currentMessageObject == null ? 0 : currentMessageObject.textXOffset, origin, alpha, drawOnlyText); + } + + @SuppressLint("Range") + public void drawMessageText(Canvas canvas, ArrayList textLayoutBlocks, float rtlOffset, boolean origin, float alpha, boolean drawOnlyText) { if (textLayoutBlocks == null || textLayoutBlocks.isEmpty() || alpha == 0) { return; } @@ -10685,6 +10749,62 @@ public void drawMessageText(Canvas canvas, ArrayList 0) { + if (translationLoadingDrawable == null) { + translationLoadingDrawable = new LoadingDrawable(); + translationLoadingDrawable.setAppearByGradient(true); + if (translationLoadingPath == null) { + translationLoadingPath = new LinkPath(true); + } + translationLoadingDrawable.usePath(translationLoadingPath); + translationLoadingDrawable.setRadiiDp(5); + + translationLoadingDrawable.reset(); + } + + if (translationLoadingDrawableText != textLayoutBlocks) { + translationLoadingDrawableText = textLayoutBlocks; + translationLoadingPath.reset(); + for (int i = 0; i < textLayoutBlocks.size(); ++i) { + MessageObject.TextLayoutBlock block = textLayoutBlocks.get(i); + if (block != null && block.textLayout != null) { + translationLoadingPath.setCurrentLayout(block.textLayout, 0, block.isRtl() ? rtlOffset : 0, block.textYOffset); + block.textLayout.getSelectionPath(0, block.textLayout.getText().length(), translationLoadingPath); + } + } + translationLoadingDrawable.updateBounds(); + } + + if (translating && (translationLoadingDrawable.isDisappearing() || translationLoadingDrawable.isDisappeared())) { + translationLoadingDrawable.reset(); + translationLoadingDrawable.resetDisappear(); + } else if (!translating && !translationLoadingDrawable.isDisappearing() && !translationLoadingDrawable.isDisappeared()) { + translationLoadingDrawable.disappear(); + } + + int color = getThemedColor(currentMessageObject != null && currentMessageObject.isOutOwner() ? Theme.key_chat_messageLinkOut : Theme.key_chat_messageLinkIn); + translationLoadingDrawable.setColors( + Theme.multAlpha(color, .05f), + Theme.multAlpha(color, .15f), + Theme.multAlpha(color, .1f), + Theme.multAlpha(color, .3f) + ); + canvas.save(); + canvas.translate(textX, textY + transitionYOffsetForDrawables); + translationLoadingDrawable.setAlpha((int) (0xFF * alpha * translationLoading)); + translationLoadingDrawable.draw(canvas); + canvas.restore(); + invalidate(); + } + } + if (firstVisibleBlockNum >= 0) { int restore = Integer.MIN_VALUE; int oldAlpha = 0; @@ -10725,7 +10845,7 @@ public void drawMessageText(Canvas canvas, ArrayList 0) { replyTextWidth += (int) Math.ceil(replyTextLayout.getLineWidth(0)) + AndroidUtilities.dp(8); @@ -12738,10 +12880,9 @@ private String getAuthorName() { private Object getAuthorStatus() { if (currentUser != null) { - if (currentUser.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) currentUser.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { - return ((TLRPC.TL_emojiStatusUntil) currentUser.emoji_status).document_id; - } else if (currentUser.emoji_status instanceof TLRPC.TL_emojiStatus) { - return ((TLRPC.TL_emojiStatus) currentUser.emoji_status).document_id; + Long emojiStatusId = UserObject.getEmojiStatusDocumentId(currentUser); + if (emojiStatusId != null) { + return emojiStatusId; } else if (currentUser.premium) { return ContextCompat.getDrawable(ApplicationLoader.applicationContext, R.drawable.msg_premium_liststar).mutate(); } @@ -13689,10 +13830,12 @@ public void drawOutboundsContent(Canvas canvas) { } if (!transitionParams.transitionBotButtons.isEmpty() && transitionParams.animateBotButtonsChanged) { - drawBotButtons(canvas, transitionParams.transitionBotButtons, 1f - transitionParams.animateChangeProgress); + float t = transitionParams.animateChangeProgress; + t = MathUtils.clamp(1f - (float) Math.pow(t, 2f), 0f, 1f); + drawBotButtons(canvas, transitionParams.transitionBotButtons, (int) (0xFF * t)); } if (!botButtons.isEmpty()) { - drawBotButtons(canvas, botButtons, transitionParams.animateBotButtonsChanged ? transitionParams.animateChangeProgress : 1f); + drawBotButtons(canvas, botButtons, transitionParams.animateBotButtonsChanged ? (int) (0xFF * transitionParams.animateChangeProgress) : 0xFF); } drawSideButton(canvas); } @@ -14230,13 +14373,13 @@ public void drawNamesLayout(Canvas canvas, float alpha) { } else { ax = backgroundDrawableLeft + transitionParams.deltaLeft + backgroundDrawableRight + AndroidUtilities.dp(22) + nameWidth - adminLayout.getLineWidth(0); } - } else if (!mediaBackground && currentMessageObject.isOutOwner()) { ax = backgroundDrawableLeft + backgroundDrawableRight - AndroidUtilities.dp(17) - adminLayout.getLineWidth(0); } else { ax = backgroundDrawableLeft + backgroundDrawableRight - AndroidUtilities.dp(11) - adminLayout.getLineWidth(0); } } + ax += transitionParams.deltaRight; canvas.translate(ax, nameY + AndroidUtilities.dp(0.5f)); if (transitionParams.animateSign) { Theme.chat_adminPaint.setAlpha((int) (Color.alpha(color) * transitionParams.animateChangeProgress)); @@ -14687,12 +14830,36 @@ public void drawNamesLayout(Canvas canvas, float alpha) { replyNameLayout.draw(canvas); canvas.restore(); } + int spoilersColor; + if (currentMessageObject != null && currentMessageObject.isOut() && !ChatObject.isChannelAndNotMegaGroup(currentMessageObject.getChatId(), currentAccount)) { + spoilersColor = getThemedColor(Theme.key_chat_outTimeText); + } else { + spoilersColor = Theme.chat_replyTextPaint.getColor(); + } + if (transitionParams.animateReplyTextLayout != null && transitionParams.animateChangeProgress < 1) { + canvas.save(); + canvas.clipRect(replySelectorRect); + + canvas.save(); + canvas.translate(forwardNameX + replyTextOffset - transitionParams.animateReplyTextOffset, replyStartY + Theme.chat_replyNamePaint.getTextSize() + AndroidUtilities.dp(5)); + int wasAlpha2 = Theme.chat_replyTextPaint.getAlpha(); + Theme.chat_replyTextPaint.setAlpha((int) (wasAlpha2 * (1f - transitionParams.animateChangeProgress))); + SpoilerEffect.renderWithRipple(this, invalidateSpoilersParent, spoilersColor, -AndroidUtilities.dp(2), spoilersPatchedReplyTextLayout, transitionParams.animateReplyTextLayout, replySpoilers, canvas, false); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, transitionParams.animateReplyTextLayout, transitionParams.animateOutAnimateEmojiReply, 0, replySpoilers, 0, 0, 0, alpha, Theme.chat_animatedEmojiTextColorFilter); + Theme.chat_replyTextPaint.setAlpha(wasAlpha2); + canvas.restore(); + } if (replyTextLayout != null) { canvas.save(); canvas.translate(forwardNameX, replyStartY + Theme.chat_replyNamePaint.getTextSize() + AndroidUtilities.dp(5)); - int spoilersColor = currentMessageObject.isOut() && !ChatObject.isChannelAndNotMegaGroup(currentMessageObject.getChatId(), currentAccount) ? getThemedColor(Theme.key_chat_outTimeText) : replyTextLayout.getPaint().getColor(); + int wasAlpha2 = Theme.chat_replyTextPaint.getAlpha(); + Theme.chat_replyTextPaint.setAlpha((int) (wasAlpha2 * (transitionParams.animateReplyTextLayout != null ? transitionParams.animateChangeProgress : 1))); SpoilerEffect.renderWithRipple(this, invalidateSpoilersParent, spoilersColor, -AndroidUtilities.dp(2), spoilersPatchedReplyTextLayout, replyTextLayout, replySpoilers, canvas, false); AnimatedEmojiSpan.drawAnimatedEmojis(canvas, replyTextLayout, animatedEmojiReplyStack, 0, replySpoilers, 0, 0, 0, alpha, Theme.chat_animatedEmojiTextColorFilter); + Theme.chat_replyTextPaint.setAlpha(wasAlpha2); + canvas.restore(); + } + if (transitionParams.animateReplyTextLayout != null && transitionParams.animateChangeProgress < 1) { canvas.restore(); } @@ -15180,6 +15347,49 @@ private void drawCaptionLayout(Canvas canvas, StaticLayout captionLayout, boolea } } canvas.translate(captionX, captionY); + boolean translating = MessagesController.getInstance(currentAccount).getTranslateController().isTranslating(getMessageObject(), getCurrentMessagesGroup()); + if (true) { + if (translationLoadingFloat == null) { + translationLoadingFloat = new AnimatedFloat(((View) getParent()), 350, CubicBezierInterpolator.EASE_OUT_QUINT); + } + float translationLoading = translationLoadingFloat.set(translating ? 1 : 0); + if (translationLoading > 0) { + if (translationLoadingDrawable == null) { + translationLoadingDrawable = new LoadingDrawable(); + translationLoadingDrawable.setAppearByGradient(true); + if (translationLoadingPath == null) { + translationLoadingPath = new LinkPath(true); + } + translationLoadingDrawable.usePath(translationLoadingPath); + translationLoadingDrawable.setRadiiDp(5); + } + + if (translationLoadingDrawableLayout != captionLayout) { + translationLoadingDrawableLayout = captionLayout; + translationLoadingPath.setCurrentLayout(captionLayout, 0, 0); + captionLayout.getSelectionPath(0, captionLayout.getText().length(), translationLoadingPath); + translationLoadingDrawable.updateBounds(); + } + + if (translating && translationLoadingDrawable.isDisappearing() || translationLoadingDrawable.isDisappeared()) { + translationLoadingDrawable.reset(); + translationLoadingDrawable.resetDisappear(); + } else if (!translating && !translationLoadingDrawable.isDisappearing() && !translationLoadingDrawable.isDisappeared()) { + translationLoadingDrawable.disappear(); + } + + int color = getThemedColor(currentMessageObject != null && currentMessageObject.isOutOwner() ? Theme.key_chat_messageLinkOut : Theme.key_chat_messageLinkIn); + translationLoadingDrawable.setColors( + Theme.multAlpha(color, .05f), + Theme.multAlpha(color, .15f), + Theme.multAlpha(color, .1f), + Theme.multAlpha(color, .3f) + ); + translationLoadingDrawable.setAlpha((int) (0xFF * alpha * translationLoading)); + translationLoadingDrawable.draw(canvas); + invalidate(); + } + } if (links.draw(canvas)) { invalidate(); @@ -18557,8 +18767,12 @@ public class TransitionParams { private ArrayList animateOutTextBlocks; private ArrayList lastDrawingTextBlocks; + private float animateOutTextXOffset; private AnimatedEmojiSpan.EmojiGroupedSpans animateOutAnimateEmoji; + private StaticLayout animateReplyTextLayout; + private AnimatedEmojiSpan.EmojiGroupedSpans animateOutAnimateEmojiReply; + private boolean animateEditedEnter; private StaticLayout animateEditedLayout; private StaticLayout animateTimeLayout; @@ -18611,6 +18825,7 @@ public class TransitionParams { public float lastDrawingTextX; public float animateFromTextY; + public float lastTextXOffset; public int lastTopOffset; public boolean animateForwardedLayout; @@ -18624,6 +18839,10 @@ public class TransitionParams { int animateForwardNameWidth; int lastForwardNameWidth; boolean animateBotButtonsChanged; + public StaticLayout lastDrawnReplyTextLayout; + + public int lastReplyTextXOffset; + public float animateReplyTextOffset; public void recordDrawingState() { wasDraw = true; @@ -18697,6 +18916,10 @@ public void recordDrawingState() { lastForwardNameWidth = forwardedNameWidth; lastBackgroundLeft = getCurrentBackgroundLeft(); lastBackgroundRight = currentBackgroundDrawable.getBounds().right; + lastTextXOffset = currentMessageObject.textXOffset; + + lastDrawnReplyTextLayout = replyTextLayout; + lastReplyTextXOffset = replyTextOffset; reactionsLayoutInBubble.recordDrawingState(); if (replyNameLayout != null) { @@ -18743,6 +18966,7 @@ public boolean animateChange() { if (!sameText) { animateMessageText = true; animateOutTextBlocks = lastDrawingTextBlocks; + animateOutTextXOffset = lastTextXOffset; animateOutAnimateEmoji = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, ChatMessageCell.this, animateOutAnimateEmoji, lastDrawingTextBlocks, true); animatedEmojiStack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, ChatMessageCell.this, animatedEmojiStack, currentMessageObject.textLayoutBlocks); changed = true; @@ -18750,6 +18974,12 @@ public boolean animateChange() { animatedEmojiStack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, ChatMessageCell.this, animatedEmojiStack, currentMessageObject.textLayoutBlocks); } } + if (replyTextLayout != lastDrawnReplyTextLayout) { + animateReplyTextLayout = lastDrawnReplyTextLayout; + animateReplyTextOffset = lastReplyTextXOffset; + animateOutAnimateEmojiReply = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, ChatMessageCell.this, false, animateOutAnimateEmojiReply, true, lastDrawnReplyTextLayout); + changed = true; + } if (edited && !lastDrawingEdited && timeLayout != null) { String editedStr = LocaleController.getString("EditedMessage", R.string.EditedMessage); CharSequence text = timeLayout.getText(); @@ -18831,7 +19061,7 @@ public boolean animateChange() { for (int i = 0; i < botButtons.size(); i++) { BotButton button1 = botButtons.get(i); BotButton button2 = lastDrawBotButtons.get(i); - if (button1.x != button2.x || button1.width != button2.width) { + if (button1.x != button2.x || button1.width != button2.width || button1.title != button2.title) { animateBotButtonsChanged = true; break; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/CheckBoxCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/CheckBoxCell.java index 757e14bd0e2..c771bc68844 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/CheckBoxCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/CheckBoxCell.java @@ -257,11 +257,14 @@ public void setTextColor(int color) { } public void setText(CharSequence text, String value, boolean checked, boolean divider) { + setText(text, value, checked, divider, false); + } + public void setText(CharSequence text, String value, boolean checked, boolean divider, boolean animated) { textView.setText(text); if (checkBoxRound != null) { - checkBoxRound.setChecked(checked, false); + checkBoxRound.setChecked(checked, animated); } else { - checkBoxSquare.setChecked(checked, false); + checkBoxSquare.setChecked(checked, animated); } valueTextView.setText(value); needDivider = divider; @@ -359,6 +362,10 @@ public void setCheckBoxColor(String background, String background1, String check } } + public CheckBox2 getCheckBoxRound() { + return checkBoxRound; + } + public void setSquareCheckBoxColor(String uncheckedColor, String checkedColor, String checkColor) { if (checkBoxSquare != null) { checkBoxSquare.setColors(uncheckedColor, checkedColor, checkColor); @@ -385,4 +392,12 @@ private int getThemedColor(String key) { Integer color = resourcesProvider != null ? resourcesProvider.getColor(key) : null; return color != null ? color : Theme.getColor(key); } + + public void setIcon(int icon) { + checkBoxRound.setIcon(icon); + } + + public boolean hasIcon() { + return checkBoxRound.hasIcon(); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java index d6a968ce9c7..33a9c48ae11 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -99,6 +99,7 @@ import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.Components.URLSpanNoUnderline; import org.telegram.ui.Components.URLSpanNoUnderlineBold; +import org.telegram.ui.Components.VectorAvatarThumbDrawable; import org.telegram.ui.Components.spoilers.SpoilerEffect; import org.telegram.ui.DialogsActivity; import org.telegram.ui.RightSlidingDialogContainer; @@ -932,6 +933,9 @@ public void buildLayout() { } } + if (message != null) { + message.updateTranslation(); + } CharSequence msgText = message != null ? message.messageText : null; if (msgText instanceof Spannable) { Spannable sp = new SpannableStringBuilder(msgText); @@ -1100,12 +1104,10 @@ public void buildLayout() { } drawPremium = MessagesController.getInstance(currentAccount).isPremiumUser(user) && UserConfig.getInstance(currentAccount).clientUserId != user.id && user.id != 0; if (drawPremium) { - if (user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { + Long emojiStatusId = UserObject.getEmojiStatusDocumentId(user); + if (emojiStatusId != null) { nameLayoutEllipsizeByGradient = true; - emojiStatus.set(((TLRPC.TL_emojiStatusUntil) user.emoji_status).document_id, false); - } else if (user.emoji_status instanceof TLRPC.TL_emojiStatus) { - nameLayoutEllipsizeByGradient = true; - emojiStatus.set(((TLRPC.TL_emojiStatus) user.emoji_status).document_id, false); + emojiStatus.set(emojiStatusId, false); } else { nameLayoutEllipsizeByGradient = true; emojiStatus.set(PremiumGradient.getInstance().premiumStarDrawableMini, false); @@ -1227,7 +1229,7 @@ public void buildLayout() { } } } else { - if (dialogsType == 3 && UserObject.isUserSelf(user)) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_FORWARD && UserObject.isUserSelf(user)) { messageString = LocaleController.getString("SavedMessagesInfo", R.string.SavedMessagesInfo); showChecks = false; drawTime = false; @@ -1269,7 +1271,7 @@ public void buildLayout() { } if (lastMessageIsReaction) { - } else if (dialogsType == 2) { + } else if (dialogsType == DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO) { if (chat != null) { if (ChatObject.isChannel(chat) && !chat.megagroup) { if (chat.participants_count != 0) { @@ -1300,7 +1302,7 @@ public void buildLayout() { drawCount2 = false; showChecks = false; drawTime = false; - } else if (dialogsType == 3 && UserObject.isUserSelf(user)) { + } else if (dialogsType == DialogsActivity.DIALOGS_TYPE_FORWARD && UserObject.isUserSelf(user)) { messageString = LocaleController.getString("SavedMessagesInfo", R.string.SavedMessagesInfo); showChecks = false; drawTime = false; @@ -1599,7 +1601,7 @@ public void buildLayout() { promoDialog = false; MessagesController messagesController = MessagesController.getInstance(currentAccount); - if (dialogsType == 0 && messagesController.isPromoDialog(currentDialogId, true)) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_DEFAULT && messagesController.isPromoDialog(currentDialogId, true)) { drawPinBackground = true; promoDialog = true; if (messagesController.promoDialogType == MessagesController.PROMO_TYPE_PROXY) { @@ -1645,7 +1647,7 @@ public void buildLayout() { if (useMeForMyMessages) { nameString = LocaleController.getString("FromYou", R.string.FromYou); } else { - if (dialogsType == 3) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_FORWARD) { drawPinBackground = true; } nameString = LocaleController.getString("SavedMessages", R.string.SavedMessages); @@ -2587,7 +2589,7 @@ public boolean update(int mask, boolean animated) { mentionCount = forumTopic.unread_mentions_count; reactionMentionCount = forumTopic.unread_reactions_count; } - if (dialogsType == 2) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO) { drawPin = false; } @@ -2599,12 +2601,10 @@ public boolean update(int mask, boolean animated) { } if (user != null && (mask & MessagesController.UPDATE_MASK_EMOJI_STATUS) != 0) { user = MessagesController.getInstance(currentAccount).getUser(user.id); - if (user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { - nameLayoutEllipsizeByGradient = true; - emojiStatus.set(((TLRPC.TL_emojiStatusUntil) user.emoji_status).document_id, animated); - } else if (user.emoji_status instanceof TLRPC.TL_emojiStatus) { + Long emojiStatusId = UserObject.getEmojiStatusDocumentId(user); + if (emojiStatusId != null) { nameLayoutEllipsizeByGradient = true; - emojiStatus.set(((TLRPC.TL_emojiStatus) user.emoji_status).document_id, animated); + emojiStatus.set(emojiStatusId, animated); } else { nameLayoutEllipsizeByGradient = true; emojiStatus.set(PremiumGradient.getInstance().premiumStarDrawableMini, animated); @@ -2774,7 +2774,7 @@ public boolean update(int mask, boolean animated) { avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_SAVED); avatarImage.setImage(null, null, avatarDrawable, null, user, 0); } else { - avatarImage.setForUserOrChat(user, avatarDrawable, null, true); + avatarImage.setForUserOrChat(user, avatarDrawable, null, true, VectorAvatarThumbDrawable.TYPE_SMALL); } } else if (chat != null) { avatarDrawable.setInfo(chat); @@ -3721,6 +3721,9 @@ protected void onDraw(Canvas canvas) { timerPaint.setShader(null); if (avatarImage.getBitmap() != null && !avatarImage.getBitmap().isRecycled()) { timerPaint.setColor(PremiumLockIconView.getDominantColor(avatarImage.getBitmap())); + } else if (avatarImage.getDrawable() instanceof VectorAvatarThumbDrawable){ + VectorAvatarThumbDrawable vectorAvatarThumbDrawable = (VectorAvatarThumbDrawable) avatarImage.getDrawable(); + timerPaint.setColor(vectorAvatarThumbDrawable.gradientTools.getAverageColor()); } else { timerPaint.setColor(avatarDrawable.getColor2()); } @@ -4572,6 +4575,9 @@ public SpannableStringBuilder getMessageStringFormatted(String messageFormat, St applyName = false; stringBuilder = SpannableStringBuilder.valueOf(mess); } + if (applyThumbs) { + applyThumbs(stringBuilder); + } } else if (captionMessage != null && captionMessage.caption != null) { MessageObject message = captionMessage; CharSequence mess = message.caption.toString(); @@ -4784,6 +4790,10 @@ private class DialogUpdateHelper { public boolean update() { TLRPC.Dialog dialog = MessagesController.getInstance(currentAccount).dialogs_dict.get(currentDialogId); if (dialog == null) { + if (dialogsType == DialogsActivity.DIALOGS_TYPE_FORWARD && lastDrawnDialogId != currentDialogId) { + lastDrawnDialogId = currentDialogId; + return true; + } return false; } int messageHash = message == null ? 0 : message.getId(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsHintCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsHintCell.java new file mode 100644 index 00000000000..97b6678e884 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsHintCell.java @@ -0,0 +1,104 @@ +package org.telegram.ui.Cells; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.PorterDuff; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; + +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.LayoutHelper; + +public class DialogsHintCell extends FrameLayout { + private LinearLayout contentView; + private TextView titleView; + private TextView messageView; + private ImageView chevronView; + + public DialogsHintCell(@NonNull Context context) { + super(context); + + setWillNotDraw(false); + setPadding(dp(16), dp(8), dp(16), dp(8)); + + contentView = new LinearLayout(context); + contentView.setOrientation(LinearLayout.VERTICAL); + contentView.setPadding(LocaleController.isRTL ? dp(24) : 0, 0, LocaleController.isRTL ? 0 : dp(24), 0); + addView(contentView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + titleView = new TextView(context); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + titleView.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + titleView.setSingleLine(); + contentView.addView(titleView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, Gravity.TOP)); + + messageView = new TextView(context); + messageView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + messageView.setMaxLines(2); + messageView.setEllipsize(TextUtils.TruncateAt.END); + contentView.addView(messageView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, Gravity.TOP)); + + chevronView = new ImageView(context); + chevronView.setImageResource(R.drawable.arrow_newchat); + chevronView.setColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText), PorterDuff.Mode.SRC_IN); + addView(chevronView, LayoutHelper.createFrame(16, 16, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL)); + + updateColors(); + } + + public void updateColors() { + titleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + messageView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText)); + setBackground(Theme.AdaptiveRipple.filledRect()); + } + + public void setText(CharSequence title, CharSequence subtitle) { + titleView.setText(title); + messageView.setText(subtitle); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + canvas.drawLine(0, getHeight() - 1, getWidth(), getHeight() - 1, Theme.dividerPaint); + } + + private int height; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = MeasureSpec.getSize(widthMeasureSpec); + if (width <= 0) { + width = AndroidUtilities.displaySize.x; + } + contentView.measure( + MeasureSpec.makeMeasureSpec(width - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.y, MeasureSpec.AT_MOST) + ); + this.height = contentView.getMeasuredHeight() + getPaddingTop() + getPaddingBottom() + 1; + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); + } + + public int height() { + if (getVisibility() != View.VISIBLE) { + return 0; + } + if (height <= 0) { + height = dp(72) + 1; + } + return height; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsRequestedEmptyCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsRequestedEmptyCell.java new file mode 100644 index 00000000000..9db08bff42c --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogsRequestedEmptyCell.java @@ -0,0 +1,177 @@ +package org.telegram.ui.Cells; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.DocumentObject; +import org.telegram.messenger.ImageLocation; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.SvgHelper; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.StickerEmptyView; + +public class DialogsRequestedEmptyCell extends LinearLayout implements NotificationCenter.NotificationCenterDelegate { + + int currentAccount = UserConfig.selectedAccount; + BackupImageView stickerView; + TextView titleView; + TextView subtitleView; + TextView buttonView; + + public DialogsRequestedEmptyCell(Context context) { + super(context); + + setOrientation(VERTICAL); + setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + + LinearLayout linearLayout = new LinearLayout(context) { + Path path = new Path(); + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + { + paint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + paint.setShadowLayer(dp(1.33f), 0, dp(.33f), 0x1e000000); + } + @Override + protected void onDraw(Canvas canvas) { + canvas.drawPath(path, paint); + super.onDraw(canvas); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + path.rewind(); + AndroidUtilities.rectTmp.set(AndroidUtilities.dp(12), AndroidUtilities.dp(6), getMeasuredWidth() - AndroidUtilities.dp(12), getMeasuredHeight() - AndroidUtilities.dp(12)); + path.addRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(10), AndroidUtilities.dp(10), Path.Direction.CW); + } + }; + linearLayout.setWillNotDraw(false); + linearLayout.setOrientation(VERTICAL); + linearLayout.setPadding(AndroidUtilities.dp(12 + 20), AndroidUtilities.dp(6 + 10), AndroidUtilities.dp(12 + 20), AndroidUtilities.dp(12 +20)); + + stickerView = new BackupImageView(context); + stickerView.setOnClickListener(e -> { + stickerView.getImageReceiver().startAnimation(); + }); + updateSticker(); + linearLayout.addView(stickerView, LayoutHelper.createLinear(130, 130, Gravity.CENTER_HORIZONTAL | Gravity.TOP)); + + titleView = new TextView(context); + titleView.setGravity(Gravity.CENTER); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); + titleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + linearLayout.addView(titleView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 0, 6, 0, 0)); + + subtitleView = new TextView(context); + subtitleView.setGravity(Gravity.CENTER); + subtitleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + subtitleView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText)); + linearLayout.addView(subtitleView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 0, 7, 0, 0)); + + buttonView = new TextView(context); + buttonView.setGravity(Gravity.CENTER); + buttonView.setBackground(Theme.AdaptiveRipple.filledRect(Theme.key_featuredStickers_addButton, 8)); + buttonView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + buttonView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); + buttonView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + buttonView.setPadding(AndroidUtilities.dp(14), AndroidUtilities.dp(14), AndroidUtilities.dp(14), AndroidUtilities.dp(14)); + buttonView.setOnClickListener(e -> { + onButtonClick(); + }); + linearLayout.addView(buttonView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 0, 18, 0, 0)); + + addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + set(null); + } + + protected void onButtonClick() { + + } + + public void set(TLRPC.RequestPeerType requestPeerType) { + if (requestPeerType instanceof TLRPC.TL_requestPeerTypeBroadcast) { + titleView.setText(LocaleController.getString("NoSuchChannels", R.string.NoSuchChannels)); + subtitleView.setText(LocaleController.getString("NoSuchChannelsInfo", R.string.NoSuchChannelsInfo)); + buttonView.setVisibility(View.VISIBLE); + buttonView.setText(LocaleController.getString("CreateChannelForThis", R.string.CreateChannelForThis)); + } else if (requestPeerType instanceof TLRPC.TL_requestPeerTypeChat) { + titleView.setText(LocaleController.getString("NoSuchGroups", R.string.NoSuchGroups)); + subtitleView.setText(LocaleController.getString("NoSuchGroupsInfo", R.string.NoSuchGroupsInfo)); + buttonView.setVisibility(View.VISIBLE); + buttonView.setText(LocaleController.getString("CreateGroupForThis", R.string.CreateGroupForThis)); + } else { + titleView.setText(LocaleController.getString("NoSuchUsers", R.string.NoSuchUsers)); + subtitleView.setText(LocaleController.getString("NoSuchUsersInfo", R.string.NoSuchUsersInfo)); + buttonView.setVisibility(View.GONE); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.diceStickersDidLoad); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.diceStickersDidLoad); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.diceStickersDidLoad) { + String name = (String) args[0]; + if (AndroidUtilities.STICKERS_PLACEHOLDER_PACK_NAME.equals(name) && getVisibility() == VISIBLE) { + updateSticker(); + } + } + } + + private void updateSticker() { + final int stickerType = StickerEmptyView.STICKER_TYPE_SEARCH; + + TLRPC.Document document = null; + TLRPC.TL_messages_stickerSet set = MediaDataController.getInstance(currentAccount).getStickerSetByName(AndroidUtilities.STICKERS_PLACEHOLDER_PACK_NAME); + if (set == null) { + set = MediaDataController.getInstance(currentAccount).getStickerSetByEmojiOrName(AndroidUtilities.STICKERS_PLACEHOLDER_PACK_NAME); + } + if (set != null && stickerType >= 0 && stickerType < set.documents.size() ) { + document = set.documents.get(stickerType); + } + + if (document != null) { + SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(document.thumbs, Theme.key_windowBackgroundGray, 0.2f); + if (svgThumb != null) { + svgThumb.overrideWidthAndHeight(512, 512); + } + + ImageLocation imageLocation = ImageLocation.getForDocument(document); + stickerView.setImage(imageLocation, "130_130", "tgs", svgThumb, set); + stickerView.getImageReceiver().setAutoRepeat(2); + } else { + MediaDataController.getInstance(currentAccount).loadStickersByEmojiOrName(AndroidUtilities.STICKERS_PLACEHOLDER_PACK_NAME, false, set == null); + stickerView.getImageReceiver().clearImage(); + } + } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerActionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerActionCell.java index b2e8003efcd..e6704d1449f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerActionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerActionCell.java @@ -14,11 +14,8 @@ import android.graphics.PorterDuffColorFilter; import android.graphics.RectF; import android.graphics.drawable.Drawable; -import android.util.TypedValue; import android.view.Gravity; -import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; -import android.widget.Button; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; @@ -49,18 +46,22 @@ public DrawerActionCell(Context context) { imageView = new ImageView(context); addView(imageView, LayoutHelper.createFrame(24, 24, Gravity.LEFT | Gravity.TOP, 19, 12, 0, 0)); +// addView(imageView, LayoutHelper.createFrame(24, 24, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 19, 12, LocaleController.isRTL ? 19 : 0, 0)); lottieImageView = new RLottieImageView(context); lottieImageView.setAutoRepeat(false); lottieImageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chats_menuItemIcon), PorterDuff.Mode.SRC_IN)); addView(lottieImageView, LayoutHelper.createFrame(28, 28, Gravity.LEFT | Gravity.TOP, 17, 10, 0, 0)); +// addView(lottieImageView, LayoutHelper.createFrame(28, 28, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 17, 10, LocaleController.isRTL ? 17 : 0, 0)); textView = new AnimatedTextView(context, true, true, true); textView.setAnimationProperties(.6f, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); textView.setTextColor(Theme.getColor(Theme.key_chats_menuItemText)); textView.setTextSize(AndroidUtilities.dp(15)); textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setIgnoreRTL(true); addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 19 + 24 + 29, 0, 16, 0)); +// addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 16 : 62, 0, LocaleController.isRTL ? 62 : 16, 0)); setWillNotDraw(false); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java index 12e6752eeb1..f7c14a92a25 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java @@ -100,7 +100,7 @@ public class DrawerProfileCell extends FrameLayout implements NotificationCenter private float stateX, stateY; StarParticlesView.Drawable starParticlesDrawable; - PremiumGradient.GradientTools gradientTools; + PremiumGradient.PremiumGradientTools gradientTools; public DrawerProfileCell(Context context, DrawerLayoutContainer drawerLayoutContainer) { super(context); @@ -587,7 +587,7 @@ protected void onDraw(Canvas canvas) { drawPremiumProgress = Utilities.clamp(drawPremiumProgress, 1f, 0); if (drawPremiumProgress != 0) { if (gradientTools == null) { - gradientTools = new PremiumGradient.GradientTools(Theme.key_premiumGradientBottomSheet1, Theme.key_premiumGradientBottomSheet2, Theme.key_premiumGradientBottomSheet3, null); + gradientTools = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradientBottomSheet1, Theme.key_premiumGradientBottomSheet2, Theme.key_premiumGradientBottomSheet3, null); gradientTools.x1 = 0; gradientTools.y1 = 1.1f; gradientTools.x2 = 1.5f; @@ -655,14 +655,11 @@ public void setUser(TLRPC.User user, boolean accounts) { drawPremium = false;//user.premium; nameTextView.setText(text); - if (user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { + Long emojiStatusId = UserObject.getEmojiStatusDocumentId(user); + if (emojiStatusId != null) { animatedStatus.animate().alpha(1).setDuration(200).start(); nameTextView.setDrawablePadding(AndroidUtilities.dp(4)); - status.set(((TLRPC.TL_emojiStatusUntil) user.emoji_status).document_id, true); - } else if (user.emoji_status instanceof TLRPC.TL_emojiStatus) { - animatedStatus.animate().alpha(1).setDuration(200).start(); - nameTextView.setDrawablePadding(AndroidUtilities.dp(4)); - status.set(((TLRPC.TL_emojiStatus) user.emoji_status).document_id, true); + status.set(emojiStatusId, true); } else if (user.premium) { animatedStatus.animate().alpha(1).setDuration(200).start(); nameTextView.setDrawablePadding(AndroidUtilities.dp(4)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerUserCell.java index 1557a78477f..120e1c095af 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerUserCell.java @@ -10,7 +10,6 @@ import android.content.Context; import android.graphics.Canvas; -import android.graphics.Path; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.view.Gravity; @@ -25,6 +24,7 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.NotificationsController; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; @@ -139,13 +139,10 @@ public void setAccount(int account) { text = Emoji.replaceEmoji(text, textView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false); } catch (Exception ignore) {} textView.setText(text); - if (user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { + Long emojiStatusId = UserObject.getEmojiStatusDocumentId(user); + if (emojiStatusId != null) { textView.setDrawablePadding(AndroidUtilities.dp(4)); - status.set(((TLRPC.TL_emojiStatusUntil) user.emoji_status).document_id, true); - textView.setRightDrawableOutside(true); - } else if (user.emoji_status instanceof TLRPC.TL_emojiStatus) { - textView.setDrawablePadding(AndroidUtilities.dp(4)); - status.set(((TLRPC.TL_emojiStatus) user.emoji_status).document_id, true); + status.set(emojiStatusId, true); textView.setRightDrawableOutside(true); } else if (MessagesController.getInstance(account).isPremiumUser(user)) { textView.setDrawablePadding(AndroidUtilities.dp(6)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java index 4dc1997c0cf..13e15585231 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java @@ -289,44 +289,42 @@ public void buildLayout() { } nameLockTop = AndroidUtilities.dp(22.0f); updateStatus(false, null, false); - } else { - if (chat != null) { - dialog_id = -chat.id; - drawCheck = chat.verified; - if (!LocaleController.isRTL) { - nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline); - } else { - nameLeft = AndroidUtilities.dp(11); - } - updateStatus(drawCheck, null, false); - } else if (user != null) { - dialog_id = user.id; - if (!LocaleController.isRTL) { - nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline); - } else { - nameLeft = AndroidUtilities.dp(11); - } - nameLockTop = AndroidUtilities.dp(21); - drawCheck = user.verified; - drawPremium = !user.self && MessagesController.getInstance(currentAccount).isPremiumUser(user); - updateStatus(drawCheck, user, false); - } else if (contact != null) { - if (!LocaleController.isRTL) { - nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline); - } else { - nameLeft = AndroidUtilities.dp(11); - } - if (actionButton == null) { - actionButton = new CanvasButton(this); - actionButton.setDelegate(() -> { - if (getParent() instanceof RecyclerListView) { - RecyclerListView parent = (RecyclerListView) getParent(); - parent.getOnItemClickListener().onItemClick(this, parent.getChildAdapterPosition(this)); - } else { - callOnClick(); - } - }); - } + } else if (chat != null) { + dialog_id = -chat.id; + drawCheck = chat.verified; + if (!LocaleController.isRTL) { + nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline); + } else { + nameLeft = AndroidUtilities.dp(11); + } + updateStatus(drawCheck, null, false); + } else if (user != null) { + dialog_id = user.id; + if (!LocaleController.isRTL) { + nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline); + } else { + nameLeft = AndroidUtilities.dp(11); + } + nameLockTop = AndroidUtilities.dp(21); + drawCheck = user.verified; + drawPremium = !savedMessages && MessagesController.getInstance(currentAccount).isPremiumUser(user); + updateStatus(drawCheck, user, false); + } else if (contact != null) { + if (!LocaleController.isRTL) { + nameLeft = AndroidUtilities.dp(AndroidUtilities.leftBaseline); + } else { + nameLeft = AndroidUtilities.dp(11); + } + if (actionButton == null) { + actionButton = new CanvasButton(this); + actionButton.setDelegate(() -> { + if (getParent() instanceof RecyclerListView) { + RecyclerListView parent = (RecyclerListView) getParent(); + parent.getOnItemClickListener().onItemClick(this, parent.getChildAdapterPosition(this)); + } else { + callOnClick(); + } + }); } } @@ -548,13 +546,13 @@ public void updateStatus(boolean verified, TLRPC.User user, boolean animated) { if (verified) { statusDrawable.set(new CombinedDrawable(Theme.dialogs_verifiedDrawable, Theme.dialogs_verifiedCheckDrawable, 0, 0), animated); statusDrawable.setColor(null); - } else if (user != null && !user.self && user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { + } else if (user != null && !savedMessages && user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { statusDrawable.set(((TLRPC.TL_emojiStatusUntil) user.emoji_status).document_id, animated); statusDrawable.setColor(Theme.getColor(Theme.key_chats_verifiedBackground, resourcesProvider)); - } else if (user != null && !user.self && user.emoji_status instanceof TLRPC.TL_emojiStatus) { + } else if (user != null && !savedMessages && user.emoji_status instanceof TLRPC.TL_emojiStatus) { statusDrawable.set(((TLRPC.TL_emojiStatus) user.emoji_status).document_id, animated); statusDrawable.setColor(Theme.getColor(Theme.key_chats_verifiedBackground, resourcesProvider)); - } else if (user != null && !user.self && MessagesController.getInstance(currentAccount).isPremiumUser(user)) { + } else if (user != null && !savedMessages && MessagesController.getInstance(currentAccount).isPremiumUser(user)) { statusDrawable.set(PremiumGradient.getInstance().premiumStarDrawableMini, animated); statusDrawable.setColor(Theme.getColor(Theme.key_chats_verifiedBackground, resourcesProvider)); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/RequestPeerRequirementsCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/RequestPeerRequirementsCell.java new file mode 100644 index 00000000000..04cf51d8018 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/RequestPeerRequirementsCell.java @@ -0,0 +1,297 @@ +package org.telegram.ui.Cells; + +import android.content.Context; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.text.SpannableStringBuilder; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.LayoutHelper; + +import java.util.ArrayList; + +public class RequestPeerRequirementsCell extends LinearLayout { + + public RequestPeerRequirementsCell(Context context) { + super(context); + + setOrientation(VERTICAL); + setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + } + + private TLRPC.RequestPeerType requestPeerType; + private ArrayList requirements = new ArrayList<>(); + + public void set(TLRPC.RequestPeerType requestPeerType) { + if (this.requestPeerType != requestPeerType) { + this.requestPeerType = requestPeerType; + removeAllViews(); + + requirements.clear(); + + if (requestPeerType instanceof TLRPC.TL_requestPeerTypeUser) { + TLRPC.TL_requestPeerTypeUser type = (TLRPC.TL_requestPeerTypeUser) requestPeerType; + checkRequirement( + type.premium, + R.string.PeerRequirementPremiumTrue, + R.string.PeerRequirementPremiumFalse + ); + } else { + boolean isChannel = requestPeerType instanceof TLRPC.TL_requestPeerTypeBroadcast; + + if (isChannel) { + checkRequirement(requestPeerType.has_username, R.string.PeerRequirementChannelPublicTrue, R.string.PeerRequirementChannelPublicFalse); + if (requestPeerType.bot_participant != null && requestPeerType.bot_participant) { + requirements.add(Requirement.make(AndroidUtilities.replaceTags(LocaleController.getString(R.string.PeerRequirementChannelBotParticipant)))); + } + if (requestPeerType.creator != null && requestPeerType.creator) { + requirements.add(Requirement.make(AndroidUtilities.replaceTags(LocaleController.getString(R.string.PeerRequirementChannelCreatorTrue)))); + } + } else { + checkRequirement(requestPeerType.has_username, R.string.PeerRequirementGroupPublicTrue, R.string.PeerRequirementGroupPublicFalse); + checkRequirement(requestPeerType.forum, R.string.PeerRequirementForumTrue, R.string.PeerRequirementForumFalse); + if (requestPeerType.bot_participant != null && requestPeerType.bot_participant) { + requirements.add(Requirement.make(AndroidUtilities.replaceTags(LocaleController.getString(R.string.PeerRequirementGroupBotParticipant)))); + } + if (requestPeerType.creator != null && requestPeerType.creator) { + requirements.add(Requirement.make(AndroidUtilities.replaceTags(LocaleController.getString(R.string.PeerRequirementGroupCreatorTrue)))); + } + } + + if (!(requestPeerType.creator != null && requestPeerType.creator)) { + checkAdminRights(requestPeerType.user_admin_rights, isChannel, R.string.PeerRequirementUserRights, R.string.PeerRequirementUserRight); + } +// checkAdminRights(requestPeerType.bot_admin_rights, isChannel, R.string.PeerRequirementBotRights, R.string.PeerRequirementBotRight); + } + + if (!requirements.isEmpty()) { + HeaderCell headerCell = new HeaderCell(getContext(), 20); + headerCell.setText(LocaleController.getString("PeerRequirements", R.string.PeerRequirements)); + headerCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + addView(headerCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + addView(emptyView(9, Theme.getColor(Theme.key_windowBackgroundWhite)), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + for (Requirement requirement : requirements) { + addView(new RequirementCell(getContext(), requirement), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } + addView(emptyView(12, Theme.getColor(Theme.key_windowBackgroundWhite)), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + addView(emptyView(12, Theme.getThemedDrawable(getContext(), R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } + } + } + + private View emptyView(int heightDp, int color) { + return emptyView(heightDp, new ColorDrawable(color)); + } + + private View emptyView(int heightDp, Drawable background) { + View view = new View(getContext()) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(heightDp), MeasureSpec.EXACTLY)); + } + }; + view.setBackground(background); + return view; + } + + private void checkRequirement(Boolean value, String positive, String negative) { + if (value != null) { + if (value) { + requirements.add(Requirement.make(AndroidUtilities.replaceTags(positive))); + } else { + requirements.add(Requirement.make(AndroidUtilities.replaceTags(negative))); + } + } + } + + private void checkRequirement(Boolean value, int positiveResId, int negativeResId) { + if (value != null) { + if (value) { + requirements.add(Requirement.make(AndroidUtilities.replaceTags(LocaleController.getString(positiveResId)))); + } else { + requirements.add(Requirement.make(AndroidUtilities.replaceTags(LocaleController.getString(negativeResId)))); + } + } + } + + public static CharSequence rightsToString(TLRPC.TL_chatAdminRights rights, boolean isChannel) { + ArrayList array = new ArrayList<>(); + if (rights.change_info) { + array.add(Requirement.make( + 1, + isChannel ? + LocaleController.getString("EditAdminChangeChannelInfo", R.string.EditAdminChangeChannelInfo) : + LocaleController.getString("EditAdminChangeGroupInfo", R.string.EditAdminChangeGroupInfo) + )); + } + if (rights.post_messages && isChannel) { + array.add(Requirement.make(1, LocaleController.getString("EditAdminPostMessages", R.string.EditAdminPostMessages))); + } + if (rights.edit_messages && isChannel) { + array.add(Requirement.make(1, LocaleController.getString("EditAdminEditMessages", R.string.EditAdminEditMessages))); + } + if (rights.delete_messages) { + array.add(Requirement.make(1, isChannel ? LocaleController.getString("EditAdminDeleteMessages", R.string.EditAdminDeleteMessages) : LocaleController.getString("EditAdminGroupDeleteMessages", R.string.EditAdminGroupDeleteMessages))); + } + if (rights.ban_users && !isChannel) { + array.add(Requirement.make(1, LocaleController.getString("EditAdminBanUsers", R.string.EditAdminBanUsers))); + } + if (rights.invite_users) { + array.add(Requirement.make(1, LocaleController.getString("EditAdminAddUsers", R.string.EditAdminAddUsers))); + } + if (rights.pin_messages && !isChannel) { + array.add(Requirement.make(1, LocaleController.getString("EditAdminPinMessages", R.string.EditAdminPinMessages))); + } + if (rights.add_admins) { + array.add(Requirement.make(1, LocaleController.getString("EditAdminAddAdmins", R.string.EditAdminAddAdmins))); + } + if (rights.anonymous && !isChannel) { + array.add(Requirement.make(1, LocaleController.getString("EditAdminSendAnonymously", R.string.EditAdminSendAnonymously))); + } + if (rights.manage_call) { + array.add(Requirement.make(1, LocaleController.getString("StartVoipChatPermission", R.string.StartVoipChatPermission))); + } + if (rights.manage_topics && !isChannel) { + array.add(Requirement.make(1, LocaleController.getString("ManageTopicsPermission", R.string.ManageTopicsPermission))); + } + + if (array.size() == 1) { + return array.get(0).text.toString().toLowerCase(); + } else if (!array.isEmpty()) { + SpannableStringBuilder string = new SpannableStringBuilder(); + for (int i = 0; i < array.size(); ++i) { + if (i > 0) { + string.append(", "); + } + string.append(array.get(i).text.toString().toLowerCase()); + } + return string; + } + return ""; + } + + private void checkAdminRights(TLRPC.TL_chatAdminRights value, boolean isChannel, CharSequence headerText, CharSequence headerSingleText) { + if (value == null) { + return; + } + + ArrayList rights = new ArrayList<>(); + if (value.change_info) { + rights.add(Requirement.make( + 1, + isChannel ? + LocaleController.getString("EditAdminChangeChannelInfo", R.string.EditAdminChangeChannelInfo) : + LocaleController.getString("EditAdminChangeGroupInfo", R.string.EditAdminChangeGroupInfo) + )); + } + if (value.post_messages && isChannel) { + rights.add(Requirement.make(1, LocaleController.getString("EditAdminPostMessages", R.string.EditAdminPostMessages))); + } + if (value.edit_messages && isChannel) { + rights.add(Requirement.make(1, LocaleController.getString("EditAdminEditMessages", R.string.EditAdminEditMessages))); + } + if (value.delete_messages) { + rights.add(Requirement.make(1, isChannel ? LocaleController.getString("EditAdminDeleteMessages", R.string.EditAdminDeleteMessages) : LocaleController.getString("EditAdminGroupDeleteMessages", R.string.EditAdminGroupDeleteMessages))); + } + if (value.ban_users && !isChannel) { + rights.add(Requirement.make(1, LocaleController.getString("EditAdminBanUsers", R.string.EditAdminBanUsers))); + } + if (value.invite_users) { + rights.add(Requirement.make(1, LocaleController.getString("EditAdminAddUsers", R.string.EditAdminAddUsers))); + } + if (value.pin_messages && !isChannel) { + rights.add(Requirement.make(1, LocaleController.getString("EditAdminPinMessages", R.string.EditAdminPinMessages))); + } + if (value.add_admins) { + rights.add(Requirement.make(1, LocaleController.getString("EditAdminAddAdmins", R.string.EditAdminAddAdmins))); + } + if (value.anonymous && !isChannel) { + rights.add(Requirement.make(1, LocaleController.getString("EditAdminSendAnonymously", R.string.EditAdminSendAnonymously))); + } + if (value.manage_call) { + rights.add(Requirement.make(1, LocaleController.getString("StartVoipChatPermission", R.string.StartVoipChatPermission))); + } + if (value.manage_topics && !isChannel) { + rights.add(Requirement.make(1, LocaleController.getString("ManageTopicsPermission", R.string.ManageTopicsPermission))); + } + + if (rights.size() == 1) { + requirements.add(Requirement.make(TextUtils.concat(headerSingleText, " ", rights.get(0).text))); + } else if (!rights.isEmpty()) { + SpannableStringBuilder string = SpannableStringBuilder.valueOf(headerText); + string.append(" "); + for (int i = 0; i < rights.size(); ++i) { + if (i > 0) { + string.append(", "); + } + string.append(rights.get(i).text.toString().toLowerCase()); + } + string.append("."); + requirements.add(Requirement.make(string)); + } + } + + private void checkAdminRights(TLRPC.TL_chatAdminRights value, boolean isChannel, int headerTextResId, int headerSingleTextResId) { + checkAdminRights(value, isChannel, AndroidUtilities.replaceTags(LocaleController.getString(headerTextResId)), AndroidUtilities.replaceTags(LocaleController.getString(headerSingleTextResId))); + } + + class RequirementCell extends LinearLayout { + + private ImageView imageView; + private TextView textView; + + public RequirementCell(Context context, Requirement requirement) { + super(context); + + setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + + setOrientation(HORIZONTAL); + + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.CENTER); + imageView.setImageResource(requirement.padding <= 0 ? R.drawable.list_check : R.drawable.list_circle); + imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteBlueHeader), PorterDuff.Mode.MULTIPLY)); + addView(imageView, LayoutHelper.createLinear(20, 20, 0, Gravity.TOP | Gravity.LEFT, 17 + requirement.padding * 16, -1, 0, 0)); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2)); + textView.setSingleLine(false); + textView.setText(requirement.text); + addView(textView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1, 6, 4, 24, 4)); + } + } +} + +class Requirement { + public int padding; + public CharSequence text; + + private Requirement(CharSequence text, int padding) { + this.text = text; + this.padding = padding; + } + + public static Requirement make(CharSequence text) { + return new Requirement(text, 0); + } + + public static Requirement make(int pad, CharSequence text) { + return new Requirement(text, pad); + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell2.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell2.java index 989cc799960..fff78f7d702 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell2.java @@ -255,6 +255,9 @@ private boolean canAutoDownload(MessageObject messageObject) { public void setVideoText(String videoText, boolean drawVideoIcon) { this.videoText = videoText; showVideoLayout = videoText != null; + if (showVideoLayout && videoInfoLayot != null && !videoInfoLayot.getText().toString().equals(videoText)) { + videoInfoLayot = null; + } this.drawVideoIcon = drawVideoIcon; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerSetNameCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerSetNameCell.java index cdd87419092..dc33dbff69f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerSetNameCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerSetNameCell.java @@ -75,9 +75,9 @@ public StickerSetNameCell(Context context, boolean emoji, boolean supportRtl, Th } } if (supportRtl) { - lp = LayoutHelper.createFrameRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.TOP, emoji ? 5 : 17, emoji ? 10 : 2, emoji ? 15 : 57, 0); + lp = LayoutHelper.createFrameRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.TOP, emoji ? 5 : 17, emoji ? 5 : 2, emoji ? 15 : 57, 0); } else { - lp = LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, emoji ? 5 : 17, emoji ? 10 : 2, emoji ? 15 : 57, 0); + lp = LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, emoji ? 5 : 17, emoji ? 5 : 2, emoji ? 15 : 57, 0); } addView(textView, lp); @@ -97,10 +97,14 @@ public StickerSetNameCell(Context context, boolean emoji, boolean supportRtl, Th buttonView = new ImageView(context); buttonView.setScaleType(ImageView.ScaleType.CENTER); buttonView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_emojiPanelStickerSetNameIcon), PorterDuff.Mode.MULTIPLY)); + buttonView.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), Theme.RIPPLE_MASK_CIRCLE_TO_BOUND_EDGE)); if (supportRtl) { - lp = LayoutHelper.createFrameRelatively(24, 24, Gravity.TOP | Gravity.END, 0, 0, 11, 0); + lp = LayoutHelper.createFrameRelatively(24, 24, Gravity.TOP | Gravity.END, 0, 0, isEmoji ? 0 : 11, 0); } else { - lp = LayoutHelper.createFrame(24, 24, Gravity.TOP | Gravity.RIGHT, 0, 0, 11, 0); + lp = LayoutHelper.createFrame(24, 24, Gravity.TOP | Gravity.RIGHT, 0, 0, isEmoji ? 0 : 11, 0); + } + if (isEmoji) { + buttonView.setTranslationY(AndroidUtilities.dp(4)); } addView(buttonView, lp); } @@ -191,7 +195,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (empty) { super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(1, MeasureSpec.EXACTLY)); } else { - super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(isEmoji ? 32 : 24), MeasureSpec.EXACTLY)); + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(isEmoji ? 27 : 24), MeasureSpec.EXACTLY)); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java index 70771dab0bf..6eed7d6ce3b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java @@ -37,6 +37,7 @@ public class TextCell extends FrameLayout { public final SimpleTextView textView; private final SimpleTextView subtitleView; public final AnimatedTextView valueTextView; + public final SimpleTextView valueSpoilersTextView; public final RLottieImageView imageView; private Switch checkBox; private ImageView valueImageView; @@ -88,14 +89,24 @@ public TextCell(Context context, int left, boolean dialog, boolean needCheck, Th subtitleView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); addView(subtitleView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT)); - valueTextView = new AnimatedTextView(context); + valueTextView = new AnimatedTextView(context, false, false, true); valueTextView.setTextColor(Theme.getColor(dialog ? Theme.key_dialogTextBlue2 : Theme.key_windowBackgroundWhiteValueText, resourcesProvider)); valueTextView.setPadding(0, AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18)); valueTextView.setTextSize(AndroidUtilities.dp(16)); valueTextView.setGravity(LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT); valueTextView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); + valueTextView.setTranslationY(AndroidUtilities.dp(-2)); addView(valueTextView); + valueSpoilersTextView = new SimpleTextView(context); + valueSpoilersTextView.setEllipsizeByGradient(18, false); + valueSpoilersTextView.setTextColor(Theme.getColor(dialog ? Theme.key_dialogTextBlue2 : Theme.key_windowBackgroundWhiteValueText, resourcesProvider)); + valueSpoilersTextView.setGravity(LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT); + valueSpoilersTextView.setTextSize(16); + valueSpoilersTextView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); + valueSpoilersTextView.setVisibility(GONE); + addView(valueSpoilersTextView); + imageView = new RLottieImageView(context); imageView.setScaleType(ImageView.ScaleType.CENTER); imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(dialog ? Theme.key_dialogIcon : Theme.key_windowBackgroundWhiteGrayIcon, resourcesProvider), PorterDuff.Mode.MULTIPLY)); @@ -143,8 +154,10 @@ public ImageView getValueImageView() { } public void setPrioritizeTitleOverValue(boolean prioritizeTitleOverValue) { - this.prioritizeTitleOverValue = prioritizeTitleOverValue; - requestLayout(); + if (this.prioritizeTitleOverValue != prioritizeTitleOverValue) { + this.prioritizeTitleOverValue = prioritizeTitleOverValue; + requestLayout(); + } } @Override @@ -152,14 +165,18 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); int height = AndroidUtilities.dp(heightDp); + int valueWidth; if (prioritizeTitleOverValue) { textView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + leftPadding), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); subtitleView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + leftPadding), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); valueTextView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(103 + leftPadding) - textView.getTextWidth(), LocaleController.isRTL ? MeasureSpec.AT_MOST : MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); + valueSpoilersTextView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(103 + leftPadding) - textView.getTextWidth(), LocaleController.isRTL ? MeasureSpec.AT_MOST : MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); } else { valueTextView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(leftPadding), LocaleController.isRTL ? MeasureSpec.AT_MOST : MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); - textView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + leftPadding) - valueTextView.width(), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); - subtitleView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + leftPadding) - valueTextView.width(), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); + valueSpoilersTextView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(leftPadding), LocaleController.isRTL ? MeasureSpec.AT_MOST : MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); + valueWidth = Math.max(valueTextView.width(), valueSpoilersTextView.getTextWidth()); + textView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + leftPadding) - valueWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); + subtitleView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + leftPadding) - valueWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); } if (imageView.getVisibility() == VISIBLE) { imageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); @@ -186,13 +203,14 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto int height = bottom - top; int width = right - left; - int viewTop = (height - valueTextView.getTextHeight()) / 2; + int viewTop = (height - Math.max(valueSpoilersTextView.getTextHeight(), valueTextView.getTextHeight())) / 2; int viewLeft = LocaleController.isRTL ? AndroidUtilities.dp(leftPadding) : 0; if (prioritizeTitleOverValue && !LocaleController.isRTL) { - viewLeft = width - valueTextView.getMeasuredWidth() - AndroidUtilities.dp(leftPadding); + viewLeft = width - valueTextView.getMeasuredWidth() - AndroidUtilities.dp(leftPadding); } valueTextView.layout(viewLeft, viewTop, viewLeft + valueTextView.getMeasuredWidth(), viewTop + valueTextView.getMeasuredHeight()); - + viewLeft = LocaleController.isRTL ? AndroidUtilities.dp(leftPadding) : width - valueSpoilersTextView.getMeasuredWidth() - AndroidUtilities.dp(leftPadding); + valueSpoilersTextView.layout(viewLeft, viewTop, viewLeft + valueSpoilersTextView.getMeasuredWidth(), viewTop + valueSpoilersTextView.getMeasuredHeight()); if (LocaleController.isRTL) { viewLeft = getMeasuredWidth() - textView.getMeasuredWidth() - AndroidUtilities.dp(imageView.getVisibility() == VISIBLE ? offsetFromImage : leftPadding); @@ -245,6 +263,7 @@ public void setText(String text, boolean divider) { valueTextView.setText(null, false); imageView.setVisibility(GONE); valueTextView.setVisibility(GONE); + valueSpoilersTextView.setVisibility(GONE); valueImageView.setVisibility(GONE); needDivider = divider; setWillNotDraw(!needDivider); @@ -258,12 +277,25 @@ public void setTextAndIcon(String text, int resId, boolean divider) { imageView.setImageResource(resId); imageView.setVisibility(VISIBLE); valueTextView.setVisibility(GONE); + valueSpoilersTextView.setVisibility(GONE); valueImageView.setVisibility(GONE); imageView.setPadding(0, AndroidUtilities.dp(7), 0, 0); needDivider = divider; setWillNotDraw(!needDivider); } + public void setTextAndColorfulIcon(String text, int resId, int color, boolean divider) { + imageLeft = 21; + offsetFromImage = 71; + textView.setText(text); + valueTextView.setText(null, false); + setColorfulIcon(color, resId); + valueTextView.setVisibility(GONE); + valueImageView.setVisibility(GONE); + needDivider = divider; + setWillNotDraw(!needDivider); + } + public void setTextAndIcon(String text, Drawable drawable, boolean divider) { offsetFromImage = 68; imageLeft = 18; @@ -301,6 +333,7 @@ public void setTextAndValue(String text, String value, boolean animated, boolean textView.setText(text); valueTextView.setText(value, animated); valueTextView.setVisibility(VISIBLE); + valueSpoilersTextView.setVisibility(GONE); imageView.setVisibility(GONE); valueImageView.setVisibility(GONE); needDivider = divider; @@ -310,6 +343,38 @@ public void setTextAndValue(String text, String value, boolean animated, boolean } } + public void setTextAndValueAndColorfulIcon(String text, CharSequence value, boolean animated, int resId, int color, boolean divider) { + imageLeft = 21; + offsetFromImage = 71; + textView.setText(text); + valueTextView.setText(value, animated); + valueTextView.setVisibility(VISIBLE); + valueSpoilersTextView.setVisibility(GONE); + setColorfulIcon(color, resId); + valueImageView.setVisibility(GONE); + needDivider = divider; + setWillNotDraw(!needDivider); + if (checkBox != null) { + checkBox.setVisibility(GONE); + } + } + + public void setTextAndSpoilersValueAndColorfulIcon(String text, CharSequence value, int resId, int color, boolean divider) { + imageLeft = 21; + offsetFromImage = 71; + textView.setText(text); + valueSpoilersTextView.setVisibility(VISIBLE); + valueSpoilersTextView.setText(value); + valueTextView.setVisibility(GONE); + setColorfulIcon(color, resId); + valueImageView.setVisibility(GONE); + needDivider = divider; + setWillNotDraw(!needDivider); + if (checkBox != null) { + checkBox.setVisibility(GONE); + } + } + public void setTextAndValueAndIcon(String text, String value, int resId, boolean divider) { setTextAndValueAndIcon(text, value, false, resId, divider); } @@ -320,6 +385,7 @@ public void setTextAndValueAndIcon(String text, String value, boolean animated, textView.setText(text); valueTextView.setText(value, animated); valueTextView.setVisibility(VISIBLE); + valueSpoilersTextView.setVisibility(GONE); valueImageView.setVisibility(GONE); imageView.setVisibility(VISIBLE); imageView.setTranslationX(0); @@ -337,11 +403,11 @@ public void setColorfulIcon(int color, int resId) { offsetFromImage = 65; imageView.setVisibility(VISIBLE); imageView.setPadding(AndroidUtilities.dp(2), AndroidUtilities.dp(2), AndroidUtilities.dp(2), AndroidUtilities.dp(2)); - imageView.setTranslationX(AndroidUtilities.dp(-3)); + imageView.setTranslationX(AndroidUtilities.dp(LocaleController.isRTL ? 0 : -3)); imageView.setTranslationY(AndroidUtilities.dp(6)); imageView.setImageResource(resId); imageView.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); - imageView.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(8), color)); + imageView.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(9), color)); } public void setTextAndCheck(String text, boolean checked, boolean divider) { @@ -364,6 +430,7 @@ public void setTextAndCheckAndIcon(String text, boolean checked, int resId, bool offsetFromImage = 71; textView.setText(text); valueTextView.setVisibility(GONE); + valueSpoilersTextView.setVisibility(GONE); valueImageView.setVisibility(GONE); if (checkBox != null) { checkBox.setVisibility(VISIBLE); @@ -381,6 +448,7 @@ public void setTextAndCheckAndIcon(String text, boolean checked, Drawable resDra offsetFromImage = 71; textView.setText(text); valueTextView.setVisibility(GONE); + valueSpoilersTextView.setVisibility(GONE); valueImageView.setVisibility(GONE); if (checkBox != null) { checkBox.setVisibility(VISIBLE); @@ -401,6 +469,7 @@ public void setTextAndValueDrawable(String text, Drawable drawable, boolean divi valueImageView.setVisibility(VISIBLE); valueImageView.setImageDrawable(drawable); valueTextView.setVisibility(GONE); + valueSpoilersTextView.setVisibility(GONE); imageView.setVisibility(GONE); imageView.setPadding(0, AndroidUtilities.dp(7), 0, 0); needDivider = divider; @@ -456,6 +525,9 @@ public void showEnabledAlpha(boolean show) { if (valueTextView != null) { valueTextView.animate().alpha(alpha).start(); } + if (valueSpoilersTextView != null) { + valueSpoilersTextView.animate().alpha(alpha).start(); + } if (valueImageView != null) { valueImageView.animate().alpha(alpha).start(); } @@ -469,6 +541,9 @@ public void showEnabledAlpha(boolean show) { if (valueTextView != null) { valueTextView.setAlpha(alpha); } + if (valueSpoilersTextView != null) { + valueSpoilersTextView.setAlpha(alpha); + } if (valueImageView != null) { valueImageView.setAlpha(alpha); } @@ -542,7 +617,12 @@ protected void dispatchDraw(Canvas canvas) { float alpha = (0.6f + 0.4f * loadingProgress) * drawLoadingProgress; paint.setAlpha((int) (255 * alpha)); int cy = getMeasuredHeight() >> 1; - AndroidUtilities.rectTmp.set(getMeasuredWidth() - AndroidUtilities.dp(11) - AndroidUtilities.dp(loadingSize), cy - AndroidUtilities.dp(3), getMeasuredWidth() - AndroidUtilities.dp(11), cy + AndroidUtilities.dp(3)); + AndroidUtilities.rectTmp.set( + getMeasuredWidth() - AndroidUtilities.dp(21) - AndroidUtilities.dp(loadingSize), + cy - AndroidUtilities.dp(3), + getMeasuredWidth() - AndroidUtilities.dp(21), + cy + AndroidUtilities.dp(3) + ); if (LocaleController.isRTL) { AndroidUtilities.rectTmp.left = getMeasuredWidth() - AndroidUtilities.rectTmp.left; AndroidUtilities.rectTmp.right = getMeasuredWidth() - AndroidUtilities.rectTmp.right; @@ -551,6 +631,7 @@ protected void dispatchDraw(Canvas canvas) { invalidate(); } valueTextView.setAlpha(1f - drawLoadingProgress); + valueSpoilersTextView.setAlpha(1f - drawLoadingProgress); super.dispatchDraw(canvas); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java index adb8dbba6e6..fb65cc52acc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java @@ -13,7 +13,10 @@ import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.Typeface; import android.graphics.drawable.ColorDrawable; import android.text.TextUtils; @@ -24,6 +27,7 @@ import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; +import android.widget.ImageView; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; @@ -32,6 +36,7 @@ import org.telegram.ui.Components.AnimationProperties; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.Switch; import java.util.ArrayList; @@ -53,6 +58,7 @@ public class TextCheckCell extends FrameLayout { private boolean drawCheckRipple; private int padding; private Theme.ResourcesProvider resourcesProvider; + ImageView imageView; public static final Property ANIMATION_PROGRESS = new AnimationProperties.FloatProperty("animationProgress") { @Override @@ -123,6 +129,10 @@ public void setEnabled(boolean enabled) { checkBox.setEnabled(enabled); } + public void setCheckBoxIcon(int icon) { + checkBox.setIcon(icon); + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (isMultiline) { @@ -333,7 +343,11 @@ protected void onDraw(Canvas canvas) { canvas.drawCircle(cx, cy, animatedRad, animationPaint); } if (needDivider) { - canvas.drawLine(LocaleController.isRTL ? 0 : AndroidUtilities.dp(20), getMeasuredHeight() - 1, getMeasuredWidth() - (LocaleController.isRTL ? AndroidUtilities.dp(20) : 0), getMeasuredHeight() - 1, Theme.dividerPaint); + if (imageView != null) { + canvas.drawLine(LocaleController.isRTL ? 0 : padding, getMeasuredHeight() - 1, getMeasuredWidth() - (LocaleController.isRTL ? padding : 0), getMeasuredHeight() - 1, Theme.dividerPaint); + } else { + canvas.drawLine(LocaleController.isRTL ? 0 : AndroidUtilities.dp(20), getMeasuredHeight() - 1, getMeasuredWidth() - (LocaleController.isRTL ? AndroidUtilities.dp(20) : 0), getMeasuredHeight() - 1, Theme.dividerPaint); + } } } @@ -369,4 +383,20 @@ protected void onDetachedFromWindow() { super.onDetachedFromWindow(); attached = false; } + + public void setColorfullIcon(int color, int resId) { + if (imageView == null) { + imageView = new RLottieImageView(getContext()); + imageView.setScaleType(ImageView.ScaleType.CENTER); + addView(imageView, LayoutHelper.createFrame(29, 29, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL, 19, 0, 19, 0)); + padding = AndroidUtilities.dp(65); + ((MarginLayoutParams)textView.getLayoutParams()).leftMargin = LocaleController.isRTL ? 70 : padding; + ((MarginLayoutParams)textView.getLayoutParams()).rightMargin = LocaleController.isRTL ? padding: 70; + } + imageView.setVisibility(VISIBLE); + imageView.setPadding(AndroidUtilities.dp(2), AndroidUtilities.dp(2), AndroidUtilities.dp(2), AndroidUtilities.dp(2)); + imageView.setImageResource(resId); + imageView.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + imageView.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(9), color)); + } } \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell2.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell2.java index 8e9b6546608..5c0ee74d60c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell2.java @@ -10,16 +10,24 @@ import android.content.Context; import android.graphics.Canvas; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; +import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; +import android.widget.LinearLayout; 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.AnimatedTextView; +import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.Switch; @@ -31,6 +39,47 @@ public class TextCheckCell2 extends FrameLayout { private boolean needDivider; private boolean isMultiline; + private LinearLayout collapseViewContainer; + private AnimatedTextView animatedTextView; + private View collapsedArrow; + private View checkBoxClickArea; + + public void setCollapseArrow(String text, boolean collapsed, Runnable onCheckClick) { + if (collapseViewContainer == null) { + collapseViewContainer = new LinearLayout(getContext()); + collapseViewContainer.setOrientation(LinearLayout.HORIZONTAL); + animatedTextView = new AnimatedTextView(getContext(), false, true, true); + animatedTextView.setTextSize(AndroidUtilities.dp(14)); + animatedTextView.getDrawable().setAllowCancel(true); + animatedTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + animatedTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + collapseViewContainer.addView(animatedTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT,20)); + + collapsedArrow = new View(getContext()); + Drawable drawable = getContext().getResources().getDrawable(R.drawable.arrow_more).mutate(); + drawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText), PorterDuff.Mode.MULTIPLY)); + collapsedArrow.setBackground(drawable); + collapseViewContainer.addView(collapsedArrow, LayoutHelper.createLinear(16, 16, Gravity.CENTER_VERTICAL)); + collapseViewContainer.setClipChildren(false); + setClipChildren(false); + addView(collapseViewContainer, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); + + checkBoxClickArea = new View(getContext()) { + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + canvas.drawLine(0, AndroidUtilities.dp(14), 2, getMeasuredHeight()- AndroidUtilities.dp(14), Theme.dividerPaint); + } + }; + checkBoxClickArea.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector), 2)); + addView(checkBoxClickArea, LayoutHelper.createFrame(76, LayoutHelper.MATCH_PARENT, LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT)); + } + animatedTextView.setText(text); + collapsedArrow.animate().cancel(); + collapsedArrow.animate().rotation(collapsed ? 0 : 180).setDuration(340).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + checkBoxClickArea.setOnClickListener(v -> onCheckClick.run()); + } + public TextCheckCell2(Context context) { this(context, null); } @@ -46,7 +95,7 @@ public TextCheckCell2(Context context, Theme.ResourcesProvider resourcesProvider textView.setSingleLine(true); textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); textView.setEllipsize(TextUtils.TruncateAt.END); - addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 64 : 21, 0, LocaleController.isRTL ? 21 : 64, 0)); + addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 64 : 21, 0, LocaleController.isRTL ? 21 : 64, 0)); valueTextView = new TextView(context); valueTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2, resourcesProvider)); @@ -73,10 +122,26 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } } + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (collapseViewContainer != null) { + if (LocaleController.isRTL) { + collapseViewContainer.setTranslationX(textView.getLeft() - collapseViewContainer.getMeasuredWidth() - AndroidUtilities.dp(4)); + } else { + collapseViewContainer.setTranslationX(textView.getRight() + AndroidUtilities.dp(4)); + } + } + } + public void setTextAndCheck(String text, boolean checked, boolean divider) { + setTextAndCheck(text, checked, divider, false); + } + + public void setTextAndCheck(String text, boolean checked, boolean divider, boolean animated) { textView.setText(text); isMultiline = false; - checkBox.setChecked(checked, false); + checkBox.setChecked(checked, animated); needDivider = divider; valueTextView.setVisibility(GONE); LayoutParams layoutParams = (LayoutParams) textView.getLayoutParams(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSettingsCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSettingsCell.java index 35a1f49daa9..c18de2afab8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSettingsCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSettingsCell.java @@ -12,6 +12,7 @@ import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; @@ -42,6 +43,7 @@ public class TextSettingsCell extends FrameLayout { private TextView textView; private AnimatedTextView valueTextView; private ImageView imageView; + private boolean imageViewIsColorful; private BackupImageView valueBackupImageView; private ImageView valueImageView; private boolean needDivider; @@ -94,14 +96,14 @@ public TextSettingsCell(Context context, int padding, Theme.ResourcesProvider re imageView = new RLottieImageView(context); imageView.setScaleType(ImageView.ScaleType.CENTER); - imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteGrayIcon), PorterDuff.Mode.MULTIPLY)); + imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteGrayIcon, resourcesProvider), PorterDuff.Mode.MULTIPLY)); imageView.setVisibility(GONE); addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL, 21, 0, 21, 0)); valueImageView = new ImageView(context); valueImageView.setScaleType(ImageView.ScaleType.CENTER); valueImageView.setVisibility(INVISIBLE); - valueImageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteGrayIcon), PorterDuff.Mode.MULTIPLY)); + valueImageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteGrayIcon, resourcesProvider), PorterDuff.Mode.MULTIPLY)); addView(valueImageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL, padding, 0, padding, 0)); } @@ -120,7 +122,11 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } if (imageView.getVisibility() == VISIBLE) { - imageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST)); + if (imageViewIsColorful) { + imageView.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(28), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(28), MeasureSpec.EXACTLY)); + } else { + imageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST)); + } } if (valueBackupImageView != null) { @@ -213,6 +219,30 @@ public void setTextAndIcon(CharSequence text, int resId, boolean divider) { public void setIcon(int resId) { MarginLayoutParams params = (MarginLayoutParams) textView.getLayoutParams(); + imageViewIsColorful = false; + if (resId == 0) { + imageView.setVisibility(GONE); + if (LocaleController.isRTL) { + params.rightMargin = AndroidUtilities.dp(this.padding); + } else { + params.leftMargin = AndroidUtilities.dp(this.padding); + } + } else { + imageView.setImageResource(resId); + imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteGrayIcon, resourcesProvider), PorterDuff.Mode.MULTIPLY)); + imageView.setBackground(null); + imageView.setVisibility(VISIBLE); + if (LocaleController.isRTL) { + params.rightMargin = AndroidUtilities.dp(71); + } else { + params.leftMargin = AndroidUtilities.dp(71); + } + } + } + + public void setColorfulIcon(int resId, int color) { + MarginLayoutParams params = (MarginLayoutParams) textView.getLayoutParams(); + imageViewIsColorful = true; if (resId == 0) { imageView.setVisibility(GONE); if (LocaleController.isRTL) { @@ -221,7 +251,9 @@ public void setIcon(int resId) { params.leftMargin = AndroidUtilities.dp(this.padding); } } else { + imageView.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(8), color)); imageView.setImageResource(resId); + imageView.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY)); imageView.setVisibility(VISIBLE); if (LocaleController.isRTL) { params.rightMargin = AndroidUtilities.dp(71); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ThemePreviewMessagesCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ThemePreviewMessagesCell.java index fad7ab5a91e..a226d954024 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ThemePreviewMessagesCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ThemePreviewMessagesCell.java @@ -191,6 +191,9 @@ public ThemePreviewMessagesCell(Context context, INavigationLayout layout, int t private GestureDetector gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { @Override public boolean onDoubleTap(MotionEvent e) { + if (MediaDataController.getInstance(currentAccount).getDoubleTapReaction() == null) { + return false; + } boolean added = getMessageObject().selectReaction(ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(MediaDataController.getInstance(currentAccount).getDoubleTapReaction()), false, false); setMessageObject(getMessageObject(), null, false, false); requestLayout(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java index 439d9d39e1a..d451cb0999d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java @@ -54,6 +54,7 @@ import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.Utilities; import org.telegram.messenger.browser.Browser; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; @@ -110,6 +111,7 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC private LinearLayout linearLayout2; private HeaderCell headerCell2; private EditTextBoldCursor editText; + private boolean isGroup; private RLottieDrawable cameraDrawable; @@ -141,23 +143,29 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC private int currentStep; private long chatId; private boolean canCreatePublic = true; + private Boolean forcePublic; private TLRPC.InputFile inputPhoto; private TLRPC.InputFile inputVideo; + private TLRPC.VideoSize inputEmojiMarkup; private String inputVideoPath; private double videoTimestamp; private boolean createAfterUpload; private boolean donePressed; private Integer doneRequestId; + private Utilities.Callback2 onFinishListener; private final static int done_button = 1; public ChannelCreateActivity(Bundle args) { super(args); currentStep = args.getInt("step", 0); + if (args.containsKey("forcePublic")) { + forcePublic = args.getBoolean("forcePublic", false); + } if (currentStep == 0) { avatarDrawable = new AvatarDrawable(); - imageUpdater = new ImageUpdater(true); + imageUpdater = new ImageUpdater(true, ImageUpdater.FOR_TYPE_CHANNEL, true); TLRPC.TL_channels_checkUsername req = new TLRPC.TL_channels_checkUsername(); req.username = "1"; @@ -175,6 +183,10 @@ public ChannelCreateActivity(Bundle args) { } } + public void setOnFinishListener(Utilities.Callback2 onFinishListener) { + this.onFinishListener = onFinishListener; + } + @Override public boolean onFragmentCreate() { NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.chatDidCreated); @@ -343,7 +355,7 @@ public void onItemClick(int id) { createAfterUpload = true; return; } - doneRequestId = MessagesController.getInstance(currentAccount).createChat(nameTextView.getText().toString(), new ArrayList<>(), descriptionTextView.getText().toString(), ChatObject.CHAT_TYPE_CHANNEL, false, null, null, 0, ChannelCreateActivity.this); + doneRequestId = MessagesController.getInstance(currentAccount).createChat(nameTextView.getText().toString(), new ArrayList<>(), descriptionTextView.getText().toString(), ChatObject.CHAT_TYPE_CHANNEL, false, null, null, -1, ChannelCreateActivity.this); } else if (currentStep == 1) { if (!isPrivate) { if (descriptionTextView.length() == 0) { @@ -362,15 +374,30 @@ public void onItemClick(int id) { AndroidUtilities.shakeView(checkTextView); return; } else { - MessagesController.getInstance(currentAccount).updateChannelUserName(ChannelCreateActivity.this, chatId, lastCheckName, null, null); + AndroidUtilities.runOnUIThread(enableDoneLoading, 200); + MessagesController.getInstance(currentAccount).updateChannelUserName(ChannelCreateActivity.this, chatId, lastCheckName, () -> { + updateDoneProgress(false); + if (onFinishListener != null) { + onFinishListener.run(ChannelCreateActivity.this, chatId); + } + }, () -> { + updateDoneProgress(false); + if (onFinishListener != null) { + onFinishListener.run(ChannelCreateActivity.this, chatId); + } + }); } } + } else if (onFinishListener != null) { + onFinishListener.run(ChannelCreateActivity.this, chatId); + } + if (onFinishListener == null) { + Bundle args = new Bundle(); + args.putInt("step", 2); + args.putLong("chatId", chatId); + args.putInt("chatType", ChatObject.CHAT_TYPE_CHANNEL); + presentFragment(new GroupCreateActivity(args), true); } - Bundle args = new Bundle(); - args.putInt("step", 2); - args.putLong("chatId", chatId); - args.putInt("chatType", ChatObject.CHAT_TYPE_CHANNEL); - presentFragment(new GroupCreateActivity(args), true); } } } @@ -545,7 +572,7 @@ public void invalidate(int l, int t, int r, int b) { @Override protected void onDraw(Canvas canvas) { if (avatarImage != null && avatarImage.getImageReceiver().hasNotThumb()) { - paint.setAlpha((int) (0x55 * avatarImage.getImageReceiver().getCurrentAlpha())); + paint.setAlpha((int) (0x55 * avatarImage.getImageReceiver().getCurrentAlpha() * avatarProgressView.getAlpha())); canvas.drawCircle(getMeasuredWidth() / 2.0f, getMeasuredHeight() / 2.0f, getMeasuredWidth() / 2.0f, paint); } } @@ -559,6 +586,7 @@ protected void onDraw(Canvas canvas) { inputPhoto = null; inputVideo = null; inputVideoPath = null; + inputEmojiMarkup = null; videoTimestamp = 0; showAvatarProgress(false, true); avatarImage.setImage(null, null, avatarDrawable, null); @@ -599,8 +627,14 @@ public void invalidate() { avatarEditor.setPadding(AndroidUtilities.dp(0), 0, 0, AndroidUtilities.dp(1)); frameLayout.addView(avatarEditor, LayoutHelper.createFrame(64, 64, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 0 : 15, 12, LocaleController.isRTL ? 15 : 0, 12)); - avatarProgressView = new RadialProgressView(context); - avatarProgressView.setSize(AndroidUtilities.dp(30)); + avatarProgressView = new RadialProgressView(context) { + @Override + public void setAlpha(float alpha) { + super.setAlpha(alpha); + avatarOverlay.invalidate(); + } + }; + avatarProgressView.setSize(AndroidUtilities.dp(30)); avatarProgressView.setProgressColor(0xffffffff); avatarProgressView.setNoProgress(false); frameLayout.addView(avatarProgressView, LayoutHelper.createFrame(64, 64, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 0 : 16, 12, LocaleController.isRTL ? 16 : 0, 12)); @@ -683,14 +717,16 @@ public void afterTextChanged(Editable editable) { linearLayout.setOrientation(LinearLayout.VERTICAL); scrollView.addView(linearLayout, new ScrollView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - actionBar.setTitle(LocaleController.getString("ChannelSettingsTitle", R.string.ChannelSettingsTitle)); + TLRPC.Chat chat = getMessagesController().getChat(chatId); + isGroup = chat != null && (!ChatObject.isChannel(chat) || ChatObject.isMegagroup(chat)); + actionBar.setTitle(isGroup ? LocaleController.getString("GroupSettingsTitle", R.string.GroupSettingsTitle) : LocaleController.getString("ChannelSettingsTitle", R.string.ChannelSettingsTitle)); fragmentView.setTag(Theme.key_windowBackgroundGray); fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); headerCell2 = new HeaderCell(context, 23); headerCell2.setHeight(46); headerCell2.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - headerCell2.setText(LocaleController.getString("ChannelTypeHeader", R.string.ChannelTypeHeader)); + headerCell2.setText(isGroup ? LocaleController.getString("GroupTypeHeader", R.string.GroupTypeHeader) : LocaleController.getString("ChannelTypeHeader", R.string.ChannelTypeHeader)); linearLayout.addView(headerCell2); linearLayout2 = new LinearLayout(context); @@ -700,8 +736,14 @@ public void afterTextChanged(Editable editable) { radioButtonCell1 = new RadioButtonCell(context); radioButtonCell1.setBackgroundDrawable(Theme.getSelectorDrawable(false)); - radioButtonCell1.setTextAndValue(LocaleController.getString("ChannelPublic", R.string.ChannelPublic), LocaleController.getString("ChannelPublicInfo", R.string.ChannelPublicInfo), false, !isPrivate); - linearLayout2.addView(radioButtonCell1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + if (forcePublic != null && !forcePublic) { + isPrivate = true; + } + if (isGroup) { + radioButtonCell1.setTextAndValue(LocaleController.getString("MegaPublic", R.string.MegaPublic), LocaleController.getString("MegaPublicInfo", R.string.MegaPublicInfo), false, !isPrivate); + } else { + radioButtonCell1.setTextAndValue(LocaleController.getString("ChannelPublic", R.string.ChannelPublic), LocaleController.getString("ChannelPublicInfo", R.string.ChannelPublicInfo), false, !isPrivate); + } radioButtonCell1.setOnClickListener(v -> { if (!canCreatePublic) { showPremiumIncreaseLimitDialog(); @@ -713,11 +755,20 @@ public void afterTextChanged(Editable editable) { isPrivate = false; updatePrivatePublic(); }); + if (forcePublic == null || forcePublic) { + linearLayout2.addView(radioButtonCell1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } radioButtonCell2 = new RadioButtonCell(context); radioButtonCell2.setBackgroundDrawable(Theme.getSelectorDrawable(false)); - radioButtonCell2.setTextAndValue(LocaleController.getString("ChannelPrivate", R.string.ChannelPrivate), LocaleController.getString("ChannelPrivateInfo", R.string.ChannelPrivateInfo), false, isPrivate); - linearLayout2.addView(radioButtonCell2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + if (forcePublic != null && forcePublic) { + isPrivate = false; + } + if (isGroup) { + radioButtonCell2.setTextAndValue(LocaleController.getString("MegaPrivate", R.string.MegaPrivate), LocaleController.getString("MegaPrivateInfo", R.string.MegaPrivateInfo), false, isPrivate); + } else { + radioButtonCell2.setTextAndValue(LocaleController.getString("ChannelPrivate", R.string.ChannelPrivate), LocaleController.getString("ChannelPrivateInfo", R.string.ChannelPrivateInfo), false, isPrivate); + } radioButtonCell2.setOnClickListener(v -> { if (isPrivate) { return; @@ -725,6 +776,9 @@ public void afterTextChanged(Editable editable) { isPrivate = true; updatePrivatePublic(); }); + if (forcePublic == null || !forcePublic) { + linearLayout2.addView(radioButtonCell2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } sectionCell = new ShadowSectionCell(context); linearLayout.addView(sectionCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); @@ -923,8 +977,13 @@ private void updatePrivatePublic() { typeInfoCell.setBackgroundDrawable(Theme.getThemedDrawable(typeInfoCell.getContext(), R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); linkContainer.setVisibility(View.VISIBLE); loadingAdminedCell.setVisibility(View.GONE); - typeInfoCell.setText(isPrivate ? LocaleController.getString("ChannelPrivateLinkHelp", R.string.ChannelPrivateLinkHelp) : LocaleController.getString("ChannelUsernameHelp", R.string.ChannelUsernameHelp)); - headerCell.setText(isPrivate ? LocaleController.getString("ChannelInviteLinkTitle", R.string.ChannelInviteLinkTitle) : LocaleController.getString("ChannelLinkTitle", R.string.ChannelLinkTitle)); + if (isGroup) { + typeInfoCell.setText(isPrivate ? LocaleController.getString("MegaPrivateLinkHelp", R.string.MegaPrivateLinkHelp) : LocaleController.getString("MegaUsernameHelp", R.string.MegaUsernameHelp)); + headerCell.setText(isPrivate ? LocaleController.getString("ChannelInviteLinkTitle", R.string.ChannelInviteLinkTitle) : LocaleController.getString("ChannelLinkTitle", R.string.ChannelLinkTitle)); + } else { + typeInfoCell.setText(isPrivate ? LocaleController.getString("ChannelPrivateLinkHelp", R.string.ChannelPrivateLinkHelp) : LocaleController.getString("ChannelUsernameHelp", R.string.ChannelUsernameHelp)); + headerCell.setText(isPrivate ? LocaleController.getString("ChannelInviteLinkTitle", R.string.ChannelInviteLinkTitle) : LocaleController.getString("ChannelLinkTitle", R.string.ChannelLinkTitle)); + } publicContainer.setVisibility(isPrivate ? View.GONE : View.VISIBLE); privateContainer.setVisibility(isPrivate ? View.VISIBLE : View.GONE); linkContainer.setPadding(0, 0, 0, isPrivate ? 0 : AndroidUtilities.dp(7)); @@ -954,11 +1013,12 @@ public void didStartUpload(boolean isVideo) { } @Override - public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile video, double videoStartTimestamp, String videoPath, final TLRPC.PhotoSize bigSize, final TLRPC.PhotoSize smallSize, boolean isVideo) { + public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile video, double videoStartTimestamp, String videoPath, final TLRPC.PhotoSize bigSize, final TLRPC.PhotoSize smallSize, boolean isVideo, TLRPC.VideoSize emojiMarkup) { AndroidUtilities.runOnUIThread(() -> { if (photo != null || video != null) { inputPhoto = photo; inputVideo = video; + inputEmojiMarkup = emojiMarkup; inputVideoPath = videoPath; videoTimestamp = videoStartTimestamp; if (createAfterUpload) { @@ -975,6 +1035,7 @@ public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile vi doneButton.performClick(); } showAvatarProgress(false, true); + avatarEditor.setImageDrawable(null); } else { avatar = smallSize.location; avatarBig = bigSize.location; @@ -1124,10 +1185,15 @@ public void didReceivedNotification(int id, int account, Object... args) { bundle.putInt("step", 1); bundle.putLong("chat_id", chat_id); bundle.putBoolean("canCreatePublic", canCreatePublic); - if (inputPhoto != null || inputVideo != null) { - MessagesController.getInstance(currentAccount).changeChatAvatar(chat_id, null, inputPhoto, inputVideo, videoTimestamp, inputVideoPath, avatar, avatarBig, null); + if (forcePublic != null) { + bundle.putBoolean("forcePublic", forcePublic); + } + if (inputPhoto != null || inputVideo != null || inputEmojiMarkup != null) { + MessagesController.getInstance(currentAccount).changeChatAvatar(chat_id, null, inputPhoto, inputVideo, inputEmojiMarkup, videoTimestamp, inputVideoPath, avatar, avatarBig, null); } - presentFragment(new ChannelCreateActivity(bundle), true); + ChannelCreateActivity activity = new ChannelCreateActivity(bundle); + activity.setOnFinishListener(onFinishListener); + presentFragment(activity, true); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 6258fdeb363..6e6805280ca 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -124,6 +124,7 @@ import org.telegram.messenger.ChatThemeController; import org.telegram.messenger.ContactsController; import org.telegram.messenger.DialogObject; +import org.telegram.messenger.DownloadController; import org.telegram.messenger.Emoji; import org.telegram.messenger.EmojiData; import org.telegram.messenger.FileLoader; @@ -144,6 +145,7 @@ import org.telegram.messenger.SecretChatHelper; import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.TranslateController; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; @@ -258,6 +260,7 @@ import org.telegram.ui.Components.ReactedHeaderView; import org.telegram.ui.Components.ReactedUsersListView; import org.telegram.ui.Components.ReactionTabHolderView; +import org.telegram.ui.Components.Reactions.ChatSelectionReactionMenuOverlay; import org.telegram.ui.Components.Reactions.ReactionsEffectOverlay; import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; import org.telegram.ui.Components.ReactionsContainerLayout; @@ -274,7 +277,8 @@ import org.telegram.ui.Components.TextStyleSpan; import org.telegram.ui.Components.ThemeEditorView; import org.telegram.ui.Components.TranscribeButton; -import org.telegram.ui.Components.TranslateAlert; +import org.telegram.ui.Components.TranslateAlert2; +import org.telegram.ui.Components.TranslateButton; import org.telegram.ui.Components.TrendingStickersAlert; import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.Components.URLSpanBotCommand; @@ -354,6 +358,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private ActionBarMenuItem headerItem; private ActionBarMenuItem editTextItem; private ActionBarMenuItem searchItem; + private ActionBarMenuSubItem translateItem; private ActionBarMenuItem searchIconItem; private ActionBarMenuItem audioCallIconItem; private boolean searchItemVisible; @@ -427,7 +432,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private boolean addToContactsButtonArchive; private TextView reportSpamButton; private TextView restartTopicButton; - private View topViewSeparator1, topViewSeparator2; + private TranslateButton translateButton; + private View topViewSeparator1, topViewSeparator2, topViewSeparator3; private LinkSpanDrawable.LinksTextView emojiStatusSpamHint; private ImageView closeReportSpam; private TextView chatWithAdminTextView; @@ -672,7 +678,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private SparseArray repliesMessagesDict = new SparseArray<>(); private SparseArray> replyMessageOwners = new SparseArray<>(); private HashMap> messagesByDays = new HashMap<>(); - protected ArrayList messages = new ArrayList<>(); + protected ArrayList messages = new ArrayList(); private SparseArray waitingForReplies = new SparseArray<>(); private LongSparseArray> polls = new LongSparseArray<>(); private LongSparseArray groupedMessagesMap = new LongSparseArray<>(); @@ -889,6 +895,8 @@ public void run() { } }; + private ChatSelectionReactionMenuOverlay selectionReactionsOverlay; + private boolean isPauseOnThemePreview; private ChatThemeBottomSheet chatThemeBottomSheet; public ThemeDelegate themeDelegate; @@ -1116,6 +1124,14 @@ public Object get(Object object) { return items; } + public boolean allowSendPhotos() { + if (currentChat != null && !ChatObject.canSendPhoto(currentChat)) { + return false; + } else { + return true; + } + } + private interface ChatActivityDelegate { default void openReplyMessage(int mid) { @@ -1240,6 +1256,8 @@ public void sendButtonPressed(int index, VideoEditedInfo videoEditedInfo, boolea private final static int topic_close = 60; private final static int open_forum = 61; + private final static int translate = 62; + private final static int id_chat_compose_panel = 1000; RecyclerListView.OnItemLongClickListenerExtended onItemLongClickListener = new RecyclerListView.OnItemLongClickListenerExtended() { @@ -1250,7 +1268,7 @@ public boolean onItemClick(View view, int position, float x, float y) { } wasManualScroll = true; boolean result = true; - if (!actionBar.isActionModeShowed() && (reportType < 0 || (view instanceof ChatActionCell && (((ChatActionCell) view).getMessageObject().messageOwner.action instanceof TLRPC.TL_messageActionSetMessagesTTL) || ((ChatActionCell) view).getMessageObject().type == MessageObject.TYPE_SUGGEST_PHOTO))) { + if (!actionBar.isActionModeShowed() && (reportType < 0 || (view instanceof ChatActionCell && (((ChatActionCell) view).getMessageObject().messageOwner.action instanceof TLRPC.TL_messageActionSetMessagesTTL) || ((view instanceof ChatActionCell) && ((ChatActionCell) view).getMessageObject().type == MessageObject.TYPE_SUGGEST_PHOTO)))) { result = createMenu(view, false, true, x, y); } else { boolean outside = false; @@ -1719,6 +1737,10 @@ public boolean onFragmentCreate() { getNotificationCenter().addObserver(this, NotificationCenter.chatAvailableReactionsUpdated); getNotificationCenter().addObserver(this, NotificationCenter.dialogsUnreadReactionsCounterChanged); getNotificationCenter().addObserver(this, NotificationCenter.groupStickersDidLoad); + getNotificationCenter().addObserver(this, NotificationCenter.dialogTranslate); + getNotificationCenter().addObserver(this, NotificationCenter.dialogIsTranslatable); + getNotificationCenter().addObserver(this, NotificationCenter.messageTranslated); + getNotificationCenter().addObserver(this, NotificationCenter.messageTranslating); super.onFragmentCreate(); @@ -1951,6 +1973,15 @@ public int getOtherSameChatsDiff() { return i - cur; } + @Override + public void onBeginSlide() { + super.onBeginSlide(); + + if (selectionReactionsOverlay != null && selectionReactionsOverlay.isVisible()) { + selectionReactionsOverlay.setHiddenByScroll(true); + } + } + @Override public void onFragmentDestroy() { super.onFragmentDestroy(); @@ -2050,6 +2081,10 @@ public void onFragmentDestroy() { getNotificationCenter().removeObserver(this, NotificationCenter.didLoadSendAsPeers); getNotificationCenter().removeObserver(this, NotificationCenter.dialogsUnreadReactionsCounterChanged); getNotificationCenter().removeObserver(this, NotificationCenter.groupStickersDidLoad); + getNotificationCenter().removeObserver(this, NotificationCenter.dialogTranslate); + getNotificationCenter().removeObserver(this, NotificationCenter.dialogIsTranslatable); + getNotificationCenter().removeObserver(this, NotificationCenter.messageTranslated); + getNotificationCenter().removeObserver(this, NotificationCenter.messageTranslating); if (currentEncryptedChat != null) { getNotificationCenter().removeObserver(this, NotificationCenter.didVerifyMessagesStickers); } @@ -2378,6 +2413,11 @@ public void run(boolean revoke) { getSendMessagesHelper().sendMessage("/settings", dialog_id, null, null, null, false, null, null, null, true, 0, null, false); } else if (id == search) { openSearchWithText(null); + } else if (id == translate) { + getMessagesController().getTranslateController().setHideTranslateDialog(getDialogId(), false, true); + if (!getMessagesController().getTranslateController().toggleTranslatingDialog(getDialogId(), true)) { + updateTopPanel(true); + } } else if (id == call || id == video_call) { if (currentUser != null && getParentActivity() != null) { VoIPHelper.startCall(currentUser, id == video_call, userInfo != null && userInfo.video_calls_available, getParentActivity(), getMessagesController().getUserFull(currentUser.id), getAccountInstance()); @@ -2613,7 +2653,7 @@ public void onSearchCollapse() { if (audioCallIconItem != null && showAudioCallAsIcon) { audioCallIconItem.setVisibility(View.GONE); } - } else if (chatActivityEnterView.hasText() && TextUtils.isEmpty(chatActivityEnterView.getSlowModeTimer()) && (currentChat == null || ChatObject.canSendMessages(currentChat))) { + } else if (chatActivityEnterView.hasText() && TextUtils.isEmpty(chatActivityEnterView.getSlowModeTimer()) && (currentChat == null || ChatObject.canSendPlain(currentChat))) { if (headerItem != null) { headerItem.setVisibility(View.GONE); } @@ -2725,6 +2765,25 @@ public boolean forceShowClear() { searchItemVisible = false; } + if (chatMode == 0 && (threadMessageId == 0 || isTopic) && !UserObject.isReplyUser(currentUser) && reportType < 0) { + TLRPC.UserFull userFull = null; + if (currentUser != null) { + audioCallIconItem = menu.addItem(call, R.drawable.ic_call, themeDelegate); + audioCallIconItem.setContentDescription(LocaleController.getString("Call", R.string.Call)); + userFull = getMessagesController().getUserFull(currentUser.id); + if (userFull != null && userFull.phone_calls_available) { + showAudioCallAsIcon = !inPreviewMode; + audioCallIconItem.setVisibility(View.VISIBLE); + } else { + showAudioCallAsIcon = false; + audioCallIconItem.setVisibility(View.GONE); + } + if (avatarContainer != null) { + avatarContainer.setTitleExpand(showAudioCallAsIcon); + } + } + } + editTextItem = menu.addItem(0, R.drawable.ic_ab_other, themeDelegate); editTextItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); editTextItem.setTag(null); @@ -2758,19 +2817,7 @@ public boolean forceShowClear() { if (chatMode == 0 && (threadMessageId == 0 || isTopic) && !UserObject.isReplyUser(currentUser) && reportType < 0) { TLRPC.UserFull userFull = null; if (currentUser != null) { - audioCallIconItem = menu.addItem(call, R.drawable.ic_call, themeDelegate); - audioCallIconItem.setContentDescription(LocaleController.getString("Call", R.string.Call)); userFull = getMessagesController().getUserFull(currentUser.id); - if (userFull != null && userFull.phone_calls_available) { - showAudioCallAsIcon = !inPreviewMode; - audioCallIconItem.setVisibility(View.VISIBLE); - } else { - showAudioCallAsIcon = false; - audioCallIconItem.setVisibility(View.GONE); - } - if (avatarContainer != null) { - avatarContainer.setTitleExpand(showAudioCallAsIcon); - } } headerItem = menu.addItem(0, R.drawable.ic_ab_other, themeDelegate); headerItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); @@ -2868,6 +2915,8 @@ public void toggleMute() { if (searchItem != null) { headerItem.addSubItem(search, R.drawable.msg_search, LocaleController.getString("Search", R.string.Search), themeDelegate); } + translateItem = headerItem.addSubItem(translate, R.drawable.msg_translate, LocaleController.getString("TranslateMessage", R.string.TranslateMessage), themeDelegate); + updateTranslateItemVisibility(); if (currentChat != null && !currentChat.creator && !ChatObject.hasAdminRights(currentChat)) { headerItem.addSubItem(report, R.drawable.msg_report, LocaleController.getString("ReportChat", R.string.ReportChat), themeDelegate); } @@ -5893,6 +5942,9 @@ public void invalidate() { invalidated = true; super.invalidate(); contentView.invalidateBlur(); + if (selectionReactionsOverlay != null && selectionReactionsOverlay.isVisible()) { + selectionReactionsOverlay.invalidatePosition(); + } } @Override @@ -6293,6 +6345,10 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 512); } NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopSpoilers); + + if (selectionReactionsOverlay != null && selectionReactionsOverlay.isVisible()) { + selectionReactionsOverlay.setHiddenByScroll(true); + } } } @@ -6381,9 +6437,14 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { textSelectionHelper.onParentScrolled(); emojiAnimationsOverlay.onScrolled(dy); ReactionsEffectOverlay.onScrolled(dy); + + checkTranslation(false); } }); + selectionReactionsOverlay = new ChatSelectionReactionMenuOverlay(this, context); + contentView.addView(selectionReactionsOverlay, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + animatingImageView = new ClippingImageView(context); animatingImageView.setVisibility(View.GONE); contentView.addView(animatingImageView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); @@ -6838,7 +6899,7 @@ protected void dispatchDraw(Canvas canvas) { emojiStatusSpamHint.setGravity(Gravity.CENTER); emojiStatusSpamHint.setVisibility(View.GONE); emojiStatusSpamHint.setLinkTextColor(getThemedColor(Theme.key_windowBackgroundWhiteLinkText)); - topChatPanelView.addView(emojiStatusSpamHint, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 25, 56, 25, 1)); + topChatPanelView.addView(emojiStatusSpamHint, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 25, 0, 25, 1)); topViewSeparator1 = new View(context); topViewSeparator1.setVisibility(View.GONE); @@ -6849,6 +6910,10 @@ protected void dispatchDraw(Canvas canvas) { topViewSeparator2.setVisibility(View.GONE); topViewSeparator2.setBackgroundColor(getThemedColor(Theme.key_divider)); topChatPanelView.addView(topViewSeparator2, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1f / AndroidUtilities.density, Gravity.LEFT | Gravity.TOP, 10, 50, 10, 1)); + topViewSeparator3 = new View(context); + topViewSeparator3.setVisibility(View.GONE); + topViewSeparator3.setBackgroundColor(getThemedColor(Theme.key_divider)); + topChatPanelView.addView(topViewSeparator3, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1f / AndroidUtilities.density, Gravity.LEFT | Gravity.BOTTOM, 0, 0, 0, 38)); addToContactsButton = new TextView(context); addToContactsButton.setTextColor(getThemedColor(Theme.key_chat_addContact)); @@ -6933,6 +6998,15 @@ protected void dispatchDraw(Canvas canvas) { updateTopPanel(true); }); + translateButton = new TranslateButton(context, this, themeDelegate) { + @Override + protected void onButtonClick() { + getMessagesController().getTranslateController().toggleTranslatingDialog(getDialogId()); + updateTopPanel(true); + } + }; + topChatPanelView.addView(translateButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.LEFT | Gravity.BOTTOM, 0, 0, 0, 2)); + closeReportSpam = new ImageView(context); closeReportSpam.setImageResource(R.drawable.miniplayer_close); closeReportSpam.setContentDescription(LocaleController.getString("Close", R.string.Close)); @@ -7149,7 +7223,7 @@ public void sendSticker(TLRPC.Document sticker, String query, Object parent, boo } @Override - public boolean needSend() { + public boolean needSend(int contentType) { return true; } @@ -8844,6 +8918,7 @@ protected void onSend(int type, String message) { } updatePinnedMessageView(true); updateVisibleRows(); + updateSelectedMessageReactions(); }); bottomMessagesActionContainer.addView(replyButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); @@ -9123,15 +9198,29 @@ private void playReactionAnimation(Integer messageId) { } private void dimBehindView(View view, boolean enable) { - scrimView = view; + setScrimView(view); dimBehindView(enable ? 0.2f : 0, view != reactionsMentiondownButton && view != mentiondownButton); } private void dimBehindView(View view, float value) { - scrimView = view; + setScrimView(view); dimBehindView(value, view != reactionsMentiondownButton && view != mentiondownButton); } + private void setScrimView(View scrimView) { + if (this.scrimView == scrimView) { + return; + } + if (this.scrimView != null) { + if (this.scrimView instanceof ChatActionCell) { + ((ChatActionCell) this.scrimView).setInvalidateWithParent(null); + } + } + this.scrimView = scrimView; + if (this.scrimView instanceof ChatActionCell) { + ((ChatActionCell) this.scrimView).setInvalidateWithParent(fragmentView); + } + } public void dimBehindView(boolean enable) { dimBehindView(enable ? 0.2f : 0, true); } @@ -9186,7 +9275,7 @@ private void dimBehindView(float value, boolean hidePagedownButtons) { @Override public void onAnimationEnd(Animator animation) { if (!enable) { - scrimView = null; + setScrimView(null); scrimViewReaction = null; contentView.invalidate(); chatListView.invalidate(); @@ -9194,7 +9283,7 @@ public void onAnimationEnd(Animator animation) { } }); if (scrimView != null && scrimViewAlpha <= 0f) { - scrimView = null; + setScrimView(null); } scrimAnimatorSet.start(); } @@ -9350,7 +9439,7 @@ protected void selectAnotherChat() { } Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); args.putInt("hasPoll", hasPoll); args.putBoolean("hasInvoice", hasInvoice); args.putInt("messagesCount", forwardingMessages.messages.size()); @@ -9470,6 +9559,13 @@ private void searchUserMessages(TLRPC.User user, TLRPC.Chat chat) { getMediaDataController().searchMessagesInChat("", dialog_id, mergeDialogId, classGuid, 0, threadMessageId, searchingUserMessages, searchingChatMessages); } + private void updateTranslateItemVisibility() { + if (translateItem == null) { + return; + } + translateItem.setVisibility(getMessagesController().getTranslateController().isTranslateDialogHidden(getDialogId()) && getMessagesController().getTranslateController().isDialogTranslatable(getDialogId()) ? View.VISIBLE : View.GONE); + } + private Animator infoTopViewAnimator; private void updateInfoTopView(boolean animated) { @@ -9848,7 +9944,7 @@ private void updateChatListViewTopPadding() { if (!invalidateChatListViewTopPadding || chatListView == null || (fixedKeyboardHeight > 0 && searchExpandProgress == 0)) { return; } - float topPanelViewH = Math.max(0, AndroidUtilities.dp(48) + topChatPanelViewOffset); + float topPanelViewH = Math.max(0, (topChatPanelView.getLayoutParams().height - AndroidUtilities.dp(2)) + topChatPanelViewOffset); float pinnedViewH = 0; if (pinnedMessageView != null && pinnedMessageView.getVisibility() == View.VISIBLE) { pinnedViewH = Math.max(0, AndroidUtilities.dp(48) + pinnedMessageEnterOffset); @@ -9967,7 +10063,8 @@ private void invalidateChatListViewTopPadding() { } } - float translation = contentPanTranslation + contentPaddingTop + Math.max(0, AndroidUtilities.dp(48) + topChatPanelViewOffset); + int topPanelHeight = (topChatPanelView == null || topChatPanelView.getLayoutParams() == null ? AndroidUtilities.dp(50) : topChatPanelView.getLayoutParams().height) - AndroidUtilities.dp(2); + float translation = contentPanTranslation + contentPaddingTop + Math.max(0, topPanelHeight + topChatPanelViewOffset); if (pinnedMessageView != null) { translation += pinnedMessageEnterOffset; pinnedMessageView.setTranslationY(translation); @@ -10173,6 +10270,10 @@ private void setPagedownLoading(boolean loading, boolean animated) { public void onAnimationEnd(Animator animation) { if (loading) { pagedownButtonArrow.setVisibility(View.GONE); + if (!startedLoading[0]) { + pagedownButtonLoadingDrawable.reset(); + pagedownButtonLoading.setVisibility(View.VISIBLE); + } } else { pagedownButtonLoading.setVisibility(View.GONE); } @@ -10260,9 +10361,12 @@ private void openForward(boolean fromActionBar) { break; } } + if (selectionReactionsOverlay != null && selectionReactionsOverlay.isVisible()) { + selectionReactionsOverlay.setHiddenByScroll(true); + } Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); args.putInt("messagesCount", canForwardMessagesCount); args.putInt("hasPoll", hasPoll); args.putBoolean("hasInvoice", hasInvoice); @@ -10974,6 +11078,16 @@ private void showMediaBannedHint() { if (userInfo != null && userInfo.voice_messages_forbidden) { mediaBanTooltip.setText(AndroidUtilities.replaceTags(LocaleController.formatString(chatActivityEnterView.isInVideoMode() ? R.string.VideoMessagesRestrictedByPrivacy : R.string.VoiceMessagesRestrictedByPrivacy, currentUser.first_name))); + } else if (!ChatObject.canSendVoice(currentChat) && !ChatObject.canSendVoice(currentChat)) { + if (chatActivityEnterView.isInVideoMode()) { + mediaBanTooltip.setText(ChatObject.getRestrictedErrorText(currentChat, ChatObject.ACTION_SEND_ROUND)); + } else { + mediaBanTooltip.setText(ChatObject.getRestrictedErrorText(currentChat, ChatObject.ACTION_SEND_VOICE)); + } + } else if (ChatObject.isActionBannedByDefault(currentChat, ChatObject.ACTION_SEND_VOICE)) { + mediaBanTooltip.setText(LocaleController.getString("GlobalAttachVoiceRestricted", R.string.GlobalAttachVoiceRestricted)); + } else if (ChatObject.isActionBannedByDefault(currentChat, ChatObject.ACTION_SEND_ROUND)) { + mediaBanTooltip.setText(LocaleController.getString("GlobalAttachRoundRestricted", R.string.GlobalAttachRoundRestricted)); } else if (ChatObject.isActionBannedByDefault(currentChat, ChatObject.ACTION_SEND_MEDIA)) { mediaBanTooltip.setText(LocaleController.getString("GlobalAttachMediaRestricted", R.string.GlobalAttachMediaRestricted)); } else { @@ -12093,7 +12207,6 @@ public void showFieldPanel(boolean show, MessageObject messageObjectToReply, Mes } } } else if (messageObjectToReply != null) { - forwardingMessages = null; editingMessageObject = null; replyingMessageObject = messageObjectToReply; chatActivityEnterView.setReplyingMessageObject(messageObjectToReply); @@ -13039,7 +13152,7 @@ public void updateMessagesVisiblePart(boolean inLayout) { } } getMessagesController().addToPollsQueue(dialog_id, pollsToCheck); - if (maxAdapterPosition >= 0 && minAdapterPosition >= 0) { + if (!isInScheduleMode() && maxAdapterPosition >= 0 && minAdapterPosition >= 0) { int from = minAdapterPosition - chatAdapter.messagesStartRow - 10; int to = maxAdapterPosition - chatAdapter.messagesStartRow + 10; if (from < 0) { @@ -13518,7 +13631,7 @@ public void scrollToMessageId(int id, int fromMessageId, boolean select, int loa if (inCaseLoading != null) { inCaseLoading.run(); - } else { + } else if (forceNextPinnedMessageId == 0) { progressDialog = new AlertDialog(getParentActivity(), AlertDialog.ALERT_TYPE_SPINNER, themeDelegate); progressDialog.setOnShowListener(dialogInterface -> showPinnedProgress(false)); progressDialog.setOnCancelListener(postponedScrollCancelListener); @@ -13716,7 +13829,7 @@ private void updateSecretStatus() { return; } boolean hideKeyboard = false; - if (currentChat != null && !ChatObject.canSendMessages(currentChat) && !currentChat.gigagroup && (!ChatObject.isChannel(currentChat) || currentChat.megagroup)) { + if (currentChat != null && !ChatObject.canSendMessages(currentChat) && !ChatObject.canSendAnyMedia(currentChat) && !currentChat.gigagroup && (!ChatObject.isChannel(currentChat) || currentChat.megagroup)) { if (currentChat.default_banned_rights != null && currentChat.default_banned_rights.send_messages) { bottomOverlayText.setText(LocaleController.getString("GlobalSendMessageRestricted", R.string.GlobalSendMessageRestricted)); } else if (AndroidUtilities.isBannedForever(currentChat.banned_rights)) { @@ -14359,6 +14472,20 @@ public void onAnimationCancel(Animator animation) { } } } + updateSelectedMessageReactions(); + } + + private void updateSelectedMessageReactions() { + List selected = new ArrayList<>(); + SparseArray objs = selectedMessagesIds[0]; + for (int i = 0; i < objs.size(); i++) { + selected.add(objs.valueAt(i)); + } + objs = selectedMessagesIds[1]; + for (int i = 0; i < objs.size(); i++) { + selected.add(objs.valueAt(i)); + } + selectionReactionsOverlay.setSelectedMessages(selected); } private void processRowSelect(View view, boolean outside, float touchX, float touchY) { @@ -15036,6 +15163,9 @@ private boolean isSkeletonVisible() { if (wallpaper instanceof MotionBackgroundDrawable) { MotionBackgroundDrawable motion = (MotionBackgroundDrawable) wallpaper; if (((MotionBackgroundDrawable) wallpaper).isIndeterminateAnimation() != rotate) { + if (!rotate) { + motion.generateNextGradient(); + } motion.setIndeterminateAnimation(rotate); motion.setIndeterminateSpeedScale(rotate ? 1.5f : 1f); motion.updateAnimation(true); @@ -15695,6 +15825,7 @@ public void didReceivedNotification(int id, int account, final Object... args) { } else { obj.stableId = lastStableId++; } + getMessagesController().getTranslateController().checkTranslation(obj, false); if (load_type == 1) { messages.add(0, obj); } else { @@ -17194,6 +17325,9 @@ public void didReceivedNotification(int id, int account, final Object... args) { } }); } else if (id == NotificationCenter.didUpdateReactions) { + if (isInScheduleMode()) { + return; + } long did = (Long) args[0]; doOnIdle(() -> { int msgId = (Integer) args[1]; @@ -18080,9 +18214,290 @@ public void didReceivedNotification(int id, int account, final Object... args) { avatarContainer.updateSubtitle(); } } + } else if (id == NotificationCenter.dialogTranslate) { + final long dialogId = (long) args[0]; + if (getDialogId() != dialogId) { + return; + } + + updateTopPanel(true); + if (chatListView != null && chatAdapter != null) { + boolean updatedPinned = false; + ArrayList groupChecked = new ArrayList<>(); + for (int i = 0; i < chatListView.getChildCount(); ++i) { + View child = chatListView.getChildAt(i); + if (child instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) child; + MessageObject messageObject = cell.getMessageObject(); + boolean update = false; + if (messageObject != null && messageObject.updateTranslation(false)) { + update = true; + + MessageObject pinnedMessageObject = pinnedMessageObjects.get(messageObject.getId()); + if (pinnedMessageObject != null) { + pinnedMessageObject.messageOwner.translatedText = messageObject.messageOwner.translatedText; + pinnedMessageObject.messageOwner.translatedToLanguage = messageObject.messageOwner.translatedToLanguage; + if (pinnedMessageObject.updateTranslation(currentPinnedMessageId == messageObject.getId())) { + updatedPinned = true; + } + } + } + MessageObject.GroupedMessages group = groupedMessagesMap.get(messageObject.getGroupId()); + if (group != null && !groupChecked.contains(group.groupId)) { + for (int j = 0; j < group.messages.size(); ++j) { + MessageObject groupMessageObject = group.messages.get(j); + if (groupMessageObject != null && groupMessageObject.updateTranslation(false)) { + update = true; + } + } + groupChecked.add(group.groupId); + } + if (messageObject != null && messageObject.replyMessageObject != null) { + MessageObject translatedReplyMessageObject = getMessagesController().getTranslateController().findReplyMessageObject(dialogId, messageObject.replyMessageObject.getId()); + if (translatedReplyMessageObject != null) { + messageObject.replyMessageObject.messageOwner.translatedText = translatedReplyMessageObject.messageOwner.translatedText; + messageObject.replyMessageObject.messageOwner.translatedToLanguage = translatedReplyMessageObject.messageOwner.translatedToLanguage; + if (messageObject.replyMessageObject.updateTranslation(true)) { + update = true; + } + } + } + + if (update) { + messageObject.forceUpdate = true; + cell.setMessageObject(messageObject, cell.getCurrentMessagesGroup(), cell.isPinnedBottom(), cell.isPinnedTop()); + if (group != null) { + if (chatListItemAnimator != null) { + chatListItemAnimator.groupWillChanged(group); + } + for (int j = 0; j < group.messages.size(); j++) { + group.messages.get(j).forceUpdate = true; + } + chatAdapter.notifyDataSetChanged(true); + } else { + chatAdapter.updateRowAtPosition(chatListView.getChildAdapterPosition(child)); + } + } else { + cell.invalidate(); + } + } + } + if (!updatedPinned) { + for (MessageObject pinnedMessageObject : pinnedMessageObjects.values()) { + if (pinnedMessageObject != null && pinnedMessageObject.updateTranslation(currentPinnedMessageId == pinnedMessageObject.getId())) { + updatedPinned = true; + } + } + } + if (updatedPinned) { + updatePinnedMessageView(true, 1); + } + } + checkTranslation(true); + updateTranslateItemVisibility(); + } else if (id == NotificationCenter.messageTranslated) { + MessageObject messageObject = (MessageObject) args[0]; + if (getDialogId() != messageObject.getDialogId()) { + return; + } + updateMessageTranslation(messageObject); + if (args.length > 1 && (boolean) args[1]) { + checkTranslation(true); + } + } else if (id == NotificationCenter.messageTranslating) { + MessageObject messageObject = (MessageObject) args[0]; + if (getDialogId() != messageObject.getDialogId()) { + return; + } + if (chatListView == null || chatAdapter == null) { + return; + } + for (int i = 0; i < chatListView.getChildCount(); ++i) { + View child = chatListView.getChildAt(i); + if (child instanceof ChatMessageCell) { + child.invalidate(); + } + } + } else if (id == NotificationCenter.dialogIsTranslatable) { + final long dialogId = (long) args[0]; + if (getDialogId() != dialogId) { + return; + } + + updateTopPanel(true); + updateTranslateItemVisibility(); + } + } + + private boolean updateMessageTranslation(MessageObject messageObject) { + if (messageObject == null || messageObject.messageOwner == null) { + return false; + } + boolean updated = false; + for (MessageObject pinnedMessageObject : pinnedMessageObjects.values()) { + if (pinnedMessageObject != null && pinnedMessageObject.getId() == messageObject.getId()) { + pinnedMessageObject.messageOwner.translatedText = messageObject.messageOwner.translatedText; + pinnedMessageObject.messageOwner.translatedToLanguage = messageObject.messageOwner.translatedToLanguage; + if (pinnedMessageObject.updateTranslation(true)) { + updatePinnedMessageView(true, 1); + updated = true; + } + } + } + if (chatListView == null) { + return updated; + } + ArrayList groupChecked = new ArrayList<>(); + for (int i = 0; i < chatListView.getChildCount(); ++i) { + View child = chatListView.getChildAt(i); + if (child instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) child; + MessageObject cellMessageObject = cell.getMessageObject(); + if (cellMessageObject == null) { + continue; + } + boolean update = false; + if (cellMessageObject.getId() == messageObject.getId()) { + cellMessageObject.messageOwner.translatedText = messageObject.messageOwner.translatedText; + cellMessageObject.messageOwner.translatedToLanguage = messageObject.messageOwner.translatedToLanguage; + if (cellMessageObject.updateTranslation(false)) { + update = true; + ArrayList dependentMessages = replyMessageOwners.get(cellMessageObject.getId()); + if (dependentMessages != null) { + updateMessagesReplyTranslation(dependentMessages, messageObject); + } + } + } + MessageObject.GroupedMessages group = groupedMessagesMap.get(messageObject.getGroupId()); + if (group != null && !groupChecked.contains(group.groupId)) { + for (int j = 0; j < group.messages.size(); ++j) { + MessageObject groupMessageObject = group.messages.get(j); + if (groupMessageObject != null && groupMessageObject.updateTranslation(false)) { + update = true; + } + } + groupChecked.add(group.groupId); + } + if (cellMessageObject.replyMessageObject != null && cellMessageObject.replyMessageObject.getId() == messageObject.getId() && cellMessageObject.replyMessageObject.getDialogId() == messageObject.getDialogId()) { + cellMessageObject.replyMessageObject.messageOwner.translatedText = messageObject.messageOwner.translatedText; + cellMessageObject.replyMessageObject.messageOwner.translatedToLanguage = messageObject.messageOwner.translatedToLanguage; + if (cellMessageObject.replyMessageObject.updateTranslation(false)) { + update = true; + } + } + if (update) { + cellMessageObject.forceUpdate = true; + cell.setMessageObject(cellMessageObject, cell.getCurrentMessagesGroup(), cell.isPinnedBottom(), cell.isPinnedTop()); + if (group != null) { + if (chatListItemAnimator != null) { + chatListItemAnimator.groupWillChanged(group); + } + for (int j = 0; j < group.messages.size(); j++) { + group.messages.get(j).forceUpdate = true; + } + chatAdapter.notifyDataSetChanged(true); + } else { + chatAdapter.updateRowAtPosition(chatListView.getChildAdapterPosition(child)); + } + updated = true; + } + } + } + return updated; + } + + + private boolean updateMessagesReplyTranslation(ArrayList messageIds, MessageObject translatedReplyMessageObject) { + boolean updated = false; + for (int i = 0; i < chatListView.getChildCount(); ++i) { + View child = chatListView.getChildAt(i); + if (child instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) child; + MessageObject cellMessageObject = cell.getMessageObject(); + boolean update = false; + if (cellMessageObject != null && messageIds.contains(cellMessageObject.getId()) && cellMessageObject.replyMessageObject != null && cellMessageObject.replyMessageObject.getId() == translatedReplyMessageObject.getId()) { + cellMessageObject.replyMessageObject.messageOwner.translatedText = translatedReplyMessageObject.messageOwner.translatedText; + cellMessageObject.replyMessageObject.messageOwner.translatedToLanguage = translatedReplyMessageObject.messageOwner.translatedToLanguage; + if (cellMessageObject.replyMessageObject.updateTranslation(false)) { + update = true; + } + } + if (update) { + cellMessageObject.forceUpdate = true; + cell.setMessageObject(cellMessageObject, cell.getCurrentMessagesGroup(), cell.isPinnedBottom(), cell.isPinnedTop()); + chatAdapter.updateRowAtPosition(chatListView.getChildAdapterPosition(child)); + updated = true; + } + } } + return updated; } + private long lastTranslationCheck; + private void checkTranslation(boolean force) { + if (System.currentTimeMillis() - lastTranslationCheck > 1000) { + force = true; + } + AndroidUtilities.cancelRunOnUIThread(checkTranslationRunnable); + AndroidUtilities.runOnUIThread(checkTranslationRunnable, force ? 0 : 150); + } + private Runnable checkTranslationRunnable = () -> { + lastTranslationCheck = System.currentTimeMillis(); + if (chatListView != null && chatAdapter != null) { + int minId = Integer.MAX_VALUE, maxId = Integer.MIN_VALUE; + for (int i = 0; i < chatListView.getChildCount(); ++i) { + View child = chatListView.getChildAt(i); + if (child instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) child; + if (cell.getCurrentMessagesGroup() != null) { + for (int j = 0; j < cell.getCurrentMessagesGroup().messages.size(); ++j) { + final int mid = cell.getCurrentMessagesGroup().messages.get(j).getId(); + minId = Math.min(minId, mid); + maxId = Math.max(maxId, mid); + } + } else if (cell.getMessageObject() != null) { + final int mid = cell.getMessageObject().getId(); + minId = Math.min(minId, mid); + maxId = Math.max(maxId, mid); + } + } + } + + if (minId <= maxId) { + ArrayList groupsChecked = new ArrayList<>(); + for (int i = 0; i < messages.size(); ++i) { + MessageObject messageObject = messages.get(i); + MessageObject.GroupedMessages group = groupedMessagesMap.get(messageObject.getGroupId()); + if (group != null) { + if (!groupsChecked.contains(group.groupId)) { + for (int j = 0; j < group.messages.size(); ++j) { + MessageObject messageObject1 = group.messages.get(j); + if (messageObject1 != null) { + final int mid = messageObject1.getId(); + getMessagesController().getTranslateController().checkTranslation( + messageObject1, mid >= minId - 7 && mid <= maxId + 7 + ); + } + } + groupsChecked.add(group.groupId); + } + } else { + final int mid = messageObject.getId(); + getMessagesController().getTranslateController().checkTranslation( + messageObject, mid >= minId - 7 && mid <= maxId + 7 + ); + } + } + } + } + + if (currentPinnedMessageId > 0 && pinnedMessageObjects != null) { + getMessagesController().getTranslateController().checkTranslation(pinnedMessageObjects.get(currentPinnedMessageId), true); + } + + updateTranslateItemVisibility(); + }; + private void checkSecretMessageForLocation(MessageObject messageObject) { if (messageObject.type != MessageObject.TYPE_GEO || locationAlertShown || SharedConfig.isSecretMapPreviewSet()) { return; @@ -18971,6 +19386,7 @@ private void processNewMessages(ArrayList arr) { } } obj.stableId = lastStableId++; + getMessagesController().getTranslateController().checkTranslation(obj, false); messages.add(placeToPaste, obj); if (placeToPaste == 0 && !obj.isSponsored()) { needMoveScrollToLastMessage = true; @@ -19957,6 +20373,7 @@ public void onTransitionAnimationEnd(boolean isOpen, boolean backward) { allowWrite.set(allow); }); + builder.setCustomViewOffset(6); builder.setView(cell); } builder.show(); @@ -20897,6 +21314,7 @@ public void onAnimationCancel(Animator animation) { } } CharSequence pinnedText = null; + pinnedMessageObject.updateTranslation(false); if (pinnedMessageObject.type == MessageObject.TYPE_MUSIC) { pinnedText = String.format("%s - %s", pinnedMessageObject.getMusicAuthor(), pinnedMessageObject.getMusicTitle()); } else if (pinnedMessageObject.type == MessageObject.TYPE_POLL) { @@ -20915,22 +21333,22 @@ public void onAnimationCancel(Animator animation) { mess = mess.substring(0, 150); } mess = mess.replace('\n', ' '); - CharSequence message = mess; + pinnedText = mess; + pinnedText = Emoji.replaceEmoji(pinnedText, messageTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false); if (pinnedMessageObject != null && pinnedMessageObject.messageOwner != null) { - message = MessageObject.replaceAnimatedEmoji(mess, pinnedMessageObject.messageOwner.entities, messageTextView.getPaint().getFontMetricsInt()); + pinnedText = pinnedMessageObject.replaceAnimatedEmoji(pinnedText, messageTextView.getPaint().getFontMetricsInt()); } - pinnedText = Emoji.replaceEmoji(message, messageTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false); } else if (pinnedMessageObject.messageText != null) { String mess = pinnedMessageObject.messageText.toString(); if (mess.length() > 150) { mess = mess.substring(0, 150); } mess = mess.replace('\n', ' '); - CharSequence message = mess; + pinnedText = mess; + pinnedText = Emoji.replaceEmoji(pinnedText, messageTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false); if (pinnedMessageObject != null && pinnedMessageObject.messageOwner != null) { - message = MessageObject.replaceAnimatedEmoji(mess, pinnedMessageObject.messageOwner.entities, messageTextView.getPaint().getFontMetricsInt()); + pinnedText = pinnedMessageObject.replaceAnimatedEmoji(pinnedText, messageTextView.getPaint().getFontMetricsInt()); } - pinnedText = Emoji.replaceEmoji(message, messageTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false); } if (pinnedText != null) { if (pinnedText instanceof Spannable) { @@ -21285,9 +21703,11 @@ public TrackingWidthSimpleTextView(Context context) { } private boolean trackWidth = true; + public void setTrackWidth(boolean value) { this.trackWidth = value; } + public boolean getTrackWidth() { return this.trackWidth; } @@ -21335,6 +21755,7 @@ private void updateTopPanel(boolean animated) { boolean showAddMembersToGroup = preferences.getBoolean("dialog_bar_invite" + did, false); TLRPC.EmojiStatus showEmojiStatusReport = currentUser != null && (showReport || showBlock) && (currentUser.emoji_status instanceof TLRPC.TL_emojiStatus || currentUser.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) currentUser.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) ? currentUser.emoji_status : null; boolean showRestartTopic = !isInPreviewMode() && forumTopic != null && forumTopic.closed && !forumTopic.hidden && ChatObject.canManageTopic(currentAccount, currentChat, forumTopic); + boolean showTranslate = getMessagesController().getTranslateController().isDialogTranslatable(getDialogId()) && !getMessagesController().getTranslateController().isTranslateDialogHidden(getDialogId()); if (showRestartTopic) { shownRestartTopic = true; } @@ -21342,13 +21763,17 @@ private void updateTopPanel(boolean animated) { reportSpamButton.setVisibility(showReport || showBlock || showGeo ? View.VISIBLE : View.GONE); boolean showRestartTopic1 = (showRestartTopic || shownRestartTopic) && !(showReport || showBlock || showGeo); restartTopicButton.setVisibility(showRestartTopic1 ? View.VISIBLE : View.GONE); - closeReportSpam.setVisibility(showRestartTopic1 ? View.GONE : View.VISIBLE); + translateButton.setVisibility(showTranslate ? View.VISIBLE : View.GONE); + if (showTranslate) { + translateButton.updateText(); + } + closeReportSpam.setVisibility(showRestartTopic1 || showTranslate && !(showReport || showBlock || showGeo) ? View.GONE : View.VISIBLE); if (!showRestartTopic) { shownRestartTopic = false; } - if (showRestartTopic) { + if (showRestartTopic || showTranslate) { show = true; } @@ -21382,12 +21807,8 @@ public void onClick(View view) { addToContactsButton.setVisibility(View.GONE); chatWithAdminTextView.setText(AndroidUtilities.replaceTags(str)); } else if (showAddMembersToGroup) { - String str = LocaleController.getString("GroupAddMembers", R.string.GroupAddMembers); - if (str != null) { - str = str.toUpperCase(); - } addToContactsButton.setVisibility(View.VISIBLE); - addToContactsButton.setText(str); + addToContactsButton.setText(LocaleController.getString("GroupAddMembers", R.string.GroupAddMembers)); addToContactsButton.setTag(4); addToContactsButton.setTextColor(getThemedColor(Theme.key_chat_addContact)); if (Build.VERSION.SDK_INT >= 21) { @@ -21409,7 +21830,8 @@ public void onClick(View view) { if (reportSpamButton.getVisibility() == View.VISIBLE) { addToContactsButton.setText(LocaleController.getString("AddContactChat", R.string.AddContactChat)); } else { - addToContactsButton.setText(LocaleController.formatString("AddContactFullChat", R.string.AddContactFullChat, UserObject.getFirstName(user)).toUpperCase()); + float baseWidth = addToContactsButton.getPaint().measureText(LocaleController.formatString(R.string.AddContactFullChat, "")); + addToContactsButton.setText(LocaleController.formatString("AddContactFullChat", R.string.AddContactFullChat, TextUtils.ellipsize(UserObject.getFirstName(user), addToContactsButton.getPaint(), getContext().getResources().getDisplayMetrics().widthPixels - baseWidth - AndroidUtilities.dp(64 * 2), TextUtils.TruncateAt.MIDDLE)).toUpperCase()); } } addToContactsButton.setTag(null); @@ -21468,11 +21890,11 @@ public void onClick(View view) { if (chatWithAdminTextView != null) { chatWithAdminTextView.setVisibility(isChatWithAdmin ? View.VISIBLE : View.GONE); } - if (userBlocked || (addToContactsButton.getVisibility() == View.GONE && reportSpamButton.getVisibility() == View.GONE && (chatWithAdminTextView == null || chatWithAdminTextView.getVisibility() == View.GONE) && restartTopicButton.getVisibility() == View.GONE)) { + if (userBlocked || (addToContactsButton.getVisibility() == View.GONE && reportSpamButton.getVisibility() == View.GONE && (chatWithAdminTextView == null || chatWithAdminTextView.getVisibility() == View.GONE) && restartTopicButton.getVisibility() == View.GONE && translateButton.getVisibility() == View.GONE)) { show = false; } - int topChatPanelHeight; + int topChatPanelHeight = AndroidUtilities.dp(50); if (showEmojiStatusReport != null) { emojiStatusSpamHint.setVisibility(View.VISIBLE); topViewSeparator1.setVisibility(View.VISIBLE); @@ -21513,12 +21935,33 @@ public void updateDrawState(@NonNull TextPaint ds) { } emojiStatusSpamHint.setText(text); emojiStatusSpamHint.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x - AndroidUtilities.dp(50), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(99999, View.MeasureSpec.AT_MOST)); - topChatPanelHeight = AndroidUtilities.dp(50 + 16) + emojiStatusSpamHint.getMeasuredHeight(); + topChatPanelHeight += AndroidUtilities.dp(6); + emojiStatusSpamHint.setTranslationY(topChatPanelHeight); + topChatPanelHeight += AndroidUtilities.dp(10) + emojiStatusSpamHint.getMeasuredHeight(); } else { emojiStatusSpamHint.setVisibility(View.GONE); topViewSeparator1.setVisibility(View.GONE); topViewSeparator2.setVisibility(View.GONE); - topChatPanelHeight = AndroidUtilities.dp(50); + } + if (showTranslate) { + if (restartTopicButton.getVisibility() == View.VISIBLE) { +// topChatPanelHeight += AndroidUtilities.dp(48); + topViewSeparator3.setVisibility(View.VISIBLE); + } else if (addToContactsButton.getVisibility() == View.VISIBLE || user != null && !TextUtils.isEmpty(chatWithAdmin)) { + topViewSeparator3.setVisibility(View.VISIBLE); + } else { + topChatPanelHeight -= AndroidUtilities.dp(48); + topViewSeparator3.setVisibility(View.GONE); + } + topChatPanelHeight += AndroidUtilities.dp(36); + } else { + topViewSeparator3.setVisibility(View.GONE); + } + if (topViewSeparator3.getVisibility() == View.VISIBLE || + topViewSeparator2.getVisibility() == View.VISIBLE) { + topViewSeparator1.setVisibility(View.VISIBLE); + } else { + topViewSeparator1.setVisibility(View.GONE); } topChatPanelView.getLayoutParams().height = topChatPanelHeight; @@ -21637,7 +22080,7 @@ private void checkListViewPaddings() { private void checkRaiseSensors() { if (chatActivityEnterView != null && chatActivityEnterView.isStickersExpanded()) { MediaController.getInstance().setAllowStartRecord(false); - } else if (currentChat != null && !ChatObject.canSendMedia(currentChat)) { + } else if (currentChat != null && !ChatObject.canSendVoice(currentChat)) { MediaController.getInstance().setAllowStartRecord(false); } else if (!ApplicationLoader.mainInterfacePaused && (bottomOverlayChat == null || bottomOverlayChat.getVisibility() != View.VISIBLE) && (bottomOverlay == null || bottomOverlay.getVisibility() != View.VISIBLE) && (searchContainer == null || searchContainer.getVisibility() != View.VISIBLE)) { MediaController.getInstance().setAllowStartRecord(true); @@ -21785,6 +22228,11 @@ public int getBottomOffset(int tag) { height += contentPanTranslation; return height - AndroidUtilities.dp(1.5f); } + + @Override + public boolean allowLayoutChanges() { + return false; + } }); checkActionBarMenu(false); @@ -21870,6 +22318,10 @@ public int getBottomOffset(int tag) { } } + public float getPullingDownOffset() { + return pullingDownOffset; + } + public void checkAdjustResize() { if (reportType >= 0) { AndroidUtilities.requestAdjustNothing(getParentActivity(), classGuid); @@ -22657,13 +23109,16 @@ public void setAutoDeleteHistory(int time, int action) { } catch (Exception e) { } } - if (messageTextToTranslate == null) { + if (messageTextToTranslate == null && MessageObject.isMediaEmpty(selectedObject.messageOwner)) { messageTextToTranslate = getMessageContent(selectedObject, 0, false); } if (messageTextToTranslate != null && Emoji.fullyConsistsOfEmojis(messageTextToTranslate)) { messageTextToTranslate = null; // message fully consists of emojis, do not translate } } + if (selectedObject.translated) { + messageTextToTranslate = null; + } if (message.isSponsored() && !getMessagesController().premiumLocked) { items.add(LocaleController.getString("HideAd", R.string.HideAd)); @@ -23585,10 +24040,10 @@ public void run() { popupLayout.addView(rateTranscriptionLayout, rateTranscriptionLayoutParams); } - final boolean translateButtonEnabled = MessagesController.getGlobalMainSettings().getBoolean("translate_button", false); - scrimPopupWindowItems = new ActionBarMenuSubItem[items.size() + (selectedObject.isSponsored() ? 1 : 0)]; + final boolean translateButtonEnabled = MessagesController.getInstance(currentAccount).getTranslateController().isContextTranslateEnabled(); + scrimPopupWindowItems = new ActionBarMenuSubItem[items.size() + (selectedObject != null && selectedObject.isSponsored() ? 1 : 0)]; for (int a = 0, N = items.size(); a < N; a++) { - if (a == 0 && selectedObject.isSponsored()) { + if (a == 0 && selectedObject != null && selectedObject.isSponsored()) { ActionBarMenuSubItem cell = new ActionBarMenuSubItem(getParentActivity(), true, true, themeDelegate); cell.setTextAndIcon(LocaleController.getString("SponsoredMessageInfo", R.string.SponsoredMessageInfo), R.drawable.msg_info); cell.setItemHeight(56); @@ -23637,9 +24092,10 @@ public void run() { processSelectedOption(options.get(i)); }); if (option == OPTION_TRANSLATE) { - String toLang = LocaleController.getInstance().getCurrentLocale().getLanguage(); + String toLangDefault = LocaleController.getInstance().getCurrentLocale().getLanguage(); + String toLang = TranslateAlert2.getToLanguage(); final CharSequence finalMessageText = messageTextToTranslate; - TranslateAlert.OnLinkPress onLinkPress = (link) -> { + Utilities.CallbackReturn onLinkPress = (link) -> { didPressMessageUrl(link, false, selectedObject, v instanceof ChatMessageCell ? (ChatMessageCell) v : null); return true; }; @@ -23652,10 +24108,10 @@ public void run() { finalMessageText.toString(), (String lang) -> { fromLang[0] = lang; - if (fromLang[0] != null && (!fromLang[0].equals(toLang) || fromLang[0].equals("und")) && ( - translateButtonEnabled && !RestrictedLanguagesSelectActivity.getRestrictedLanguages().contains(fromLang[0]) || - (currentChat != null && (currentChat.has_link || ChatObject.isPublic(currentChat)) || selectedObject.messageOwner.fwd_from != null) && ("uk".equals(fromLang[0]) || "ru".equals(fromLang[0])) - )) { + if (fromLang[0] != null && (!fromLang[0].equals(toLang) || !fromLang[0].equals(toLangDefault) || fromLang[0].equals(TranslateController.UNKNOWN_LANGUAGE)) && ( + translateButtonEnabled && !RestrictedLanguagesSelectActivity.getRestrictedLanguages().contains(fromLang[0]) || + (currentChat != null && (currentChat.has_link || ChatObject.isPublic(currentChat)) || selectedObject.messageOwner.fwd_from != null) && ("uk".equals(fromLang[0]) || "ru".equals(fromLang[0])) + )) { cell.setVisibility(View.VISIBLE); } waitForLangDetection.set(false); @@ -23677,8 +24133,10 @@ public void run() { if (selectedObject == null || i >= options.size() || getParentActivity() == null) { return; } - TranslateAlert alert = TranslateAlert.showAlert(getParentActivity(), this, currentAccount, inputPeer, messageIdToTranslate[0], fromLang[0], toLang, finalMessageText, noforwards, onLinkPress, () -> dimBehindView(false)); - alert.showDim(false); + String toLangValue = fromLang[0] != null && fromLang[0].equals(toLang) ? toLangDefault : toLang; + ArrayList entities = selectedObject != null && selectedObject.messageOwner != null ? selectedObject.messageOwner.entities : null; + TranslateAlert2 alert = TranslateAlert2.showAlert(getParentActivity(), this, currentAccount, inputPeer, messageIdToTranslate[0], fromLang[0], toLangValue, finalMessageText, entities, noforwards, onLinkPress, () -> dimBehindView(false)); + alert.setDimBehind(false); closeMenu(false); }); cell.postDelayed(() -> { @@ -23691,8 +24149,8 @@ public void run() { if (selectedObject == null || i >= options.size() || getParentActivity() == null) { return; } - TranslateAlert alert = TranslateAlert.showAlert(getParentActivity(), this, currentAccount, inputPeer, messageIdToTranslate[0], "und", toLang, finalMessageText, noforwards, onLinkPress, () -> dimBehindView(false)); - alert.showDim(false); + TranslateAlert2 alert = TranslateAlert2.showAlert(getParentActivity(), this, currentAccount, inputPeer, messageIdToTranslate[0], "und", toLang, finalMessageText, null, noforwards, onLinkPress, () -> dimBehindView(false)); + alert.setDimBehind(false); closeMenu(false); }); } else { @@ -24088,7 +24546,7 @@ private void closeMenu(boolean hideDim) { Runnable updateReactionRunnable; - private void selectReaction(MessageObject primaryMessage, ReactionsContainerLayout reactionsLayout, View fromView, float x, float y, ReactionsLayoutInBubble.VisibleReaction visibleReaction, boolean fromDoubleTap, boolean bigEmoji, boolean addToRecent) { + public void selectReaction(MessageObject primaryMessage, ReactionsContainerLayout reactionsLayout, View fromView, float x, float y, ReactionsLayoutInBubble.VisibleReaction visibleReaction, boolean fromDoubleTap, boolean bigEmoji, boolean addToRecent) { if (isInScheduleMode()) { return; } @@ -24338,7 +24796,7 @@ private CharSequence getMessageContent(MessageObject messageObject, long previou String restrictionReason = MessagesController.getRestrictionReason(messageObject.messageOwner.restriction_reason); if (!TextUtils.isEmpty(restrictionReason)) { str.append(restrictionReason); - } else if (messageObject.caption != null){ + } else if (messageObject.caption != null) { str.append(messageObject.caption); } else { str.append(messageObject.messageText); @@ -24445,7 +24903,7 @@ private void processSelectedOption(int option) { forwardingMessageGroup = selectedObjectGroup; Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); args.putInt("messagesCount", forwardingMessageGroup == null ? 1 : forwardingMessageGroup.messages.size()); args.putInt("hasPoll", forwardingMessage.isPoll() ? (forwardingMessage.isPublicPoll() ? 2 : 1) : 0); args.putBoolean("hasInvoice", forwardingMessage.isInvoice()); @@ -24744,6 +25202,7 @@ private void processSelectedOption(int option) { checks[1] = !checks[1]; cell1.setChecked(checks[1], true); }); + builder.setCustomViewOffset(6); builder.setView(frameLayout); } } else if (ChatObject.isChannel(currentChat) && currentChat.megagroup || currentChat != null && !ChatObject.isChannel(currentChat)) { @@ -24768,6 +25227,7 @@ private void processSelectedOption(int option) { checks[0] = !checks[0]; cell1.setChecked(checks[0], true); }); + builder.setCustomViewOffset(9); builder.setView(frameLayout); } } else { @@ -25062,9 +25522,9 @@ private void processSelectedOption(int option) { } @Override - public void didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param) { + public boolean didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param) { if (forwardingMessage == null && selectedMessagesIds[0].size() == 0 && selectedMessagesIds[1].size() == 0) { - return; + return false; } ArrayList fmessages = new ArrayList<>(); if (forwardingMessage != null) { @@ -25073,8 +25533,6 @@ public void didSelectDialogs(DialogsActivity fragment, ArrayList= 0; a--) { ArrayList ids = new ArrayList<>(); @@ -25089,6 +25547,25 @@ public void didSelectDialogs(DialogsActivity fragment, ArrayList= 0; a--) { selectedMessagesCanCopyIds[a].clear(); selectedMessagesCanStarIds[a].clear(); selectedMessagesIds[a].clear(); @@ -25129,7 +25606,7 @@ public void didSelectDialogs(DialogsActivity fragment, ArrayList= 0; a--) { selectedMessagesIds[a].clear(); selectedMessagesCanCopyIds[a].clear(); @@ -25244,7 +25726,8 @@ private void clearSelectionMode() { } hideActionMode(); updatePinnedMessageView(true); - updateVisibleRows(); + updateVisibleRows(suppressUpdateMessageObject); + updateSelectedMessageReactions(); } public void onListItemAnimatorTick() { @@ -25294,6 +25777,10 @@ public boolean isReplyChatComment() { } private void updateVisibleRows() { + updateVisibleRows(false); + } + + private void updateVisibleRows(boolean suppressUpdateMessageObject) { if (chatListView == null) { return; } @@ -25341,7 +25828,7 @@ private void updateVisibleRows() { cell.setChecked(false, false, true); } - if (!cell.getMessageObject().deleted || cell.linkedChatId != linkedChatId) { + if ((!cell.getMessageObject().deleted || cell.linkedChatId != linkedChatId) && !suppressUpdateMessageObject) { cell.setIsUpdating(true); cell.linkedChatId = chatInfo != null ? chatInfo.linked_chat_id : 0; cell.setMessageObject(cell.getMessageObject(), cell.getCurrentMessagesGroup(), cell.isPinnedBottom(), cell.isPinnedTop()); @@ -25362,7 +25849,9 @@ private void updateVisibleRows() { cell.setSpoilersSuppressed(chatListView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE); } else if (view instanceof ChatActionCell) { ChatActionCell cell = (ChatActionCell) view; - cell.setMessageObject(cell.getMessageObject()); + if (!suppressUpdateMessageObject) { + cell.setMessageObject(cell.getMessageObject()); + } cell.setSpoilersSuppressed(chatListView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE); } } @@ -25495,6 +25984,10 @@ public boolean canScheduleMessage() { return currentEncryptedChat == null && (bottomOverlayChat == null || bottomOverlayChat.getVisibility() != View.VISIBLE) && !isThreadChat(); } + public boolean canSendMessage() { + return currentEncryptedChat == null && (bottomOverlayChat == null || bottomOverlayChat.getVisibility() != View.VISIBLE); + } + public boolean isInScheduleMode() { return chatMode == MODE_SCHEDULED; } @@ -25590,6 +26083,25 @@ public void sendMedia(MediaController.PhotoEntry photoEntry, VideoEditedInfo vid afterMessageSend(); } + public void sendAnimatedEmoji(TLRPC.Document emoji, boolean notify, int scheduleDate) { + if (emoji == null) { + return; + } + String message = MessageObject.findAnimatedEmojiEmoticon(emoji, null); + if (message == null) { + return; + } + ArrayList entities = new ArrayList<>(); + TLRPC.TL_messageEntityCustomEmoji entity = new TLRPC.TL_messageEntityCustomEmoji(); + entity.document = emoji; + entity.document_id = emoji.id; + entity.offset = 0; + entity.length = message.length(); + entities.add(entity); + SendMessagesHelper.getInstance(currentAccount).sendMessage(message, dialog_id, replyingMessageObject, getThreadMessage(), null, false, entities, null, null, notify, scheduleDate, null, false); + afterMessageSend(); + } + public void showOpenGameAlert(final TLRPC.TL_game game, final MessageObject messageObject, final String urlStr, boolean ask, final long uid) { TLRPC.User user = getMessagesController().getUser(uid); if (ask) { @@ -25913,7 +26425,6 @@ public void showRequestUrlAlert(final TLRPC.TL_urlAuthResultRequest request, TLR } }); } - builder.setCustomViewOffset(12); builder.setView(linearLayout); builder.setPositiveButton(LocaleController.getString("Open", R.string.Open), (dialogInterface, i) -> { if (!cells[0].isChecked()) { @@ -26210,8 +26721,8 @@ public void end(boolean replaced) { private void processExternalUrl(int type, String url, CharacterStyle span, ChatMessageCell cell, boolean forceAlert) { try { - Uri uri = Uri.parse(url); - String host = uri.getHost() != null ? uri.getHost().toLowerCase() : ""; + + String host = AndroidUtilities.getHostAuthority(url); if ((currentEncryptedChat == null || getMessagesController().secretWebpagePreview == 1) && getMessagesController().authDomains.contains(host)) { getSendMessagesHelper().requestUrlAuth(url, this, type == 0 || type == 2); return; @@ -27003,7 +27514,7 @@ public void didPressBotButton(ChatMessageCell cell, TLRPC.KeyboardButton button) !(button instanceof TLRPC.TL_keyboardButtonSwitchInline) && !(button instanceof TLRPC.TL_keyboardButtonCallback) && !(button instanceof TLRPC.TL_keyboardButtonGame) && !(button instanceof TLRPC.TL_keyboardButtonUrl) && !(button instanceof TLRPC.TL_keyboardButtonBuy) && !(button instanceof TLRPC.TL_keyboardButtonUrlAuth) && - !(button instanceof TLRPC.TL_keyboardButtonUserProfile)) { + !(button instanceof TLRPC.TL_keyboardButtonUserProfile) && !(button instanceof TLRPC.TL_keyboardButtonRequestPeer)) { return; } chatActivityEnterView.didPressedBotButton(button, cell.getMessageObject(), cell.getMessageObject(), makeProgressForBotButton(cell, button instanceof TLRPC.TL_keyboardButtonUrl ? button.url : null)); @@ -27405,7 +27916,13 @@ public void needReloadPolls() { @Override public void didPressImage(ChatMessageCell cell, float x, float y) { MessageObject message = cell.getMessageObject(); - message.putInDownloadsStore = true; + if (message.isVideo()) { + if (DownloadController.getInstance(currentAccount).canDownloadMedia(message.messageOwner) == 1) { + message.putInDownloadsStore = true; + } + } else { + message.putInDownloadsStore = true; + } if (message.isSendError()) { createMenu(cell, false, false, x, y); return; @@ -27718,7 +28235,7 @@ public void didClickImage(ChatActionCell cell) { TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, 640); TLRPC.VideoSize videoSize = null; if (message.messageOwner.action.photo.video_sizes != null && !message.messageOwner.action.photo.video_sizes.isEmpty()) { - videoSize = message.messageOwner.action.photo.video_sizes.get(0); + videoSize = FileLoader.getClosestVideoSizeWithSize(message.messageOwner.action.photo.video_sizes, 1000); } if (cell.getMessageObject().type == MessageObject.TYPE_SUGGEST_PHOTO && !message.isOutOwner()) { if (message.settingAvatar) { @@ -27845,10 +28362,10 @@ public void didPressReplyMessage(ChatActionCell cell, int id) { @Override public void didPressBotButton(MessageObject messageObject, TLRPC.KeyboardButton button) { if (getParentActivity() == null || bottomOverlayChat.getVisibility() == View.VISIBLE && - !(button instanceof TLRPC.TL_keyboardButtonSwitchInline) && !(button instanceof TLRPC.TL_keyboardButtonCallback) && - !(button instanceof TLRPC.TL_keyboardButtonGame) && !(button instanceof TLRPC.TL_keyboardButtonUrl) && - !(button instanceof TLRPC.TL_keyboardButtonBuy) && !(button instanceof TLRPC.TL_keyboardButtonUrlAuth) && - !(button instanceof TLRPC.TL_keyboardButtonUserProfile)) { + !(button instanceof TLRPC.TL_keyboardButtonSwitchInline) && !(button instanceof TLRPC.TL_keyboardButtonCallback) && + !(button instanceof TLRPC.TL_keyboardButtonGame) && !(button instanceof TLRPC.TL_keyboardButtonUrl) && + !(button instanceof TLRPC.TL_keyboardButtonBuy) && !(button instanceof TLRPC.TL_keyboardButtonUrlAuth) && + !(button instanceof TLRPC.TL_keyboardButtonUserProfile) && !(button instanceof TLRPC.TL_keyboardButtonRequestPeer)) { return; } chatActivityEnterView.didPressedBotButton(button, messageObject, messageObject); @@ -27896,6 +28413,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { TLRPC.BotInfo mBotInfo = botInfo.size() != 0 ? botInfo.get(currentUser.id) : null; helpView.setText(true, mBotInfo != null ? mBotInfo.description : null, mBotInfo != null ? mBotInfo.description_document != null ? mBotInfo.description_document : mBotInfo.description_photo : null, mBotInfo); } + updateBotHelpCellClick(helpView); } else if (position == loadingDownRow || position == loadingUpRow) { ChatLoadingCell loadingCell = (ChatLoadingCell) holder.itemView; loadingCell.setProgressVisible(loadsCount > 1); @@ -28038,6 +28556,12 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } } + message.updateTranslation(false); + if (groupedMessages != null) { + for (int i = 0; i < groupedMessages.messages.size(); ++i) { + groupedMessages.messages.get(i).updateTranslation(false); + } + } messageCell.setMessageObject(message, groupedMessages, pinnedBottom, pinnedTop); messageCell.setSpoilersSuppressed(chatListView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE); messageCell.setHighlighted(highlightMessageId != Integer.MAX_VALUE && message.getId() == highlightMessageId); @@ -28348,6 +28872,16 @@ public boolean onPreDraw() { } } } + if (message.updateTranslation(false)) { + messageCell.setMessageObject(message, messageCell.getCurrentMessagesGroup(), messageCell.isPinnedBottom(), messageCell.isPinnedTop()); + } else { + MessageObject.GroupedMessages group = messageCell.getCurrentMessagesGroup(); + if (group != null) { + for (int i = 0; i < group.messages.size(); ++i) { + group.messages.get(i).updateTranslation(); + } + } + } boolean selected = false; boolean disableSelection = false; @@ -30477,6 +31011,52 @@ private int getCurrentColorOrDefault(String key, boolean ignoreAnimation) { } } + private void updateBotHelpCellClick(BotHelpCell cell) { + final boolean translateButtonEnabled = MessagesController.getInstance(currentAccount).getTranslateController().isContextTranslateEnabled(); + if (translateButtonEnabled && LanguageDetector.hasSupport()) { + final CharSequence text = cell.getText(); + LanguageDetector.detectLanguage(text == null ? "" : text.toString(), lang -> { + String toLang = LocaleController.getInstance().getCurrentLocale().getLanguage(); + if (lang != null && (!lang.equals(toLang) || lang.equals("und")) && !RestrictedLanguagesSelectActivity.getRestrictedLanguages().contains(lang)) { + cell.setOnClickListener(e -> { + + ActionBarPopupWindow.ActionBarPopupWindowLayout layout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getContext()); + Drawable shadowDrawable2 = ContextCompat.getDrawable(getContext(), R.drawable.popup_fixed_alert).mutate(); + shadowDrawable2.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_actionBarDefaultSubmenuBackground), PorterDuff.Mode.MULTIPLY)); + layout.setBackground(shadowDrawable2); + + final Runnable[] dismiss = new Runnable[1]; + ActionBarMenuSubItem translateButton = new ActionBarMenuSubItem(getContext(), true, true); + translateButton.setTextAndIcon(LocaleController.getString("TranslateMessage", R.string.TranslateMessage), R.drawable.msg_translate); + translateButton.setOnClickListener(e2 -> { + TranslateAlert2.showAlert(getContext(), this, currentAccount, lang, toLang, text, null, false, null, null); + if (dismiss[0] != null) { + dismiss[0].run(); + } + }); + layout.addView(translateButton); + + ActionBarPopupWindow window = new ActionBarPopupWindow(layout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT); + dismiss[0] = () -> window.dismiss(); + window.setPauseNotifications(true); + window.setDismissAnimationDuration(220); + window.setOutsideTouchable(true); + window.setClippingEnabled(true); + window.setAnimationStyle(R.style.PopupContextAnimation); + window.setFocusable(true); + window.showAsDropDown(cell, cell.getWidth() / 2 - AndroidUtilities.dp(90), AndroidUtilities.dp(-16), Gravity.BOTTOM | Gravity.LEFT); + }); + } else { + cell.setClickable(false); + } + }, err -> { + cell.setClickable(false); + }); + } else { + cell.setClickable(false); + } + } + @Override protected boolean allowPresentFragment() { return !inPreviewMode; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java index dbbb3f1612a..c6ee5bc5f1a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java @@ -199,8 +199,9 @@ public void openPhotoForEdit(String file, String thumb, boolean isVideo) { public ChatEditActivity(Bundle args) { super(args); avatarDrawable = new AvatarDrawable(); - imageUpdater = new ImageUpdater(true); chatId = args.getLong("chat_id", 0); + TLRPC.Chat chat = getMessagesController().getChat(chatId); + imageUpdater = new ImageUpdater(true, chat != null && ChatObject.isChannelAndNotMegaGroup(chat) ? ImageUpdater.FOR_TYPE_CHANNEL : ImageUpdater.FOR_TYPE_GROUP, true); } @Override @@ -605,7 +606,7 @@ protected void onDraw(Canvas canvas) { setAvatarCell.setOnClickListener(v -> { imageUpdater.openMenu(avatar != null, () -> { avatar = null; - MessagesController.getInstance(currentAccount).changeChatAvatar(chatId, null, null, null, 0, null, null, null, null); + MessagesController.getInstance(currentAccount).changeChatAvatar(chatId, null, null, null, null, 0, null, null, null, null); showAvatarProgress(false, true); avatarImage.setImage(null, null, avatarDrawable, currentChat); cameraDrawable.setCurrentFrame(0); @@ -1110,11 +1111,11 @@ public void didStartUpload(boolean isVideo) { } @Override - public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile video, double videoStartTimestamp, String videoPath, final TLRPC.PhotoSize bigSize, final TLRPC.PhotoSize smallSize, boolean isVideo) { + public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile video, double videoStartTimestamp, String videoPath, final TLRPC.PhotoSize bigSize, final TLRPC.PhotoSize smallSize, boolean isVideo, TLRPC.VideoSize emojiMarkup) { AndroidUtilities.runOnUIThread(() -> { avatar = smallSize.location; - if (photo != null || video != null) { - getMessagesController().changeChatAvatar(chatId, null, photo, video, videoStartTimestamp, videoPath, smallSize.location, bigSize.location, null); + if (photo != null || video != null || emojiMarkup != null) { + getMessagesController().changeChatAvatar(chatId, null, photo, video, emojiMarkup, videoStartTimestamp, videoPath, smallSize.location, bigSize.location, null); if (createAfterUpload) { try { if (progressDialog != null && progressDialog.isShowing()) { @@ -1473,24 +1474,13 @@ private void updateFields(boolean updateChat, boolean animated) { } else { int count = 0; if (currentChat.default_banned_rights != null) { - if (!currentChat.default_banned_rights.send_stickers) { - count++; - } - if (!currentChat.default_banned_rights.send_media) { - count++; - } - if (!currentChat.default_banned_rights.embed_links) { - count++; - } - if (!currentChat.default_banned_rights.send_messages) { + if (!currentChat.default_banned_rights.send_plain) { count++; } + count += ChatUsersActivity.getSendMediaSelectedCount(currentChat.default_banned_rights); if (!currentChat.default_banned_rights.pin_messages) { count++; } - if (!currentChat.default_banned_rights.send_polls) { - count++; - } if (!currentChat.default_banned_rights.invite_users) { count++; } @@ -1501,9 +1491,9 @@ private void updateFields(boolean updateChat, boolean animated) { count++; } } else { - count = forum ? 9 : 8; + count = forum ? 14 : 13; } - blockCell.setTextAndValueAndIcon(LocaleController.getString("ChannelPermissions", R.string.ChannelPermissions), String.format("%d/%d", count, forum ? 9 : 8), animated, R.drawable.msg_permissions, true); + blockCell.setTextAndValueAndIcon(LocaleController.getString("ChannelPermissions", R.string.ChannelPermissions), String.format("%d/%d", count, forum ? 14 : 13), animated, R.drawable.msg_permissions, true); } if (memberRequestsCell != null) { memberRequestsCell.setTextAndValueAndIcon(LocaleController.getString("MemberRequests", R.string.MemberRequests), String.format("%d", info.requests_pending), R.drawable.msg_requests, logCell != null && logCell.getVisibility() == View.VISIBLE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java index c4426ad1586..9e2f0ddbe37 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java @@ -39,6 +39,7 @@ import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.ChatObject; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; @@ -55,6 +56,7 @@ import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; +import org.telegram.ui.Cells.CheckBoxCell; import org.telegram.ui.Cells.DialogRadioCell; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.PollEditTextCell; @@ -69,12 +71,14 @@ import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.CircularProgressDrawable; import org.telegram.ui.Components.CrossfadeDrawable; +import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.RecyclerListView; import java.util.ArrayList; import java.util.Calendar; +import java.util.Locale; public class ChatRightsEditActivity extends BaseFragment { @@ -136,6 +140,12 @@ public class ChatRightsEditActivity extends BaseFragment { private int sendMessagesRow; private int sendMediaRow; + private int sendPhotosRow; + private int sendVideosRow; + private int sendMusicRow; + private int sendFilesRow; + private int sendVoiceRow; + private int sendRoundRow; private int sendStickersRow; private int sendPollsRow; private int embedLinksRow; @@ -154,9 +164,11 @@ public class ChatRightsEditActivity extends BaseFragment { public static final int TYPE_ADD_BOT = 2; private boolean closingKeyboardAfterFinish = false; + private boolean sendMediaExpanded; public interface ChatRightsEditActivityDelegate { void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank); + void didChangeOwner(TLRPC.User user); } @@ -261,10 +273,12 @@ public ChatRightsEditActivity(long userId, long channelId, TLRPC.TL_chatAdminRig if (defaultBannedRights == null) { defaultBannedRights = new TLRPC.TL_chatBannedRights(); defaultBannedRights.view_messages = defaultBannedRights.send_media = defaultBannedRights.send_messages = - defaultBannedRights.embed_links = defaultBannedRights.send_stickers = defaultBannedRights.send_gifs = - defaultBannedRights.send_games = defaultBannedRights.send_inline = defaultBannedRights.send_polls = - defaultBannedRights.invite_users = defaultBannedRights.change_info = defaultBannedRights.pin_messages = - defaultBannedRights.manage_topics = true; + defaultBannedRights.embed_links = defaultBannedRights.send_stickers = defaultBannedRights.send_gifs = + defaultBannedRights.send_games = defaultBannedRights.send_inline = defaultBannedRights.send_polls = + defaultBannedRights.invite_users = defaultBannedRights.change_info = defaultBannedRights.pin_messages = + defaultBannedRights.manage_topics = defaultBannedRights.send_plain = defaultBannedRights.send_videos = + defaultBannedRights.send_photos = defaultBannedRights.send_audios = defaultBannedRights.send_docs = + defaultBannedRights.send_voices = defaultBannedRights.send_roundvideos = false; } if (!defaultBannedRights.change_info) { @@ -278,19 +292,21 @@ public ChatRightsEditActivity(long userId, long channelId, TLRPC.TL_chatAdminRig if (defaultBannedRights == null) { defaultBannedRights = new TLRPC.TL_chatBannedRights(); defaultBannedRights.view_messages = defaultBannedRights.send_media = defaultBannedRights.send_messages = - defaultBannedRights.embed_links = defaultBannedRights.send_stickers = defaultBannedRights.send_gifs = - defaultBannedRights.send_games = defaultBannedRights.send_inline = defaultBannedRights.send_polls = - defaultBannedRights.invite_users = defaultBannedRights.change_info = defaultBannedRights.pin_messages = - defaultBannedRights.manage_topics = false; + defaultBannedRights.embed_links = defaultBannedRights.send_stickers = defaultBannedRights.send_gifs = + defaultBannedRights.send_games = defaultBannedRights.send_inline = defaultBannedRights.send_polls = + defaultBannedRights.invite_users = defaultBannedRights.change_info = defaultBannedRights.pin_messages = + defaultBannedRights.manage_topics = defaultBannedRights.send_plain = defaultBannedRights.send_videos = + defaultBannedRights.send_photos = defaultBannedRights.send_audios = defaultBannedRights.send_docs = + defaultBannedRights.send_voices = defaultBannedRights.send_roundvideos = false; } bannedRights = new TLRPC.TL_chatBannedRights(); if (rightsBanned == null) { bannedRights.view_messages = bannedRights.send_media = bannedRights.send_messages = - bannedRights.embed_links = bannedRights.send_stickers = bannedRights.send_gifs = - bannedRights.send_games = bannedRights.send_inline = bannedRights.send_polls = - bannedRights.invite_users = bannedRights.change_info = bannedRights.pin_messages = - bannedRights.manage_topics = false; + bannedRights.embed_links = bannedRights.send_stickers = bannedRights.send_gifs = + bannedRights.send_games = bannedRights.send_inline = bannedRights.send_polls = + bannedRights.invite_users = bannedRights.change_info = bannedRights.pin_messages = + bannedRights.manage_topics = false; } else { bannedRights.view_messages = rightsBanned.view_messages; bannedRights.send_messages = rightsBanned.send_messages; @@ -306,6 +322,13 @@ public ChatRightsEditActivity(long userId, long channelId, TLRPC.TL_chatAdminRig bannedRights.pin_messages = rightsBanned.pin_messages; bannedRights.until_date = rightsBanned.until_date; bannedRights.manage_topics = rightsBanned.manage_topics; + bannedRights.send_photos = rightsBanned.send_photos; + bannedRights.send_videos = rightsBanned.send_videos; + bannedRights.send_roundvideos = rightsBanned.send_roundvideos; + bannedRights.send_audios = rightsBanned.send_audios; + bannedRights.send_voices = rightsBanned.send_voices; + bannedRights.send_docs = rightsBanned.send_docs; + bannedRights.send_plain = rightsBanned.send_plain; } if (defaultBannedRights.view_messages) { bannedRights.view_messages = true; @@ -346,6 +369,27 @@ public ChatRightsEditActivity(long userId, long channelId, TLRPC.TL_chatAdminRig if (defaultBannedRights.manage_topics) { bannedRights.manage_topics = true; } + if (defaultBannedRights.send_photos) { + bannedRights.send_photos = true; + } + if (defaultBannedRights.send_videos) { + bannedRights.send_videos = true; + } + if (defaultBannedRights.send_audios) { + bannedRights.send_audios = true; + } + if (defaultBannedRights.send_docs) { + bannedRights.send_docs = true; + } + if (defaultBannedRights.send_voices) { + bannedRights.send_voices = true; + } + if (defaultBannedRights.send_roundvideos) { + bannedRights.send_roundvideos = true; + } + if (defaultBannedRights.send_plain) { + bannedRights.send_plain = true; + } currentBannedRights = ChatObject.getBannedRightsString(bannedRights); @@ -354,15 +398,30 @@ public ChatRightsEditActivity(long userId, long channelId, TLRPC.TL_chatAdminRig updateRows(false); } + public static TLRPC.TL_chatAdminRights rightsOR(TLRPC.TL_chatAdminRights a, TLRPC.TL_chatAdminRights b) { + TLRPC.TL_chatAdminRights adminRights = new TLRPC.TL_chatAdminRights(); + adminRights.change_info = a.change_info || b.change_info; + adminRights.post_messages = a.post_messages || b.post_messages; + adminRights.edit_messages = a.edit_messages || b.edit_messages; + adminRights.delete_messages = a.delete_messages || b.delete_messages; + adminRights.ban_users = a.ban_users || b.ban_users; + adminRights.invite_users = a.invite_users || b.invite_users; + adminRights.pin_messages = a.pin_messages || b.pin_messages; + adminRights.add_admins = a.add_admins || b.add_admins; + adminRights.manage_call = a.manage_call || b.manage_call; + adminRights.manage_topics = a.manage_topics || b.manage_topics; + return adminRights; + } + + public static TLRPC.TL_chatAdminRights emptyAdminRights(boolean value) { TLRPC.TL_chatAdminRights adminRights = new TLRPC.TL_chatAdminRights(); adminRights.change_info = adminRights.post_messages = adminRights.edit_messages = - adminRights.delete_messages = adminRights.ban_users = adminRights.invite_users = - adminRights.pin_messages = adminRights.add_admins = adminRights.manage_call = adminRights.manage_topics = value; + adminRights.delete_messages = adminRights.ban_users = adminRights.invite_users = + adminRights.pin_messages = adminRights.add_admins = adminRights.manage_call = adminRights.manage_topics = value; return adminRights; } - @Override public View createView(Context context) { actionBar.setBackButtonImage(R.drawable.ic_ab_back); @@ -400,6 +459,7 @@ public void onItemClick(int id) { fragmentView = new FrameLayout(context) { private int previousHeight = -1; + @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); @@ -445,7 +505,10 @@ protected int getExtraLayoutSpace(RecyclerView.State state) { if (currentType == TYPE_ADD_BOT) { listView.setResetSelectorOnChanged(false); } + itemAnimator.setSupportsChangeAnimations(false); itemAnimator.setDelayAnimations(false); + itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + itemAnimator.setDurations(350); listView.setItemAnimator(itemAnimator); listView.setVerticalScrollbarPosition(LocaleController.isRTL ? RecyclerListView.SCROLLBAR_POSITION_LEFT : RecyclerListView.SCROLLBAR_POSITION_RIGHT); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); @@ -463,13 +526,32 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { if (!canEdit && (!currentChat.creator || currentType != TYPE_ADMIN || position != anonymousRow)) { return; } + if (position == sendMediaRow) { +// if (allDefaultMediaBanned()) { +// new AlertDialog.Builder(getParentActivity()) +// .setTitle(LocaleController.getString("UserRestrictionsCantModify", R.string.UserRestrictionsCantModify)) +// .setMessage(LocaleController.getString("UserRestrictionsCantModifyEnabled", R.string.UserRestrictionsCantModifyEnabled)) +// .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) +// .create() +// .show(); +// return; +// } + sendMediaExpanded = !sendMediaExpanded; + updateRows(false); + if (sendMediaExpanded) { + listViewAdapter.notifyItemRangeInserted(sendMediaRow + 1, 9); + } else { + listViewAdapter.notifyItemRangeRemoved(sendMediaRow + 1, 9); + } + return; + } if (position == 0) { Bundle args = new Bundle(); args.putLong("user_id", currentUser.id); presentFragment(new ProfileActivity(args)); } else if (position == removeAdminRow) { if (currentType == TYPE_ADMIN) { - MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, currentUser, new TLRPC.TL_chatAdminRights(), currentRank, isChannel, getFragmentForAlert(0), isAddingNew, false, null,null); + MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, currentUser, new TLRPC.TL_chatAdminRights(), currentRank, isChannel, getFragmentForAlert(0), isAddingNew, false, null, null); if (delegate != null) { delegate.didSetRights(0, adminRights, bannedRights, currentRank); } @@ -630,30 +712,78 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { } builder.setCustomView(linearLayout); showDialog(builder.create()); + } else if (view instanceof CheckBoxCell) { + CheckBoxCell checkBoxCell = (CheckBoxCell) view; + if (currentType == TYPE_BANNED && bannedRights != null) { + boolean disabled = !checkBoxCell.isChecked(); + boolean value = false; + + if (checkBoxCell.hasIcon()) { + if (currentType != TYPE_ADD_BOT) { + new AlertDialog.Builder(getParentActivity()) + .setTitle(LocaleController.getString("UserRestrictionsCantModify", R.string.UserRestrictionsCantModify)) + .setMessage(LocaleController.getString("UserRestrictionsCantModifyDisabled", R.string.UserRestrictionsCantModifyDisabled)) + .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) + .create() + .show(); + } + return; + } + + if (position == sendPhotosRow) { + value = bannedRights.send_photos = !bannedRights.send_photos; + } else if (position == sendVideosRow) { + value = bannedRights.send_videos = !bannedRights.send_videos; + } else if (position == sendMusicRow) { + value = bannedRights.send_audios = !bannedRights.send_audios; + } else if (position == sendFilesRow) { + value = bannedRights.send_docs = !bannedRights.send_docs; + } else if (position == sendRoundRow) { + value = bannedRights.send_roundvideos = !bannedRights.send_roundvideos; + } else if (position == sendVoiceRow) { + value = bannedRights.send_voices = !bannedRights.send_voices; + } else if (position == sendStickersRow) { + value = bannedRights.send_stickers = bannedRights.send_games = bannedRights.send_gifs = bannedRights.send_inline = !bannedRights.send_stickers; + } else if (position == embedLinksRow) { + if (bannedRights.send_plain || defaultBannedRights.send_plain) { + View senMessagesView = linearLayoutManager.findViewByPosition(sendMessagesRow); + if (senMessagesView != null) { + AndroidUtilities.shakeViewSpring(senMessagesView); + BotWebViewVibrationEffect.APP_ERROR.vibrate(); + return; + } + } + value = bannedRights.embed_links = !bannedRights.embed_links; + } else if (position == sendPollsRow) { + value = bannedRights.send_polls = !bannedRights.send_polls; + } + listViewAdapter.notifyItemChanged(sendMediaRow); + checkBoxCell.setChecked(!value, true); + } } else if (view instanceof TextCheckCell2) { TextCheckCell2 checkCell = (TextCheckCell2) view; if (checkCell.hasIcon()) { if (currentType != TYPE_ADD_BOT) { new AlertDialog.Builder(getParentActivity()) - .setTitle(LocaleController.getString("UserRestrictionsCantModify", R.string.UserRestrictionsCantModify)) - .setMessage(LocaleController.getString("UserRestrictionsCantModifyDisabled", R.string.UserRestrictionsCantModifyDisabled)) - .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) - .create() - .show(); + .setTitle(LocaleController.getString("UserRestrictionsCantModify", R.string.UserRestrictionsCantModify)) + .setMessage(LocaleController.getString("UserRestrictionsCantModifyDisabled", R.string.UserRestrictionsCantModifyDisabled)) + .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) + .create() + .show(); } return; } if (!checkCell.isEnabled()) { if ((currentType == TYPE_ADD_BOT || currentType == TYPE_ADMIN) && - (position == changeInfoRow && defaultBannedRights != null && !defaultBannedRights.change_info || - position == pinMessagesRow && defaultBannedRights != null && !defaultBannedRights.pin_messages)) { + (position == changeInfoRow && defaultBannedRights != null && !defaultBannedRights.change_info || + position == pinMessagesRow && defaultBannedRights != null && !defaultBannedRights.pin_messages)) { new AlertDialog.Builder(getParentActivity()) - .setTitle(LocaleController.getString("UserRestrictionsCantModify", R.string.UserRestrictionsCantModify)) - .setMessage(LocaleController.getString("UserRestrictionsCantModifyEnabled", R.string.UserRestrictionsCantModifyEnabled)) - .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) - .create() - .show(); + .setTitle(LocaleController.getString("UserRestrictionsCantModify", R.string.UserRestrictionsCantModify)) + .setMessage(LocaleController.getString("UserRestrictionsCantModifyEnabled", R.string.UserRestrictionsCantModifyEnabled)) + .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) + .create() + .show(); } return; } @@ -705,63 +835,18 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { } else if (currentType == TYPE_BANNED && bannedRights != null) { boolean disabled = !checkCell.isChecked(); if (position == sendMessagesRow) { - value = bannedRights.send_messages = !bannedRights.send_messages; - } else if (position == sendMediaRow) { - value = bannedRights.send_media = !bannedRights.send_media; - } else if (position == sendStickersRow) { - value = bannedRights.send_stickers = bannedRights.send_games = bannedRights.send_gifs = bannedRights.send_inline = !bannedRights.send_stickers; - } else if (position == embedLinksRow) { - value = bannedRights.embed_links = !bannedRights.embed_links; - } else if (position == sendPollsRow) { - value = bannedRights.send_polls = !bannedRights.send_polls; + value = bannedRights.send_plain = !bannedRights.send_plain; } - if (disabled) { - if (bannedRights.view_messages && !bannedRights.send_messages) { - bannedRights.send_messages = true; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(sendMessagesRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(false); - } - } - if ((bannedRights.view_messages || bannedRights.send_messages) && !bannedRights.send_media) { - bannedRights.send_media = true; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(sendMediaRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(false); - } - } - if ((bannedRights.view_messages || bannedRights.send_messages) && !bannedRights.send_polls) { - bannedRights.send_polls = true; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(sendPollsRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(false); - } - } - if ((bannedRights.view_messages || bannedRights.send_messages) && !bannedRights.send_stickers) { - bannedRights.send_stickers = bannedRights.send_games = bannedRights.send_gifs = bannedRights.send_inline = true; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(sendStickersRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(false); - } - } - if ((bannedRights.view_messages || bannedRights.send_messages) && !bannedRights.embed_links) { - bannedRights.embed_links = true; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(embedLinksRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(false); - } - } - } else { - if ((!bannedRights.send_messages || !bannedRights.embed_links || !bannedRights.send_inline || !bannedRights.send_media || !bannedRights.send_polls) && bannedRights.view_messages) { + if (!disabled) { + if ((!bannedRights.send_plain || !bannedRights.embed_links || !bannedRights.send_inline || !bannedRights.send_photos || !bannedRights.send_videos || !bannedRights.send_audios || !bannedRights.send_docs || !bannedRights.send_voices || !bannedRights.send_roundvideos || !bannedRights.send_polls) && bannedRights.view_messages) { bannedRights.view_messages = false; } - if ((!bannedRights.embed_links || !bannedRights.send_inline || !bannedRights.send_media || !bannedRights.send_polls) && bannedRights.send_messages) { - bannedRights.send_messages = false; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(sendMessagesRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(true); - } - } + } + if (embedLinksRow >= 0) { + listViewAdapter.notifyItemChanged(embedLinksRow); + } + if (sendMediaRow >= 0) { + listViewAdapter.notifyItemChanged(sendMediaRow); } } if (currentType == TYPE_ADD_BOT) { @@ -982,6 +1067,13 @@ private void updateRows(boolean update) { sendMessagesRow = -1; sendMediaRow = -1; + + sendPhotosRow = -1; + sendVideosRow = -1; + sendMusicRow = -1; + sendFilesRow = -1; + sendVoiceRow = -1; + sendRoundRow = -1; sendStickersRow = -1; sendPollsRow = -1; embedLinksRow = -1; @@ -1021,9 +1113,18 @@ private void updateRows(boolean update) { } else if (currentType == TYPE_BANNED) { sendMessagesRow = rowCount++; sendMediaRow = rowCount++; - sendStickersRow = rowCount++; - sendPollsRow = rowCount++; - embedLinksRow = rowCount++; + if (sendMediaExpanded) { + sendPhotosRow = rowCount++; + sendVideosRow = rowCount++; + sendFilesRow = rowCount++; + sendMusicRow = rowCount++; + sendVoiceRow = rowCount++; + sendRoundRow = rowCount++; + sendStickersRow = rowCount++; + sendPollsRow = rowCount++; + embedLinksRow = rowCount++; + } + addUsersRow = rowCount++; pinMessagesRow = rowCount++; changeInfoRow = rowCount++; @@ -1136,10 +1237,10 @@ private void onDonePressed() { MessagesController.getInstance(currentAccount).setUserAdminRole(chatId, currentUser, adminRights, currentRank, isChannel, this, isAddingNew, false, null, () -> { if (delegate != null) { delegate.didSetRights( - adminRights.change_info || adminRights.post_messages || adminRights.edit_messages || - adminRights.delete_messages || adminRights.ban_users || adminRights.invite_users || (isForum && adminRights.manage_topics) || - adminRights.pin_messages || adminRights.add_admins || adminRights.anonymous || adminRights.manage_call || - adminRights.other ? 1 : 0, adminRights, bannedRights, currentRank); + adminRights.change_info || adminRights.post_messages || adminRights.edit_messages || + adminRights.delete_messages || adminRights.ban_users || adminRights.invite_users || (isForum && adminRights.manage_topics) || + adminRights.pin_messages || adminRights.add_admins || adminRights.anonymous || adminRights.manage_call || + adminRights.other ? 1 : 0, adminRights, bannedRights, currentRank); finishFragment(); } }, err -> { @@ -1162,17 +1263,17 @@ private void onDonePressed() { } else if (currentType == TYPE_ADD_BOT) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(asAdmin ? - LocaleController.getString("AddBotAdmin", R.string.AddBotAdmin) : - LocaleController.getString("AddBot", R.string.AddBot) + LocaleController.getString("AddBotAdmin", R.string.AddBotAdmin) : + LocaleController.getString("AddBot", R.string.AddBot) ); boolean isChannel = ChatObject.isChannel(currentChat) && !currentChat.megagroup; String chatName = currentChat == null ? "" : currentChat.title; builder.setMessage(AndroidUtilities.replaceTags( - asAdmin ? ( - isChannel ? - LocaleController.formatString("AddBotMessageAdminChannel", R.string.AddBotMessageAdminChannel, chatName) : - LocaleController.formatString("AddBotMessageAdminGroup", R.string.AddBotMessageAdminGroup, chatName) - ) : LocaleController.formatString("AddMembersAlertNamesText", R.string.AddMembersAlertNamesText, UserObject.getUserName(currentUser), chatName) + asAdmin ? ( + isChannel ? + LocaleController.formatString("AddBotMessageAdminChannel", R.string.AddBotMessageAdminChannel, chatName) : + LocaleController.formatString("AddBotMessageAdminGroup", R.string.AddBotMessageAdminGroup, chatName) + ) : LocaleController.formatString("AddMembersAlertNamesText", R.string.AddMembersAlertNamesText, UserObject.getUserName(currentUser), chatName) )); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); builder.setPositiveButton(asAdmin ? LocaleController.getString("AddAsAdmin", R.string.AddAsAdmin) : LocaleController.getString("AddBot", R.string.AddBot), (di, i) -> { @@ -1301,6 +1402,8 @@ private class ListAdapter extends RecyclerListView.SelectionAdapter { private final int VIEW_TYPE_UNTIL_DATE_CELL = 6; private final int VIEW_TYPE_RANK_CELL = 7; private final int VIEW_TYPE_ADD_BOT_CELL = 8; + private final int VIEW_TYPE_EXPANDABLE_SWITCH = 9; + private final int VIEW_TYPE_INNER_CHECK = 10; private Context mContext; private boolean ignoreTextChange; @@ -1335,7 +1438,7 @@ public long getItemId(int position) { if (position == rankRow) return 18; if (position == rankInfoRow) return 19; if (position == sendMessagesRow) return 20; - if (position == sendMediaRow) return 21; + if (position == sendPhotosRow) return 21; if (position == sendStickersRow) return 22; if (position == sendPollsRow) return 23; if (position == embedLinksRow) return 24; @@ -1344,6 +1447,12 @@ public long getItemId(int position) { if (position == untilDateRow) return 27; if (position == addBotButtonRow) return 28; if (position == manageTopicsRow) return 29; + if (position == sendVideosRow) return 30; + if (position == sendFilesRow) return 31; + if (position == sendMusicRow) return 32; + if (position == sendVoiceRow) return 33; + if (position == sendRoundRow) return 34; + if (position == sendMediaRow) return 35; return 0; } else { return super.getItemId(position); @@ -1421,6 +1530,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType view = new HeaderCell(mContext, Theme.key_windowBackgroundWhiteBlueHeader, 21, 15, true); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; + case VIEW_TYPE_EXPANDABLE_SWITCH: case VIEW_TYPE_SWITCH_CELL: view = new TextCheckCell2(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); @@ -1482,6 +1592,14 @@ public void afterTextChanged(Editable s) { }); view = cell; break; + case VIEW_TYPE_INNER_CHECK: + CheckBoxCell checkBoxCell = new CheckBoxCell(mContext, 4, 21, getResourceProvider()); + checkBoxCell.getCheckBoxRound().setDrawBackgroundAsArc(14); + checkBoxCell.getCheckBoxRound().setColor(Theme.key_switch2TrackChecked, Theme.key_radioBackground, Theme.key_checkboxCheck); + checkBoxCell.setEnabled(true); + view = checkBoxCell; + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; } return new RecyclerListView.Holder(view); } @@ -1489,6 +1607,39 @@ public void afterTextChanged(Editable s) { @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { + case VIEW_TYPE_INNER_CHECK: + CheckBoxCell checkBoxCell = (CheckBoxCell) holder.itemView; + boolean animated = checkBoxCell.getTag() != null && (Integer) checkBoxCell.getTag() == position; + checkBoxCell.setTag(position); + if (position == sendStickersRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionStickersGifs", R.string.SendMediaPermissionStickersGifs), "", !bannedRights.send_stickers && !defaultBannedRights.send_stickers, true, animated); + checkBoxCell.setIcon(defaultBannedRights.send_stickers ? R.drawable.permission_locked : 0); + } else if (position == embedLinksRow) { + checkBoxCell.setText(LocaleController.getString("UserRestrictionsEmbedLinks", R.string.UserRestrictionsEmbedLinks), "", !bannedRights.embed_links && !defaultBannedRights.embed_links && !bannedRights.send_plain && !defaultBannedRights.send_plain, true, animated); + checkBoxCell.setIcon(defaultBannedRights.embed_links ? R.drawable.permission_locked : 0); + } else if (position == sendPollsRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPolls", R.string.SendMediaPolls), "", !bannedRights.send_polls && !defaultBannedRights.send_polls, true, animated); + checkBoxCell.setIcon(defaultBannedRights.send_polls ? R.drawable.permission_locked : 0); + } else if (position == sendPhotosRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionPhotos", R.string.SendMediaPermissionPhotos), "", !bannedRights.send_photos && !defaultBannedRights.send_photos, true, animated); + checkBoxCell.setIcon(defaultBannedRights.send_photos ? R.drawable.permission_locked : 0); + } else if (position == sendVideosRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionVideos", R.string.SendMediaPermissionVideos), "", !bannedRights.send_videos && !defaultBannedRights.send_videos, true, animated); + checkBoxCell.setIcon(defaultBannedRights.send_videos ? R.drawable.permission_locked : 0); + } else if (position == sendMusicRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionMusic", R.string.SendMediaPermissionMusic), "", !bannedRights.send_audios && !defaultBannedRights.send_audios, true, animated); + checkBoxCell.setIcon(defaultBannedRights.send_audios ? R.drawable.permission_locked : 0); + } else if (position == sendFilesRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionFiles", R.string.SendMediaPermissionFiles), "", !bannedRights.send_docs && !defaultBannedRights.send_docs, true, animated); + checkBoxCell.setIcon(defaultBannedRights.send_docs ? R.drawable.permission_locked : 0); + } else if (position == sendVoiceRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionVoice", R.string.SendMediaPermissionVoice), "", !bannedRights.send_voices && !defaultBannedRights.send_voices, true, animated); + checkBoxCell.setIcon(defaultBannedRights.send_voices ? R.drawable.permission_locked : 0); + } else if (position == sendRoundRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionRound", R.string.SendMediaPermissionRound), "", !bannedRights.send_roundvideos && !defaultBannedRights.send_roundvideos, true, animated); + checkBoxCell.setIcon(defaultBannedRights.send_roundvideos ? R.drawable.permission_locked : 0); + } + break; case VIEW_TYPE_USER_CELL: UserCell2 userCell2 = (UserCell2) holder.itemView; String status = null; @@ -1545,11 +1696,30 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { headerCell.setText(LocaleController.getString("EditAdminRank", R.string.EditAdminRank)); } break; + case VIEW_TYPE_EXPANDABLE_SWITCH: case VIEW_TYPE_SWITCH_CELL: TextCheckCell2 checkCell = (TextCheckCell2) holder.itemView; boolean asAdminValue = currentType != TYPE_ADD_BOT || asAdmin; boolean isCreator = (currentChat != null && currentChat.creator); - if (position == manageRow) { + if (position == sendMediaRow) { + int sentMediaCount = getSendMediaSelectedCount(); + checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendMedia", R.string.UserRestrictionsSendMedia), sentMediaCount > 0, true, true); + checkCell.setCollapseArrow(String.format(Locale.US, "%d/9", sentMediaCount), !sendMediaExpanded, () -> { + if (allDefaultMediaBanned()) { + new AlertDialog.Builder(getParentActivity()) + .setTitle(LocaleController.getString("UserRestrictionsCantModify", R.string.UserRestrictionsCantModify)) + .setMessage(LocaleController.getString("UserRestrictionsCantModifyEnabled", R.string.UserRestrictionsCantModifyEnabled)) + .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) + .create() + .show(); + return; + } + boolean checked = !checkCell.isChecked(); + checkCell.setChecked(checked); + setSendMediaEnabled(checked); + }); + checkCell.setIcon(allDefaultMediaBanned() ? R.drawable.permission_locked : 0); + } else if (position == manageRow) { checkCell.setTextAndCheck(LocaleController.getString("ManageGroup", R.string.ManageGroup), asAdmin, true); checkCell.setIcon(myAdminRights.add_admins || isCreator ? 0 : R.drawable.permission_locked); } else if (position == changeInfoRow) { @@ -1640,28 +1810,17 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { checkCell.setIcon(defaultBannedRights.pin_messages ? R.drawable.permission_locked : 0); } } else if (position == sendMessagesRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSend", R.string.UserRestrictionsSend), !bannedRights.send_messages && !defaultBannedRights.send_messages, true); - checkCell.setIcon(defaultBannedRights.send_messages ? R.drawable.permission_locked : 0); - } else if (position == sendMediaRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendMedia", R.string.UserRestrictionsSendMedia), !bannedRights.send_media && !defaultBannedRights.send_media, true); - checkCell.setIcon(defaultBannedRights.send_media ? R.drawable.permission_locked : 0); - } else if (position == sendStickersRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendStickers", R.string.UserRestrictionsSendStickers), !bannedRights.send_stickers && !defaultBannedRights.send_stickers, true); - checkCell.setIcon(defaultBannedRights.send_stickers ? R.drawable.permission_locked : 0); - } else if (position == embedLinksRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsEmbedLinks", R.string.UserRestrictionsEmbedLinks), !bannedRights.embed_links && !defaultBannedRights.embed_links, true); - checkCell.setIcon(defaultBannedRights.embed_links ? R.drawable.permission_locked : 0); - } else if (position == sendPollsRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendPolls", R.string.UserRestrictionsSendPolls), !bannedRights.send_polls && !defaultBannedRights.send_polls, true); - checkCell.setIcon(defaultBannedRights.send_polls ? R.drawable.permission_locked : 0); + checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSend", R.string.UserRestrictionsSend), !bannedRights.send_plain && !defaultBannedRights.send_plain, true); + checkCell.setIcon(defaultBannedRights.send_plain ? R.drawable.permission_locked : 0); } if (currentType == TYPE_ADD_BOT) { // checkCell.setEnabled((asAdmin || position == manageRow) && !checkCell.hasIcon(), false); } else { - if (position == sendMediaRow || position == sendStickersRow || position == embedLinksRow || position == sendPollsRow) { - checkCell.setEnabled(!bannedRights.send_messages && !bannedRights.view_messages && !defaultBannedRights.send_messages && !defaultBannedRights.view_messages); - } else if (position == sendMessagesRow) { +// if (position == sendMediaRow || position == sendStickersRow || position == embedLinksRow || position == sendPollsRow) { +// checkCell.setEnabled(!bannedRights.send_messages && !bannedRights.view_messages && !defaultBannedRights.send_messages && !defaultBannedRights.view_messages); +// } else + if (position == sendMessagesRow) { checkCell.setEnabled(!bannedRights.view_messages && !defaultBannedRights.view_messages); } } @@ -1729,7 +1888,11 @@ public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) { @Override public int getItemViewType(int position) { - if (position == 0) { + if (isExpandableSendMediaRow(position)) { + return VIEW_TYPE_INNER_CHECK; + } else if (position == sendMediaRow) { + return VIEW_TYPE_EXPANDABLE_SWITCH; + } else if (position == 0) { return VIEW_TYPE_USER_CELL; } else if (position == 1 || position == rightsShadowRow || position == removeAdminShadowRow || position == untilSectionRow || position == transferOwnerShadowRow) { return VIEW_TYPE_SHADOW_CELL; @@ -1737,8 +1900,7 @@ public int getItemViewType(int position) { return VIEW_TYPE_HEADER_CELL; } else if (position == changeInfoRow || position == postMessagesRow || position == editMesagesRow || position == deleteMessagesRow || position == addAdminsRow || position == banUsersRow || position == addUsersRow || position == pinMessagesRow || - position == sendMessagesRow || position == sendMediaRow || position == sendStickersRow || position == embedLinksRow || - position == sendPollsRow || position == anonymousRow || position == startVoiceChatRow || position == manageRow || position == manageTopicsRow) { + position == sendMessagesRow || position == anonymousRow || position == startVoiceChatRow || position == manageRow || position == manageTopicsRow) { return VIEW_TYPE_SWITCH_CELL; } else if (position == cantEditInfoRow || position == rankInfoRow) { return VIEW_TYPE_INFO_CELL; @@ -1754,7 +1916,69 @@ public int getItemViewType(int position) { } } + private void setSendMediaEnabled(boolean enabled) { + bannedRights.send_media = !enabled; + bannedRights.send_photos = !enabled; + bannedRights.send_videos = !enabled; + bannedRights.send_stickers = !enabled; + bannedRights.send_audios = !enabled; + bannedRights.send_docs = !enabled; + bannedRights.send_voices = !enabled; + bannedRights.send_roundvideos = !enabled; + bannedRights.embed_links = !enabled; + bannedRights.send_polls = !enabled; + AndroidUtilities.updateVisibleRows(listView); + } + + private int getSendMediaSelectedCount() { + int i = 0; + if (!bannedRights.send_photos && !defaultBannedRights.send_photos) { + i++; + } + if (!bannedRights.send_videos && !defaultBannedRights.send_videos) { + i++; + } + if (!bannedRights.send_stickers && !defaultBannedRights.send_stickers) { + i++; + } + if (!bannedRights.send_audios && !defaultBannedRights.send_audios) { + i++; + } + if (!bannedRights.send_docs && !defaultBannedRights.send_docs) { + i++; + } + if (!bannedRights.send_voices && !defaultBannedRights.send_voices) { + i++; + } + if (!bannedRights.send_roundvideos && !defaultBannedRights.send_roundvideos) { + i++; + } + if (!bannedRights.embed_links && !defaultBannedRights.embed_links && !bannedRights.send_plain && !defaultBannedRights.send_plain) { + i++; + } + if (!bannedRights.send_polls && !defaultBannedRights.send_polls) { + i++; + } + return i; + } + + private boolean allDefaultMediaBanned() { + return defaultBannedRights.send_photos && defaultBannedRights.send_videos && defaultBannedRights.send_stickers + && defaultBannedRights.send_audios && defaultBannedRights.send_docs && defaultBannedRights.send_voices && + defaultBannedRights.send_roundvideos && defaultBannedRights.embed_links && defaultBannedRights.send_polls; + } + + private boolean isExpandableSendMediaRow(int position) { + if (position == sendStickersRow || position == embedLinksRow || position == sendPollsRow || + position == sendPhotosRow || position == sendVideosRow || position == sendFilesRow || + position == sendMusicRow || position == sendRoundRow || position == sendVoiceRow) { + return true; + } + return false; + } + private ValueAnimator asAdminAnimator; + private void updateAsAdmin(boolean animated) { if (addBotButton != null) { addBotButton.invalidate(); @@ -1766,7 +1990,7 @@ private void updateAsAdmin(boolean animated) { if (child instanceof TextCheckCell2) { if (!asAdmin) { if (childPosition == changeInfoRow && !defaultBannedRights.change_info || - childPosition == pinMessagesRow && !defaultBannedRights.pin_messages) { + childPosition == pinMessagesRow && !defaultBannedRights.pin_messages) { ((TextCheckCell2) child).setChecked(true); ((TextCheckCell2) child).setEnabled(false, false); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java index c949e900c58..1417d83f7a3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java @@ -19,7 +19,6 @@ import android.text.Spanned; import android.text.TextUtils; import android.text.style.ForegroundColorSpan; -import android.util.Log; import android.util.SparseIntArray; import android.view.Gravity; import android.view.View; @@ -35,6 +34,7 @@ import androidx.recyclerview.widget.RecyclerView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.ChatObject; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; @@ -54,6 +54,7 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Adapters.SearchAdapterHelper; +import org.telegram.ui.Cells.CheckBoxCell; import org.telegram.ui.Cells.GraySectionCell; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.LoadingCell; @@ -65,6 +66,7 @@ import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.FlickerLoadingView; import org.telegram.ui.Components.GigagroupConvertAlert; import org.telegram.ui.Components.LayoutHelper; @@ -76,10 +78,14 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.Locale; import java.util.concurrent.atomic.AtomicInteger; public class ChatUsersActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + private static final int VIEW_TYPE_INNER_CHECK = 13; + private static final int VIEW_TYPE_EXPANDABLE_SWITCH = 14; + private ListAdapter listViewAdapter; private StickerEmptyView emptyView; private RecyclerListView listView; @@ -113,8 +119,17 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente private int permissionsSectionRow; private int sendMessagesRow; private int sendMediaRow; - private int sendStickersRow; + private int sendMediaPhotosRow; + private int sendMediaVideosRow; + private int sendMediaStickerGifsRow; + private int sendMediaMusicRow; + private int sendMediaFilesRow; + private int sendMediaVoiceMessagesRow; + private int sendMediaVideoMessagesRow; + private int sendMediaEmbededLinksRow; private int sendPollsRow; + + private int sendStickersRow; private int embedLinksRow; private int changeInfoRow; private int addUsersRow; @@ -164,6 +179,8 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente private int delayResults; + private boolean sendMediaExpanded; + private ChatUsersActivityDelegate delegate; private boolean needOpenSearch; @@ -229,6 +246,21 @@ public ChatUsersActivity(Bundle args) { defaultBannedRights.invite_users = currentChat.default_banned_rights.invite_users; defaultBannedRights.manage_topics = currentChat.default_banned_rights.manage_topics; defaultBannedRights.change_info = currentChat.default_banned_rights.change_info; + defaultBannedRights.send_photos = currentChat.default_banned_rights.send_photos; + defaultBannedRights.send_videos = currentChat.default_banned_rights.send_videos; + defaultBannedRights.send_roundvideos = currentChat.default_banned_rights.send_roundvideos; + defaultBannedRights.send_audios = currentChat.default_banned_rights.send_audios; + defaultBannedRights.send_voices = currentChat.default_banned_rights.send_voices; + defaultBannedRights.send_docs = currentChat.default_banned_rights.send_docs; + defaultBannedRights.send_plain = currentChat.default_banned_rights.send_plain; + if (!defaultBannedRights.send_media && defaultBannedRights.send_docs && defaultBannedRights.send_voices && defaultBannedRights.send_audios && defaultBannedRights.send_roundvideos && defaultBannedRights.send_videos && defaultBannedRights.send_photos) { + defaultBannedRights.send_photos = false; + defaultBannedRights.send_videos = false; + defaultBannedRights.send_roundvideos = false; + defaultBannedRights.send_audios = false; + defaultBannedRights.send_voices = false; + defaultBannedRights.send_docs = false; + } } initialBannedRights = ChatObject.getBannedRightsString(defaultBannedRights); isChannel = ChatObject.isChannel(currentChat) && !currentChat.megagroup; @@ -282,15 +314,31 @@ private void updateRows() { loadingProgressRow = -1; loadingUserCellRow = -1; loadingHeaderRow = -1; + sendMediaPhotosRow = -1; + sendMediaVideosRow = -1; + sendMediaStickerGifsRow = -1; + sendMediaMusicRow = -1; + sendMediaFilesRow = -1; + sendMediaVoiceMessagesRow = -1; + sendMediaVideoMessagesRow = -1; + sendMediaEmbededLinksRow = -1; rowCount = 0; if (type == TYPE_KICKED) { permissionsSectionRow = rowCount++; sendMessagesRow = rowCount++; sendMediaRow = rowCount++; - sendStickersRow = rowCount++; - sendPollsRow = rowCount++; - embedLinksRow = rowCount++; + if (sendMediaExpanded) { + sendMediaPhotosRow = rowCount++; + sendMediaVideosRow = rowCount++; + sendMediaStickerGifsRow = rowCount++; + sendMediaMusicRow = rowCount++; + sendMediaFilesRow = rowCount++; + sendMediaVoiceMessagesRow = rowCount++; + sendMediaVideoMessagesRow = rowCount++; + sendMediaEmbededLinksRow = rowCount++; + sendPollsRow = rowCount++; + } addUsersRow = rowCount++; pinMessagesRow = rowCount++; changeInfoRow = rowCount++; @@ -591,7 +639,7 @@ protected void dispatchDraw(Canvas canvas) { emptyView.showProgress(true, false); frameLayout.addView(emptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - emptyView.addView(progressLayout,0); + emptyView.addView(progressLayout, 0); listView = new RecyclerListView(context) { @Override @@ -601,6 +649,14 @@ public void invalidate() { fragmentView.invalidate(); } } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (permissionsSectionRow >= 0 && participantsDivider2Row >= 0) { + drawSectionBackground(canvas, permissionsSectionRow, Math.max(0, participantsDivider2Row - 1), getThemedColor(Theme.key_windowBackgroundWhite)); + } + super.dispatchDraw(canvas); + } }; listView.setLayoutManager(layoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) { @Override @@ -613,31 +669,6 @@ public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerVi }); DefaultItemAnimator itemAnimator = new DefaultItemAnimator() { - @Override - protected long getAddAnimationDelay(long removeDuration, long moveDuration, long changeDuration) { - return 0; - } - - @Override - protected long getMoveAnimationDelay() { - return 0; - } - - @Override - public long getMoveDuration() { - return 220; - } - - @Override - public long getRemoveDuration() { - return 220; - } - - @Override - public long getAddDuration() { - return 220; - } - int animationIndex = -1; @Override @@ -657,7 +688,24 @@ public void runPendingAnimations() { } super.runPendingAnimations(); } + + @Override + protected void onMoveAnimationUpdate(RecyclerView.ViewHolder holder) { + super.onMoveAnimationUpdate(holder); + listView.invalidate(); + } + + @Override + protected void onChangeAnimationUpdate(RecyclerView.ViewHolder holder) { + super.onChangeAnimationUpdate(holder); + listView.invalidate(); + } }; + itemAnimator.setDurations(320); + itemAnimator.setMoveDelay(0); + itemAnimator.setAddDelay(0); + itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + itemAnimator.setDelayAnimations(false); listView.setItemAnimator(itemAnimator); itemAnimator.setSupportsChangeAnimations(false); listView.setAnimateEmptyView(true, RecyclerListView.EMPTY_VIEW_ANIMATION_TYPE_ALPHA); @@ -665,10 +713,42 @@ public void runPendingAnimations() { listView.setVerticalScrollbarPosition(LocaleController.isRTL ? RecyclerListView.SCROLLBAR_POSITION_LEFT : RecyclerListView.SCROLLBAR_POSITION_RIGHT); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - listView.setOnItemClickListener((view, position) -> { + listView.setOnItemClickListener((view, position, x, y) -> { boolean listAdapter = listView.getAdapter() == listViewAdapter; if (listAdapter) { - if (position == addNewRow) { + if (isExpandableSendMediaRow(position)) { + CheckBoxCell checkBoxCell = (CheckBoxCell) view; + if (position == sendMediaPhotosRow) { + defaultBannedRights.send_photos = !defaultBannedRights.send_photos; + } else if (position == sendMediaVideosRow) { + defaultBannedRights.send_videos = !defaultBannedRights.send_videos; + } else if (position == sendMediaStickerGifsRow) { + defaultBannedRights.send_stickers = !defaultBannedRights.send_stickers; + } else if (position == sendMediaMusicRow) { + defaultBannedRights.send_audios = !defaultBannedRights.send_audios; + } else if (position == sendMediaFilesRow) { + defaultBannedRights.send_docs = !defaultBannedRights.send_docs; + } else if (position == sendMediaVoiceMessagesRow) { + defaultBannedRights.send_voices = !defaultBannedRights.send_voices; + } else if (position == sendMediaVideoMessagesRow) { + defaultBannedRights.send_roundvideos = !defaultBannedRights.send_roundvideos; + } else if (position == sendMediaEmbededLinksRow) { + if (defaultBannedRights.send_plain) { + View senMessagesView = layoutManager.findViewByPosition(sendMessagesRow); + if (senMessagesView != null) { + AndroidUtilities.shakeViewSpring(senMessagesView); + BotWebViewVibrationEffect.APP_ERROR.vibrate(); + return; + } + } + defaultBannedRights.embed_links = !defaultBannedRights.embed_links; + } else if (position == sendPollsRow) { + defaultBannedRights.send_polls = !defaultBannedRights.send_polls; + } + + checkBoxCell.setChecked(!checkBoxCell.isChecked(), true); + AndroidUtilities.updateVisibleRows(listView); + } else if (position == addNewRow) { if (type == TYPE_BANNED || type == TYPE_KICKED) { Bundle bundle = new Bundle(); bundle.putLong("chat_id", chatId); @@ -676,6 +756,7 @@ public void runPendingAnimations() { bundle.putInt("selectType", type == TYPE_BANNED ? ChatUsersActivity.SELECT_TYPE_BLOCK : ChatUsersActivity.SELECT_TYPE_EXCEPTION); ChatUsersActivity fragment = new ChatUsersActivity(bundle); fragment.setInfo(info); + fragment.setBannedRights(defaultBannedRights); fragment.setDelegate(new ChatUsersActivityDelegate() { @Override @@ -798,10 +879,10 @@ public void didSelectUsers(ArrayList users, int fwdCount) { description = LocaleController.getString("InviteToGroupErrorMessageMultipleSome", R.string.InviteToGroupErrorMessageMultipleSome); } new AlertDialog.Builder(context) - .setTitle(title) - .setMessage(description) - .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) - .show(); + .setTitle(title) + .setMessage(description) + .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) + .show(); }; for (int a = 0; a < count; a++) { final TLRPC.User user = users.get(a); @@ -977,6 +1058,14 @@ protected void onCancel() { } return; } + if (position == sendMediaRow) { + //defaultBannedRights.send_media = !defaultBannedRights.send_media; + DiffCallback diffCallback = saveState(); + sendMediaExpanded = !sendMediaExpanded; + AndroidUtilities.updateVisibleRows(listView); + updateListAnimated(diffCallback); + return; + } checkCell.setChecked(!checkCell.isChecked()); if (position == changeInfoRow) { defaultBannedRights.change_info = !defaultBannedRights.change_info; @@ -987,11 +1076,19 @@ protected void onCancel() { } else if (position == pinMessagesRow) { defaultBannedRights.pin_messages = !defaultBannedRights.pin_messages; } else { - boolean disabled = !checkCell.isChecked(); if (position == sendMessagesRow) { - defaultBannedRights.send_messages = !defaultBannedRights.send_messages; + defaultBannedRights.send_plain = !defaultBannedRights.send_plain; + if (sendMediaEmbededLinksRow >= 0) { + listViewAdapter.notifyItemChanged(sendMediaEmbededLinksRow); + } + if (sendMediaRow >= 0) { + listViewAdapter.notifyItemChanged(sendMediaRow); + } } else if (position == sendMediaRow) { - defaultBannedRights.send_media = !defaultBannedRights.send_media; + DiffCallback diffCallback = saveState(); + sendMediaExpanded = !sendMediaExpanded; + AndroidUtilities.updateVisibleRows(listView); + updateListAnimated(diffCallback); } else if (position == sendStickersRow) { defaultBannedRights.send_stickers = defaultBannedRights.send_games = defaultBannedRights.send_gifs = defaultBannedRights.send_inline = !defaultBannedRights.send_stickers; } else if (position == embedLinksRow) { @@ -999,51 +1096,6 @@ protected void onCancel() { } else if (position == sendPollsRow) { defaultBannedRights.send_polls = !defaultBannedRights.send_polls; } - if (disabled) { - if (defaultBannedRights.view_messages && !defaultBannedRights.send_messages) { - defaultBannedRights.send_messages = true; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(sendMessagesRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(false); - } - } - if ((defaultBannedRights.view_messages || defaultBannedRights.send_messages) && !defaultBannedRights.send_media) { - defaultBannedRights.send_media = true; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(sendMediaRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(false); - } - } - if ((defaultBannedRights.view_messages || defaultBannedRights.send_messages) && !defaultBannedRights.send_polls) { - defaultBannedRights.send_polls = true; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(sendPollsRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(false); - } - } - if ((defaultBannedRights.view_messages || defaultBannedRights.send_messages) && !defaultBannedRights.send_stickers) { - defaultBannedRights.send_stickers = defaultBannedRights.send_games = defaultBannedRights.send_gifs = defaultBannedRights.send_inline = true; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(sendStickersRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(false); - } - } - if ((defaultBannedRights.view_messages || defaultBannedRights.send_messages) && !defaultBannedRights.embed_links) { - defaultBannedRights.embed_links = true; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(embedLinksRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(false); - } - } - } else { - if ((!defaultBannedRights.embed_links || !defaultBannedRights.send_inline || !defaultBannedRights.send_media || !defaultBannedRights.send_polls) && defaultBannedRights.send_messages) { - defaultBannedRights.send_messages = false; - RecyclerListView.ViewHolder holder = listView.findViewHolderForAdapterPosition(sendMessagesRow); - if (holder != null) { - ((TextCheckCell2) holder.itemView).setChecked(true); - } - } - } } return; } @@ -1070,8 +1122,8 @@ protected void onCancel() { if (adminRights == null) { adminRights = new TLRPC.TL_chatAdminRights(); adminRights.change_info = adminRights.post_messages = adminRights.edit_messages = - adminRights.delete_messages = adminRights.ban_users = adminRights.invite_users = - adminRights.manage_topics = adminRights.pin_messages = adminRights.add_admins = true; + adminRights.delete_messages = adminRights.ban_users = adminRights.invite_users = + adminRights.manage_topics = adminRights.pin_messages = adminRights.add_admins = true; if (!isChannel) { adminRights.manage_call = true; } @@ -1084,8 +1136,8 @@ protected void onCancel() { if (participant instanceof TLRPC.TL_chatParticipantCreator) { adminRights = new TLRPC.TL_chatAdminRights(); adminRights.change_info = adminRights.post_messages = adminRights.edit_messages = - adminRights.delete_messages = adminRights.ban_users = adminRights.invite_users = - adminRights.manage_topics = adminRights.pin_messages = adminRights.add_admins = true; + adminRights.delete_messages = adminRights.ban_users = adminRights.invite_users = + adminRights.manage_topics = adminRights.pin_messages = adminRights.add_admins = true; if (!isChannel) { adminRights.manage_call = true; } @@ -1164,7 +1216,14 @@ protected void onCancel() { bannedRights.view_messages = true; bannedRights.send_stickers = true; bannedRights.send_media = true; + bannedRights.send_photos = true; + bannedRights.send_videos = true; + bannedRights.send_roundvideos = true; + bannedRights.send_audios = true; + bannedRights.send_voices = true; + bannedRights.send_docs = true; bannedRights.embed_links = true; + bannedRights.send_plain = true; bannedRights.send_messages = true; bannedRights.send_games = true; bannedRights.send_inline = true; @@ -1231,6 +1290,12 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { return fragmentView; } + private void setBannedRights(TLRPC.TL_chatBannedRights defaultBannedRights) { + if (defaultBannedRights != null) { + this.defaultBannedRights = defaultBannedRights; + } + } + private void sortAdmins(ArrayList participants) { Collections.sort(participants, (lhs, rhs) -> { int type1 = getChannelAdminParticipantType(lhs); @@ -1356,8 +1421,8 @@ private void onOwnerChaged(TLRPC.User user) { admin.date = (int) (System.currentTimeMillis() / 1000); admin.admin_rights = new TLRPC.TL_chatAdminRights(); admin.admin_rights.change_info = admin.admin_rights.post_messages = admin.admin_rights.edit_messages = - admin.admin_rights.delete_messages = admin.admin_rights.ban_users = admin.admin_rights.invite_users = - admin.admin_rights.manage_topics = admin.admin_rights.pin_messages = admin.admin_rights.add_admins = true; + admin.admin_rights.delete_messages = admin.admin_rights.ban_users = admin.admin_rights.invite_users = + admin.admin_rights.manage_topics = admin.admin_rights.pin_messages = admin.admin_rights.add_admins = true; if (!isChannel) { admin.admin_rights.manage_call = true; } @@ -1808,7 +1873,7 @@ public void didChangeOwner(TLRPC.User user) { }); presentFragment(fragment); } else { - getMessagesController().setUserAdminRole(chatId, getMessagesController().getUser(peerId), new TLRPC.TL_chatAdminRights(), "", !isChannel, ChatUsersActivity.this, false, false, null,null); + getMessagesController().setUserAdminRole(chatId, getMessagesController().getUser(peerId), new TLRPC.TL_chatAdminRights(), "", !isChannel, ChatUsersActivity.this, false, false, null, null); removeParticipants(peerId); } } else if (type == TYPE_BANNED || type == TYPE_KICKED) { @@ -1985,17 +2050,54 @@ private String formatUserPermissions(TLRPC.TL_chatBannedRights rights) { if (rights.view_messages && defaultBannedRights.view_messages != rights.view_messages) { builder.append(LocaleController.getString("UserRestrictionsNoRead", R.string.UserRestrictionsNoRead)); } - if (rights.send_messages && defaultBannedRights.send_messages != rights.send_messages) { + if (rights.send_messages && defaultBannedRights.send_plain != rights.send_plain) { if (builder.length() != 0) { builder.append(", "); } - builder.append(LocaleController.getString("UserRestrictionsNoSend", R.string.UserRestrictionsNoSend)); + builder.append(LocaleController.getString("UserRestrictionsNoSendText", R.string.UserRestrictionsNoSendText)); } if (rights.send_media && defaultBannedRights.send_media != rights.send_media) { if (builder.length() != 0) { builder.append(", "); } builder.append(LocaleController.getString("UserRestrictionsNoSendMedia", R.string.UserRestrictionsNoSendMedia)); + } else { + if (rights.send_photos && defaultBannedRights.send_photos != rights.send_photos) { + if (builder.length() != 0) { + builder.append(", "); + } + builder.append(LocaleController.getString("UserRestrictionsNoSendPhotos", R.string.UserRestrictionsNoSendPhotos)); + } + if (rights.send_videos && defaultBannedRights.send_videos != rights.send_videos) { + if (builder.length() != 0) { + builder.append(", "); + } + builder.append(LocaleController.getString("UserRestrictionsNoSendVideos", R.string.UserRestrictionsNoSendVideos)); + } + if (rights.send_audios && defaultBannedRights.send_audios != rights.send_audios) { + if (builder.length() != 0) { + builder.append(", "); + } + builder.append(LocaleController.getString("UserRestrictionsNoSendMusic", R.string.UserRestrictionsNoSendMusic)); + } + if (rights.send_docs && defaultBannedRights.send_docs != rights.send_docs) { + if (builder.length() != 0) { + builder.append(", "); + } + builder.append(LocaleController.getString("UserRestrictionsNoSendDocs", R.string.UserRestrictionsNoSendDocs)); + } + if (rights.send_voices && defaultBannedRights.send_voices != rights.send_voices) { + if (builder.length() != 0) { + builder.append(", "); + } + builder.append(LocaleController.getString("UserRestrictionsNoSendVoice", R.string.UserRestrictionsNoSendVoice)); + } + if (rights.send_roundvideos && defaultBannedRights.send_roundvideos != rights.send_roundvideos) { + if (builder.length() != 0) { + builder.append(", "); + } + builder.append(LocaleController.getString("UserRestrictionsNoSendRound", R.string.UserRestrictionsNoSendRound)); + } } if (rights.send_stickers && defaultBannedRights.send_stickers != rights.send_stickers) { if (builder.length() != 0) { @@ -2009,7 +2111,7 @@ private String formatUserPermissions(TLRPC.TL_chatBannedRights rights) { } builder.append(LocaleController.getString("UserRestrictionsNoSendPolls", R.string.UserRestrictionsNoSendPolls)); } - if (rights.embed_links && defaultBannedRights.embed_links != rights.embed_links) { + if (rights.embed_links && !rights.send_plain && defaultBannedRights.embed_links != rights.embed_links) { if (builder.length() != 0) { builder.append(", "); } @@ -2087,7 +2189,7 @@ private int getChannelAdminParticipantType(TLObject participant) { return 0; } else if (participant instanceof TLRPC.TL_channelParticipantAdmin || participant instanceof TLRPC.TL_channelParticipant) { return 1; - } else { + } else { return 2; } } @@ -2937,7 +3039,7 @@ public ListAdapter(Context context) { @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { int viewType = holder.getItemViewType(); - if (viewType == 7) { + if (viewType == 7 || viewType == VIEW_TYPE_EXPANDABLE_SWITCH) { return ChatObject.canBlockUsers(currentChat); } else if (viewType == 0) { ManageChatUserCell cell = (ManageChatUserCell) holder.itemView; @@ -2961,6 +3063,9 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { return ChatObject.canUserDoAdminAction(currentChat, ChatObject.ACTION_BLOCK_USERS); } } + if (viewType == VIEW_TYPE_INNER_CHECK) { + return true; + } return false; } @@ -3015,6 +3120,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType view = new TextSettingsCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; + case VIEW_TYPE_EXPANDABLE_SWITCH: case 7: view = new TextCheckCell2(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); @@ -3048,23 +3154,31 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType view = chooseView; chooseView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); chooseView.setOptions( - selectedSlowmode, - LocaleController.getString("SlowmodeOff", R.string.SlowmodeOff), - LocaleController.formatString("SlowmodeSeconds", R.string.SlowmodeSeconds, 10), - LocaleController.formatString("SlowmodeSeconds", R.string.SlowmodeSeconds, 30), - LocaleController.formatString("SlowmodeMinutes", R.string.SlowmodeMinutes, 1), - LocaleController.formatString("SlowmodeMinutes", R.string.SlowmodeMinutes, 5), - LocaleController.formatString("SlowmodeMinutes", R.string.SlowmodeMinutes, 15), - LocaleController.formatString("SlowmodeHours", R.string.SlowmodeHours, 1) + selectedSlowmode, + LocaleController.getString("SlowmodeOff", R.string.SlowmodeOff), + LocaleController.formatString("SlowmodeSeconds", R.string.SlowmodeSeconds, 10), + LocaleController.formatString("SlowmodeSeconds", R.string.SlowmodeSeconds, 30), + LocaleController.formatString("SlowmodeMinutes", R.string.SlowmodeMinutes, 1), + LocaleController.formatString("SlowmodeMinutes", R.string.SlowmodeMinutes, 5), + LocaleController.formatString("SlowmodeMinutes", R.string.SlowmodeMinutes, 15), + LocaleController.formatString("SlowmodeHours", R.string.SlowmodeHours, 1) ); chooseView.setCallback(which -> { if (info == null) { return; } selectedSlowmode = which; -// listViewAdapter.notifyItemChanged(slowmodeInfoRow); + listViewAdapter.notifyItemChanged(slowmodeInfoRow); }); break; + case VIEW_TYPE_INNER_CHECK: + CheckBoxCell checkBoxCell = new CheckBoxCell(mContext, 4, 21, getResourceProvider()); + checkBoxCell.getCheckBoxRound().setDrawBackgroundAsArc(14); + checkBoxCell.getCheckBoxRound().setColor(Theme.key_switch2TrackChecked, Theme.key_radioBackground, Theme.key_checkboxCheck); + checkBoxCell.setEnabled(true); + view = checkBoxCell; + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; } return new RecyclerListView.Holder(view); } @@ -3276,32 +3390,39 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { TextSettingsCell settingsCell = (TextSettingsCell) holder.itemView; settingsCell.setTextAndValue(LocaleController.getString("ChannelBlacklist", R.string.ChannelBlacklist), String.format("%d", info != null ? info.kicked_count : 0), false); break; + case VIEW_TYPE_EXPANDABLE_SWITCH: case 7: TextCheckCell2 checkCell = (TextCheckCell2) holder.itemView; + boolean animated = checkCell.getTag() != null && (Integer) checkCell.getTag() == position; + checkCell.setTag(position); if (position == changeInfoRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsChangeInfo", R.string.UserRestrictionsChangeInfo), !defaultBannedRights.change_info && !ChatObject.isPublic(currentChat), manageTopicsRow != -1); + checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsChangeInfo", R.string.UserRestrictionsChangeInfo), !defaultBannedRights.change_info && !ChatObject.isPublic(currentChat), manageTopicsRow != -1, animated); } else if (position == addUsersRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsInviteUsers", R.string.UserRestrictionsInviteUsers), !defaultBannedRights.invite_users, true); + checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsInviteUsers", R.string.UserRestrictionsInviteUsers), !defaultBannedRights.invite_users, true, animated); } else if (position == pinMessagesRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsPinMessages", R.string.UserRestrictionsPinMessages), !defaultBannedRights.pin_messages && !ChatObject.isPublic(currentChat), true); + checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsPinMessages", R.string.UserRestrictionsPinMessages), !defaultBannedRights.pin_messages && !ChatObject.isPublic(currentChat), true, animated); } else if (position == sendMessagesRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSend", R.string.UserRestrictionsSend), !defaultBannedRights.send_messages, true); + checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendText", R.string.UserRestrictionsSendText), !defaultBannedRights.send_plain, true, animated); } else if (position == sendMediaRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendMedia", R.string.UserRestrictionsSendMedia), !defaultBannedRights.send_media, true); + int sentMediaCount = getSendMediaSelectedCount(); + checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendMedia", R.string.UserRestrictionsSendMedia), sentMediaCount > 0, true, animated); + checkCell.setCollapseArrow(String.format(Locale.US, "%d/9", sentMediaCount), !sendMediaExpanded, new Runnable() { + @Override + public void run() { + boolean checked = !checkCell.isChecked(); + checkCell.setChecked(checked); + setSendMediaEnabled(checked); + + } + }); } else if (position == sendStickersRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendStickers", R.string.UserRestrictionsSendStickers), !defaultBannedRights.send_stickers, true); + checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendStickers", R.string.UserRestrictionsSendStickers), !defaultBannedRights.send_stickers, true, animated); } else if (position == embedLinksRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsEmbedLinks", R.string.UserRestrictionsEmbedLinks), !defaultBannedRights.embed_links, true); + checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsEmbedLinks", R.string.UserRestrictionsEmbedLinks), !defaultBannedRights.embed_links, true, animated); } else if (position == sendPollsRow) { - checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendPolls", R.string.UserRestrictionsSendPolls), !defaultBannedRights.send_polls, true); + checkCell.setTextAndCheck(LocaleController.getString("UserRestrictionsSendPollsShort", R.string.UserRestrictionsSendPollsShort), !defaultBannedRights.send_polls, true); } else if (position == manageTopicsRow) { - checkCell.setTextAndCheck(LocaleController.getString("CreateTopicsPermission", R.string.CreateTopicsPermission), !defaultBannedRights.manage_topics, false); - } - - if (position == sendMediaRow || position == sendStickersRow || position == embedLinksRow || position == sendPollsRow) { - checkCell.setEnabled(!defaultBannedRights.send_messages && !defaultBannedRights.view_messages); - } else if (position == sendMessagesRow) { - checkCell.setEnabled(!defaultBannedRights.view_messages); + checkCell.setTextAndCheck(LocaleController.getString("CreateTopicsPermission", R.string.CreateTopicsPermission), !defaultBannedRights.manage_topics, false, animated); } if (ChatObject.canBlockUsers(currentChat)) { if (position == addUsersRow && !ChatObject.canUserDoAdminAction(currentChat, ChatObject.ACTION_INVITE) || @@ -3355,6 +3476,32 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { textCell.setTextAndCheck(LocaleController.getString("ChannelHideMembers", R.string.ChannelHideMembers), info != null && info.participants_hidden, false); } break; + case VIEW_TYPE_INNER_CHECK: + CheckBoxCell checkBoxCell = (CheckBoxCell) holder.itemView; + animated = checkBoxCell.getTag() != null && (Integer) checkBoxCell.getTag() == position; + checkBoxCell.setTag(position); + if (position == sendMediaPhotosRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionPhotos", R.string.SendMediaPermissionPhotos), "", !defaultBannedRights.send_photos, true, animated); + } else if (position == sendMediaVideosRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionVideos", R.string.SendMediaPermissionVideos), "", !defaultBannedRights.send_videos, true, animated); + } else if (position == sendMediaStickerGifsRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionStickersGifs", R.string.SendMediaPermissionStickersGifs), "", !defaultBannedRights.send_stickers, true, animated); + } else if (position == sendMediaMusicRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionMusic", R.string.SendMediaPermissionMusic), "", !defaultBannedRights.send_audios, true, animated); + } else if (position == sendMediaFilesRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionFiles", R.string.SendMediaPermissionFiles), "", !defaultBannedRights.send_docs, true, animated); + } else if (position == sendMediaVoiceMessagesRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionVoice", R.string.SendMediaPermissionVoice), "", !defaultBannedRights.send_voices, true, animated); + } else if (position == sendMediaVideoMessagesRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPermissionRound", R.string.SendMediaPermissionRound), "", !defaultBannedRights.send_roundvideos, true, animated); + } else if (position == sendMediaEmbededLinksRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaEmbededLinks", R.string.SendMediaEmbededLinks), "", !defaultBannedRights.embed_links && !defaultBannedRights.send_plain, false, animated); + }else if (position == sendPollsRow) { + checkBoxCell.setText(LocaleController.getString("SendMediaPolls", R.string.SendMediaPolls), "", !defaultBannedRights.send_polls, false, animated); + } + // checkBoxCell.setText(getCheckBoxTitle(item.headerName, percents[item.index < 0 ? 8 : item.index], item.index < 0), AndroidUtilities.formatFileSize(item.size), selected, item.index < 0 ? !collapsed : !item.last); + checkBoxCell.setPad(1); + break; } } @@ -3384,7 +3531,7 @@ public int getItemViewType(int position) { } else if (position == removedUsersRow) { return 6; } else if (position == changeInfoRow || position == addUsersRow || position == pinMessagesRow || position == sendMessagesRow || - position == sendMediaRow || position == sendStickersRow || position == embedLinksRow || position == sendPollsRow || position == manageTopicsRow) { + position == sendStickersRow || position == embedLinksRow || position == manageTopicsRow) { return 7; } else if (position == membersHeaderRow || position == contactsHeaderRow || position == botHeaderRow || position == loadingHeaderRow) { return 8; @@ -3396,6 +3543,10 @@ public int getItemViewType(int position) { return 11; } else if (position == antiSpamRow || position == hideMembersRow) { return 12; + } else if (isExpandableSendMediaRow(position)) { + return VIEW_TYPE_INNER_CHECK; + } else if (position == sendMediaRow) { + return VIEW_TYPE_EXPANDABLE_SWITCH; } return 0; } @@ -3412,6 +3563,26 @@ public TLObject getItem(int position) { } } + private void setSendMediaEnabled(boolean enabled) { + defaultBannedRights.send_media = !enabled; + defaultBannedRights.send_photos = !enabled; + defaultBannedRights.send_videos = !enabled; + defaultBannedRights.send_stickers = !enabled; + defaultBannedRights.send_audios = !enabled; + defaultBannedRights.send_docs = !enabled; + defaultBannedRights.send_voices = !enabled; + defaultBannedRights.send_roundvideos = !enabled; + defaultBannedRights.embed_links = !enabled; + defaultBannedRights.send_polls = !enabled; + AndroidUtilities.updateVisibleRows(listView); + } + + private boolean isExpandableSendMediaRow(int position) { + return position == sendMediaPhotosRow || position == sendMediaVideosRow || position == sendMediaStickerGifsRow || + position == sendMediaMusicRow || position == sendMediaFilesRow || position == sendMediaVoiceMessagesRow || + position == sendMediaVideoMessagesRow || position == sendMediaEmbededLinksRow || position == sendPollsRow; + } + public DiffCallback saveState() { DiffCallback diffCallback = new DiffCallback(); diffCallback.oldRowCount = rowCount; @@ -3555,6 +3726,42 @@ private void put(int id, int position, SparseIntArray sparseIntArray) { } } + private int getSendMediaSelectedCount() { + return getSendMediaSelectedCount(defaultBannedRights); + } + + public static int getSendMediaSelectedCount(TLRPC.TL_chatBannedRights bannedRights) { + int i = 0; + if (!bannedRights.send_photos) { + i++; + } + if (!bannedRights.send_videos) { + i++; + } + if (!bannedRights.send_stickers) { + i++; + } + if (!bannedRights.send_audios) { + i++; + } + if (!bannedRights.send_docs) { + i++; + } + if (!bannedRights.send_voices) { + i++; + } + if (!bannedRights.send_roundvideos) { + i++; + } + if (!bannedRights.embed_links && !bannedRights.send_plain) { + i++; + } + if (!bannedRights.send_polls) { + i++; + } + return i; + } + @Override public ArrayList getThemeDescriptions() { ArrayList themeDescriptions = new ArrayList<>(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatsWidgetConfigActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatsWidgetConfigActivity.java index 5698a6d7404..bc87d74f8ef 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatsWidgetConfigActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatsWidgetConfigActivity.java @@ -23,7 +23,7 @@ protected boolean handleIntent(Intent intent, boolean isNew, boolean restore, bo if (creatingAppWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 10); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_WIDGET); args.putBoolean("allowSwitchAccount", true); EditWidgetActivity fragment = new EditWidgetActivity(EditWidgetActivity.TYPE_CHATS, creatingAppWidgetId); fragment.setDelegate(dialogs -> { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java index 69dd43c58c4..350de26fd02 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java @@ -171,6 +171,7 @@ public static Dialog createBackgroundActivityDialog(Context ctx) { } }) .setNegativeButton(LocaleController.getString("ContactsPermissionAlertNotNow", R.string.ContactsPermissionAlertNotNow), null) + .setOnDismissListener(dialog -> SharedConfig.BackgroundActivityPrefs.increaseDismissedCount()) .create(); } @@ -348,16 +349,69 @@ public static Dialog processError(int currentAccount, TLRPC.TL_error error, Base request instanceof TLRPC.TL_messages_forwardMessages || request instanceof TLRPC.TL_messages_sendMultiMedia || request instanceof TLRPC.TL_messages_sendScheduledMessages) { - switch (error.text) { - case "PEER_FLOOD": - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.needShowAlert, 0); - break; - case "USER_BANNED_IN_CHANNEL": - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.needShowAlert, 5); - break; - case "SCHEDULE_TOO_MUCH": - showSimpleToast(fragment, LocaleController.getString("MessageScheduledLimitReached", R.string.MessageScheduledLimitReached)); - break; + long dialogId = 0; + if (request instanceof TLRPC.TL_messages_sendMessage) { + dialogId = DialogObject.getPeerDialogId(((TLRPC.TL_messages_sendMessage) request).peer); + } else if (request instanceof TLRPC.TL_messages_sendMedia) { + dialogId = DialogObject.getPeerDialogId(((TLRPC.TL_messages_sendMedia) request).peer); + } else if (request instanceof TLRPC.TL_messages_sendInlineBotResult) { + dialogId = DialogObject.getPeerDialogId(((TLRPC.TL_messages_sendInlineBotResult) request).peer); + } else if (request instanceof TLRPC.TL_messages_forwardMessages) { + dialogId = DialogObject.getPeerDialogId(((TLRPC.TL_messages_forwardMessages) request).to_peer); + } else if (request instanceof TLRPC.TL_messages_sendMultiMedia) { + dialogId = DialogObject.getPeerDialogId(((TLRPC.TL_messages_sendMultiMedia) request).peer); + } else if (request instanceof TLRPC.TL_messages_sendScheduledMessages) { + dialogId = DialogObject.getPeerDialogId(((TLRPC.TL_messages_sendScheduledMessages) request).peer); + } + if (BuildVars.DEBUG_VERSION && error.text != null && error.text.startsWith("CHAT_SEND_") && error.text.endsWith("FORBIDDEN")) { + String errorText = error.text; + TLRPC.Chat chat = dialogId < 0 ? MessagesController.getInstance(currentAccount).getChat(-dialogId) : null; + switch (error.text) { + case "CHAT_SEND_PLAIN_FORBIDDEN": + errorText = ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_PLAIN); + break; + case "CHAT_SEND_PHOTOS_FORBIDDEN": + errorText = ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_PHOTO); + break; + case "CHAT_SEND_VIDEOS_FORBIDDEN": + errorText = ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_VIDEO); + break; + case "CHAT_SEND_ROUNDVIDEOS_FORBIDDEN": + errorText = ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_ROUND); + break; + case "CHAT_SEND_DOCS_FORBIDDEN": + errorText = ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_DOCUMENTS); + break; + case "CHAT_SEND_VOICES_FORBIDDEN": + errorText = ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_VOICE); + break; + case "CHAT_SEND_AUDIOS_FORBIDDEN": + errorText = ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_MUSIC); + break; + case "CHAT_SEND_STICKERS_FORBIDDEN": + errorText = ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_STICKERS); + break; + case "CHAT_SEND_GIFS_FORBIDDEN": + errorText = ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_GIFS); + break; + case "CHAT_SEND_POLL_FORBIDDEN": + errorText = ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_POLLS); + break; + + } + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_ERROR, errorText); + } else { + switch (error.text) { + case "PEER_FLOOD": + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.needShowAlert, 0); + break; + case "USER_BANNED_IN_CHANNEL": + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.needShowAlert, 5); + break; + case "SCHEDULE_TOO_MUCH": + showSimpleToast(fragment, LocaleController.getString("MessageScheduledLimitReached", R.string.MessageScheduledLimitReached)); + break; + } } } else if (request instanceof TLRPC.TL_messages_importChatInvite) { if (error.text.startsWith("FLOOD_WAIT")) { @@ -746,7 +800,6 @@ public static void showBlockReportSpamReplyAlert(ChatActivity fragment, MessageO cells[num].setChecked(!cells[num].isChecked(), true); }); - builder.setCustomViewOffset(12); builder.setView(linearLayout); builder.setPositiveButton(LocaleController.getString("BlockAndDeleteReplies", R.string.BlockAndDeleteReplies), (dialogInterface, i) -> { @@ -823,7 +876,6 @@ public static void showBlockReportSpamAlert(BaseFragment fragment, long dialog_i cells[num].setChecked(!cells[num].isChecked(), true); }); } - builder.setCustomViewOffset(12); builder.setView(linearLayout); } else { cells = null; @@ -1381,6 +1433,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } } }; + builder.setCustomViewOffset(6); builder.setView(frameLayout); AvatarDrawable avatarDrawable = new AvatarDrawable(); @@ -4119,6 +4172,30 @@ public static void showSendMediaAlert(int result, final BaseFragment fragment, T builder.setMessage(LocaleController.getString("ErrorSendRestrictedPrivacyVoiceMessages", R.string.ErrorSendRestrictedPrivacyVoiceMessages)); } else if (result == 8) { builder.setMessage(LocaleController.getString("ErrorSendRestrictedPrivacyVideoMessages", R.string.ErrorSendRestrictedPrivacyVideoMessages)); + } else if (result == 9) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedPrivacyVideo", R.string.ErrorSendRestrictedVideoAll)); + } else if (result == 10) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedPrivacyPhoto", R.string.ErrorSendRestrictedPhotoAll)); + } else if (result == 11) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedVideo", R.string.ErrorSendRestrictedVideo)); + } else if (result == 12) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedPhoto", R.string.ErrorSendRestrictedPhoto)); + } else if (result == 13) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedVoiceAll", R.string.ErrorSendRestrictedVoiceAll)); + } else if (result == 14) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedVoice", R.string.ErrorSendRestrictedVoice)); + } else if (result == 15) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedRoundAll", R.string.ErrorSendRestrictedRoundAll)); + } else if (result == 16) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedRound", R.string.ErrorSendRestrictedRound)); + } else if (result == 17) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedDocumentsAll", R.string.ErrorSendRestrictedDocumentsAll)); + } else if (result == 18) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedDocuments", R.string.ErrorSendRestrictedDocuments)); + } else if (result == 19) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedMusicAll", R.string.ErrorSendRestrictedMusicAll)); + } else if (result == 20) { + builder.setMessage(LocaleController.getString("ErrorSendRestrictedMusic", R.string.ErrorSendRestrictedMusic)); } builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java index 75729d73954..3ca5453b81b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java @@ -61,6 +61,9 @@ public class AnimatedEmojiDrawable extends Drawable { public static final int CACHE_TYPE_FORUM_TOPIC = 10; public static final int CACHE_TYPE_FORUM_TOPIC_LARGE = 11; public static final int CACHE_TYPE_RENDERING_VIDEO = 12; + public static final int CACHE_TYPE_ALERT_PREVIEW_STATIC = 13; + public static final int CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW = 14; + public static final int CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW2 = 15; public int rawDrawIndex; @@ -163,7 +166,9 @@ public void fetchDocument(long id, ReceivedDocument onDone) { if (emojiDocumentsCache != null) { TLRPC.Document cacheDocument = emojiDocumentsCache.get(id); if (cacheDocument != null) { - onDone.run(cacheDocument); + if (onDone != null) { + onDone.run(cacheDocument); + } return; } } @@ -171,19 +176,18 @@ public void fetchDocument(long id, ReceivedDocument onDone) { if (!checkThread()) { return; } - if (onDone != null) { - if (loadingDocuments == null) { - loadingDocuments = new HashMap<>(); - } - ArrayList callbacks = loadingDocuments.get(id); - if (callbacks != null) { - callbacks.add(onDone); - return; - } - callbacks = new ArrayList<>(1); + if (loadingDocuments == null) { + loadingDocuments = new HashMap<>(); + } + ArrayList callbacks = loadingDocuments.get(id); + if (callbacks != null) { callbacks.add(onDone); - loadingDocuments.put(id, callbacks); + return; } + callbacks = new ArrayList<>(1); + callbacks.add(onDone); + loadingDocuments.put(id, callbacks); + if (toFetchDocuments == null) { toFetchDocuments = new HashSet<>(); } @@ -312,7 +316,10 @@ public void processDocuments(ArrayList documents) { ArrayList loadingCallbacks = loadingDocuments.remove(document.id); if (loadingCallbacks != null) { for (int j = 0; j < loadingCallbacks.size(); ++j) { - loadingCallbacks.get(j).run(document); + ReceivedDocument callback = loadingCallbacks.get(j); + if (callback != null) { + callback.run(document); + } } loadingCallbacks.clear(); } @@ -413,6 +420,8 @@ private void updateSize() { sizedp = (int) ((Math.abs(Theme.chat_msgTextPaintEmoji[2].ascent()) + Math.abs(Theme.chat_msgTextPaintEmoji[2].descent())) * 1.15f / AndroidUtilities.density); } else if (this.cacheType == STANDARD_LOTTIE_FRAME) { sizedp = (int) ((Math.abs(Theme.chat_msgTextPaintEmoji[0].ascent()) + Math.abs(Theme.chat_msgTextPaintEmoji[0].descent())) * 1.15f / AndroidUtilities.density); + } else if (cacheType == CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW || cacheType == CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW2) { + sizedp = 100; } else { sizedp = 34; } @@ -459,15 +468,17 @@ protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, b } imageReceiver.setVideoThumbIsSame(true); boolean onlyStaticPreview = SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_LOW && (cacheType == CACHE_TYPE_KEYBOARD || cacheType == CACHE_TYPE_ALERT_PREVIEW || cacheType == CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP); - + if (cacheType == CACHE_TYPE_ALERT_PREVIEW_STATIC) { + onlyStaticPreview = true; + } String filter = sizedp + "_" + sizedp; if (cacheType == CACHE_TYPE_RENDERING_VIDEO) { filter += "_d_nostream"; } - if (cacheType != STANDARD_LOTTIE_FRAME && (cacheType != CACHE_TYPE_MESSAGES_LARGE || SharedConfig.getDevicePerformanceClass() < SharedConfig.PERFORMANCE_CLASS_HIGH) && cacheType != CACHE_TYPE_RENDERING_VIDEO) { + if (cacheType != CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW2 && cacheType != CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW && cacheType != STANDARD_LOTTIE_FRAME && (cacheType != CACHE_TYPE_MESSAGES_LARGE || SharedConfig.getDevicePerformanceClass() < SharedConfig.PERFORMANCE_CLASS_HIGH) && cacheType != CACHE_TYPE_RENDERING_VIDEO) { filter += "_pcache"; } - if (cacheType != CACHE_TYPE_MESSAGES && cacheType != CACHE_TYPE_MESSAGES_LARGE) { + if (cacheType != CACHE_TYPE_MESSAGES && cacheType != CACHE_TYPE_MESSAGES_LARGE && cacheType != CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW && cacheType != CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW2) { filter += "_compress"; } if (cacheType == STANDARD_LOTTIE_FRAME) { @@ -481,8 +492,7 @@ protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, b if ("video/webm".equals(document.mime_type)) { mediaLocation = ImageLocation.getForDocument(document); mediaFilter = filter + "_" + ImageLoader.AUTOPLAY_FILTER; - SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(document.thumbs, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f); - thumbDrawable = svgThumb; + thumbDrawable = DocumentObject.getSvgThumb(document.thumbs, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f); } else if ("application/x-tgsticker".equals(document.mime_type)) { String probableCacheKey = (cacheType != 0 ? cacheType + "_" : "") + documentId + "@" + filter; if (SharedConfig.getDevicePerformanceClass() != SharedConfig.PERFORMANCE_CLASS_LOW || (cacheType == CACHE_TYPE_KEYBOARD || !ImageLoader.getInstance().hasLottieMemCache(probableCacheKey))) { @@ -524,13 +534,9 @@ protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, b } - if (cacheType == CACHE_TYPE_EMOJI_STATUS || cacheType == CACHE_TYPE_ALERT_EMOJI_STATUS || cacheType == CACHE_TYPE_FORUM_TOPIC) { - imageReceiver.setAutoRepeatCount(2); - } else if (cacheType == CACHE_TYPE_FORUM_TOPIC_LARGE) { - imageReceiver.setAutoRepeatCount(1); - } + updateAutoRepeat(imageReceiver); - if (cacheType == CACHE_TYPE_ALERT_PREVIEW || cacheType == CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP || cacheType == CACHE_TYPE_ALERT_PREVIEW_LARGE) { + if (cacheType == CACHE_TYPE_ALERT_PREVIEW_STATIC || cacheType == CACHE_TYPE_ALERT_PREVIEW || cacheType == CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP || cacheType == CACHE_TYPE_ALERT_PREVIEW_LARGE) { imageReceiver.setLayerNum(7); } if (cacheType == CACHE_TYPE_ALERT_EMOJI_STATUS) { @@ -556,6 +562,14 @@ protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, b invalidate(); } + private void updateAutoRepeat(ImageReceiver imageReceiver) { + if (cacheType == CACHE_TYPE_EMOJI_STATUS || cacheType == CACHE_TYPE_ALERT_EMOJI_STATUS || cacheType == CACHE_TYPE_FORUM_TOPIC) { + imageReceiver.setAutoRepeatCount(2); + } else if (cacheType == CACHE_TYPE_FORUM_TOPIC_LARGE || cacheType == CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW) { + imageReceiver.setAutoRepeatCount(1); + } + } + void invalidate() { if (views != null) { for (int i = 0; i < views.size(); ++i) { @@ -905,11 +919,7 @@ public void play() { AnimatedEmojiDrawable drawable = (AnimatedEmojiDrawable) getDrawable(); ImageReceiver imageReceiver = drawable.getImageReceiver(); if (imageReceiver != null) { - if (drawable.cacheType == CACHE_TYPE_EMOJI_STATUS || drawable.cacheType == CACHE_TYPE_ALERT_EMOJI_STATUS || drawable.cacheType == CACHE_TYPE_FORUM_TOPIC) { - imageReceiver.setAutoRepeatCount(2); - } else if (cacheType == CACHE_TYPE_FORUM_TOPIC_LARGE) { - imageReceiver.setAutoRepeatCount(1); - } + drawable.updateAutoRepeat(imageReceiver); imageReceiver.startAnimation(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java index b0e2614bc17..aa32f5854d3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java @@ -481,7 +481,7 @@ public Bitmap getFrameAtTime(long ms, boolean precise) { if (!precise) { seekToMs(nativePtr, ms, precise); } - Bitmap backgroundBitmap = Bitmap.createBitmap((int) (metaData[0] * scaleFactor), (int) (metaData[1] * scaleFactor), Bitmap.Config.ARGB_8888); + Bitmap backgroundBitmap = Bitmap.createBitmap(metaData[0], metaData[1], Bitmap.Config.ARGB_8888); int result; if (precise) { result = getFrameAtTime(nativePtr, ms, backgroundBitmap, metaData, backgroundBitmap.getRowBytes()); @@ -1072,6 +1072,9 @@ public int getNextFrame(Bitmap bitmap) { @Override public Bitmap getFirstFrame(Bitmap bitmap) { + if (bitmap == null) { + bitmap = Bitmap.createBitmap(renderingWidth, renderingHeight, Bitmap.Config.ARGB_8888); + } Canvas canvas = new Canvas(bitmap); if (generatingCacheBitmap == null) { generatingCacheBitmap = Bitmap.createBitmap(metaData[0], metaData[1], Bitmap.Config.ARGB_8888); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFloat.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFloat.java index 92b50debd06..40f6bfdb3f4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFloat.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFloat.java @@ -77,6 +77,14 @@ public AnimatedFloat(Runnable invalidate, long transitionDuration, TimeInterpola this.firstSet = true; } + public AnimatedFloat(Runnable invalidate, long transitionDelay, long transitionDuration, TimeInterpolator transitionInterpolator) { + this.invalidate = invalidate; + this.transitionDelay = transitionDelay; + this.transitionDuration = transitionDuration; + this.transitionInterpolator = transitionInterpolator; + this.firstSet = true; + } + public AnimatedFloat(float initialValue, View parentToInvalidate) { this.parent = parentToInvalidate; this.value = targetValue = initialValue; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedTextView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedTextView.java index b3d2f6b6096..fe827eaa7ec 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedTextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedTextView.java @@ -6,6 +6,7 @@ import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.PixelFormat; @@ -39,18 +40,29 @@ public static class AnimatedTextDrawable extends Drawable { private boolean isRTL = false; - private int currentWidth, currentHeight; - private Integer[] currentLayoutOffsets; - private Integer[] currentLayoutToOldIndex; - private StaticLayout[] currentLayout; + private float currentWidth, currentHeight; + private Part[] currentParts; private CharSequence currentText; - private int oldWidth, oldHeight; - private Integer[] oldLayoutOffsets; - private Integer[] oldLayoutToCurrentIndex; - private StaticLayout[] oldLayout; + private float oldWidth, oldHeight; + private Part[] oldParts; private CharSequence oldText; + private class Part { + StaticLayout layout; + float offset; + int toOppositeIndex; + float left, width; + + public Part(StaticLayout layout, float offset, int toOppositeIndex) { + this.layout = layout; + this.offset = offset; + this.toOppositeIndex = toOppositeIndex; + this.left = layout == null || layout.getLineCount() <= 0 ? 0 : layout.getLineLeft(0); + this.width = layout == null || layout.getLineCount() <= 0 ? 0 : layout.getLineWidth(0); + } + } + private float t = 0; private boolean moveDown = true; private ValueAnimator animator; @@ -97,26 +109,35 @@ public void draw(@NonNull Canvas canvas) { canvas.translate(bounds.left, bounds.top); int fullWidth = bounds.width(); int fullHeight = bounds.height(); - if (currentLayout != null && oldLayout != null && t != 1) { - int width = AndroidUtilities.lerp(oldWidth, currentWidth, t); - int height = AndroidUtilities.lerp(oldHeight, currentHeight, t); + if (currentParts != null && oldParts != null && t != 1) { + float width = AndroidUtilities.lerp(oldWidth, currentWidth, t); + float height = AndroidUtilities.lerp(oldHeight, currentHeight, t); canvas.translate(0, (fullHeight - height) / 2f); - for (int i = 0; i < currentLayout.length; ++i) { - int j = currentLayoutToOldIndex[i]; - float x = currentLayoutOffsets[i], y = 0; + for (int i = 0; i < currentParts.length; ++i) { + Part current = currentParts[i]; + int j = current.toOppositeIndex; + float x = current.offset, y = 0; if (j >= 0) { - float oldX = oldLayoutOffsets[j]; - x = AndroidUtilities.lerp(oldX, x, t); + if (isRTL && !ignoreRTL) { + x = currentWidth - (x + current.width); + } + Part old = oldParts[j]; + float oldX = old.offset; + if (isRTL && !ignoreRTL) { + oldX = oldWidth - (oldX + old.width); + } + x = AndroidUtilities.lerp(oldX - old.left, x - current.left, t); textPaint.setAlpha(alpha); } else { + if (isRTL && !ignoreRTL) { + x = currentWidth - (x + current.width); + } + x -= current.left; y = -textPaint.getTextSize() * moveAmplitude * (1f - t) * (moveDown ? 1f : -1f); textPaint.setAlpha((int) (alpha * t)); } canvas.save(); - int lwidth = j >= 0 ? width : currentWidth; - if (isRTL && !ignoreRTL) { - x = -x + 2 * lwidth - currentLayout[i].getWidth() - fullWidth; - } + float lwidth = j >= 0 ? width : currentWidth; if ((gravity | ~Gravity.LEFT) != ~0) { if ((gravity | ~Gravity.RIGHT) == ~0) { x += fullWidth - lwidth; @@ -127,21 +148,23 @@ public void draw(@NonNull Canvas canvas) { } } canvas.translate(x, y); - currentLayout[i].draw(canvas); + current.layout.draw(canvas); canvas.restore(); } - for (int i = 0; i < oldLayout.length; ++i) { - int j = oldLayoutToCurrentIndex[i]; + for (int i = 0; i < oldParts.length; ++i) { + Part old = oldParts[i]; + int j = old.toOppositeIndex; if (j >= 0) { continue; } - float x = oldLayoutOffsets[i]; + float x = old.offset; float y = textPaint.getTextSize() * moveAmplitude * t * (moveDown ? 1f : -1f); textPaint.setAlpha((int) (alpha * (1f - t))); canvas.save(); if (isRTL && !ignoreRTL) { - x = -x + 2 * oldWidth - oldLayout[i].getWidth() - fullWidth; + x = oldWidth - (x + old.width); } + x -= old.left; if ((gravity | ~Gravity.LEFT) != ~0) { if ((gravity | ~Gravity.RIGHT) == ~0) { x += fullWidth - oldWidth; @@ -152,19 +175,21 @@ public void draw(@NonNull Canvas canvas) { } } canvas.translate(x, y); - oldLayout[i].draw(canvas); + old.layout.draw(canvas); canvas.restore(); } } else { canvas.translate(0, (fullHeight - currentHeight) / 2f); - if (currentLayout != null) { - for (int i = 0; i < currentLayout.length; ++i) { - textPaint.setAlpha(alpha); + if (currentParts != null) { + textPaint.setAlpha(alpha); + for (int i = 0; i < currentParts.length; ++i) { canvas.save(); - float x = currentLayoutOffsets[i]; + Part current = currentParts[i]; + float x = current.offset; if (isRTL && !ignoreRTL) { - x = -x + 2 * currentWidth - currentLayout[i].getWidth() - fullWidth; + x = currentWidth - (x + current.width); } + x -= current.left; if ((gravity | ~Gravity.LEFT) != ~0) { if ((gravity | ~Gravity.RIGHT) == ~0) { x += fullWidth - currentWidth; @@ -174,8 +199,9 @@ public void draw(@NonNull Canvas canvas) { x += fullWidth - currentWidth; } } +// boolean isAppeared = currentLayoutToOldIndex != null && i < currentLayoutToOldIndex.length && currentLayoutToOldIndex[i] < 0; canvas.translate(x, 0); - currentLayout[i].draw(canvas); + current.layout.draw(canvas); canvas.restore(); } } @@ -226,48 +252,45 @@ public void setText(CharSequence text, boolean animated, boolean moveDown) { oldText = currentText; currentText = text; - currentLayout = null; - oldLayout = null; - ArrayList currentLayoutOffsets = new ArrayList<>(); - ArrayList currentLayoutToOldIndex = new ArrayList<>(); - ArrayList currentLayoutList = new ArrayList<>(); - ArrayList oldLayoutOffsets = new ArrayList<>(); - ArrayList oldLayoutToCurrentIndex = new ArrayList<>(); - ArrayList oldLayoutList = new ArrayList<>(); +// ArrayList currentLayoutOffsets = new ArrayList<>(); +// ArrayList currentLayoutToOldIndex = new ArrayList<>(); +// ArrayList currentLayoutList = new ArrayList<>(); +// ArrayList oldLayoutOffsets = new ArrayList<>(); +// ArrayList oldLayoutToCurrentIndex = new ArrayList<>(); +// ArrayList oldLayoutList = new ArrayList<>(); + ArrayList currentParts = new ArrayList<>(); + ArrayList oldParts = new ArrayList<>(); currentWidth = currentHeight = 0; oldWidth = oldHeight = 0; + isRTL = AndroidUtilities.isRTL(currentText); // order execution matters RegionCallback onEqualRegion = (part, from, to) -> { - StaticLayout layout = makeLayout(part, bounds.width() - Math.min(currentWidth, oldWidth)); - oldLayoutToCurrentIndex.add(currentLayoutList.size()); - currentLayoutToOldIndex.add(oldLayoutList.size()); - currentLayoutOffsets.add(currentWidth); - currentLayoutList.add(layout); - oldLayoutOffsets.add(oldWidth); - oldLayoutList.add(layout); - float partWidth = layout.getLineWidth(0); + StaticLayout layout = makeLayout(part, bounds.width() - (int) Math.ceil(Math.min(currentWidth, oldWidth))); + final Part currentPart = new Part(layout, currentWidth, oldParts.size()); + final Part oldPart = new Part(layout, oldWidth, oldParts.size()); + currentParts.add(currentPart); + oldParts.add(oldPart); + float partWidth = currentPart.width; currentWidth += partWidth; oldWidth += partWidth; currentHeight = Math.max(currentHeight, layout.getHeight()); oldHeight = Math.max(oldHeight, layout.getHeight()); }; RegionCallback onNewPart = (part, from, to) -> { - StaticLayout layout = makeLayout(part, bounds.width() - currentWidth); - currentLayoutOffsets.add(currentWidth); - currentLayoutList.add(layout); - currentLayoutToOldIndex.add(-1); - currentWidth += layout.getLineWidth(0); + StaticLayout layout = makeLayout(part, bounds.width() - (int) Math.ceil(currentWidth)); + final Part currentPart = new Part(layout, currentWidth, -1); + currentParts.add(currentPart); + currentWidth += currentPart.width; currentHeight = Math.max(currentHeight, layout.getHeight()); }; RegionCallback onOldPart = (part, from, to) -> { - StaticLayout layout = makeLayout(part, bounds.width() - oldWidth); - oldLayoutOffsets.add(oldWidth); - oldLayoutList.add(layout); - oldLayoutToCurrentIndex.add(-1); - oldWidth += layout.getLineWidth(0); + StaticLayout layout = makeLayout(part, bounds.width() - (int) Math.ceil(oldWidth)); + final Part oldPart = new Part(layout, oldWidth, -1); + oldParts.add(oldPart); + oldWidth += oldPart.width; oldHeight = Math.max(oldHeight, layout.getHeight()); }; @@ -276,38 +299,14 @@ public void setText(CharSequence text, boolean animated, boolean moveDown) { diff(from, to, onEqualRegion, onNewPart, onOldPart); - if (this.currentLayout == null || this.currentLayout.length != currentLayoutList.size()) { - this.currentLayout = new StaticLayout[currentLayoutList.size()]; - } - currentLayoutList.toArray(currentLayout); - if (this.currentLayoutOffsets == null || this.currentLayoutOffsets.length != currentLayoutOffsets.size()) { - this.currentLayoutOffsets = new Integer[currentLayoutOffsets.size()]; + if (this.currentParts == null || this.currentParts.length != currentParts.size()) { + this.currentParts = new Part[currentParts.size()]; } - currentLayoutOffsets.toArray(this.currentLayoutOffsets); - if (this.currentLayoutToOldIndex == null || this.currentLayoutToOldIndex.length != currentLayoutToOldIndex.size()) { - this.currentLayoutToOldIndex = new Integer[currentLayoutToOldIndex.size()]; + currentParts.toArray(this.currentParts); + if (this.oldParts == null || this.oldParts.length != oldParts.size()) { + this.oldParts = new Part[oldParts.size()]; } - currentLayoutToOldIndex.toArray(this.currentLayoutToOldIndex); - - if (this.oldLayout == null || this.oldLayout.length != oldLayoutList.size()) { - this.oldLayout = new StaticLayout[oldLayoutList.size()]; - } - oldLayoutList.toArray(oldLayout); - if (this.oldLayoutOffsets == null || this.oldLayoutOffsets.length != oldLayoutOffsets.size()) { - this.oldLayoutOffsets = new Integer[oldLayoutOffsets.size()]; - } - oldLayoutOffsets.toArray(this.oldLayoutOffsets); - if (this.oldLayoutToCurrentIndex == null || this.oldLayoutToCurrentIndex.length != oldLayoutToCurrentIndex.size()) { - this.oldLayoutToCurrentIndex = new Integer[oldLayoutToCurrentIndex.size()]; - } - oldLayoutToCurrentIndex.toArray(this.oldLayoutToCurrentIndex); - - if (this.currentLayout.length > 0) { - isRTL = this.currentLayout[0].isRtlCharAt(0); - } else if (this.oldLayout.length > 0) { - isRTL = this.oldLayout[0].isRtlCharAt(0); - } - + oldParts.toArray(this.oldParts); if (animator != null) { animator.cancel(); } @@ -322,9 +321,7 @@ public void setText(CharSequence text, boolean animated, boolean moveDown) { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); - oldLayout = null; - AnimatedTextDrawable.this.oldLayoutOffsets = null; - AnimatedTextDrawable.this.oldLayoutToCurrentIndex = null; + AnimatedTextDrawable.this.oldParts = null; oldText = null; oldWidth = 0; t = 0; @@ -353,22 +350,13 @@ public void onAnimationEnd(Animator animation) { toSetTextMoveDown = false; t = 0; - currentLayout = new StaticLayout[1]; - currentLayout[0] = makeLayout(currentText = text, bounds.width()); - currentWidth = (int) currentLayout[0].getLineWidth(0); - currentHeight = currentLayout[0].getHeight(); - currentLayoutOffsets = new Integer[1]; - currentLayoutOffsets[0] = 0; - currentLayoutToOldIndex = new Integer[1]; - currentLayoutToOldIndex[0] = -1; - - if (this.currentLayout.length > 0) { - isRTL = this.currentLayout[0].isRtlCharAt(0); - } + currentParts = new Part[1]; + currentParts[0] = new Part(makeLayout(currentText = text, bounds.width()), 0, -1); + currentWidth = currentParts[0].width; + currentHeight = currentParts[0].layout.getHeight(); + isRTL = AndroidUtilities.isRTL(currentText); - oldLayout = null; - oldLayoutOffsets = null; - oldLayoutToCurrentIndex = null; + oldParts = null; oldText = null; oldWidth = 0; oldHeight = 0; @@ -381,18 +369,18 @@ public CharSequence getText() { return currentText; } - public int getWidth() { + public float getWidth() { return Math.max(currentWidth, oldWidth); } - public int getCurrentWidth() { - if (currentLayout != null && oldLayout != null) { + public float getCurrentWidth() { + if (currentParts != null && oldParts != null) { return AndroidUtilities.lerp(oldWidth, currentWidth, t); } return currentWidth; } - public int getHeight() { + public float getHeight() { return currentHeight; } @@ -654,6 +642,11 @@ public float getTextSize() { public void setTextColor(int color) { textPaint.setColor(color); + alpha = Color.alpha(color); + } + + public int getTextColor() { + return textPaint.getColor(); } public void setTypeface(Typeface typeface) { @@ -724,6 +717,7 @@ public Rect getDirtyBounds() { private CharSequence toSetText; private boolean toSetMoveDown; + public boolean adaptWidth = true; public AnimatedTextView(Context context) { this(context, false, false, false); @@ -752,8 +746,8 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setText(drawable.getText(), false); } lastMaxWidth = width; - if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) { - width = getPaddingLeft() + drawable.getWidth() + getPaddingRight(); + if (adaptWidth && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) { + width = getPaddingLeft() + (int) Math.ceil(drawable.getWidth()) + getPaddingRight(); } setMeasuredDimension(width, height); } @@ -780,7 +774,7 @@ public boolean isAnimating() { return drawable.isAnimating(); } - private void setIgnoreRTL(boolean value) { + public void setIgnoreRTL(boolean value) { drawable.ignoreRTL = value; } @@ -800,7 +794,7 @@ public void setText(CharSequence text, boolean animated, boolean moveDown) { return; } } - int wasWidth = drawable.getWidth(); + int wasWidth = (int) drawable.getWidth(); drawable.setBounds(getPaddingLeft(), getPaddingTop(), lastMaxWidth - getPaddingRight(), getMeasuredHeight() - getPaddingBottom()); drawable.setText(text, animated, moveDown); if (wasWidth < drawable.getWidth() || !animated && wasWidth != drawable.getWidth()) { @@ -809,7 +803,7 @@ public void setText(CharSequence text, boolean animated, boolean moveDown) { } public int width() { - return getPaddingLeft() + drawable.getCurrentWidth() + getPaddingRight(); + return getPaddingLeft() + (int) Math.ceil(drawable.getCurrentWidth()) + getPaddingRight(); } public CharSequence getText() { @@ -829,6 +823,10 @@ public void setTextColor(int color) { invalidate(); } + public int getTextColor() { + return drawable.getTextColor(); + } + public void setTypeface(Typeface typeface) { drawable.setTypeface(typeface); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AttachBotIntroTopView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AttachBotIntroTopView.java index 47fb79d14de..71f5fd8677f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AttachBotIntroTopView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AttachBotIntroTopView.java @@ -82,8 +82,8 @@ protected void onDetachedFromWindow() { protected void onDraw(Canvas canvas) { super.onDraw(canvas); - AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight() + AndroidUtilities.dp(6)); - canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(6), AndroidUtilities.dp(6), backgroundPaint); + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight() + AndroidUtilities.dp(10)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(10), AndroidUtilities.dp(10), backgroundPaint); imageReceiver.setImageCoords(getWidth() / 2f - AndroidUtilities.dp(ICONS_SIDE_PADDING + ICONS_SIZE_DP), getHeight() / 2f - AndroidUtilities.dp(ICONS_SIZE_DP) / 2f, AndroidUtilities.dp(ICONS_SIZE_DP), AndroidUtilities.dp(ICONS_SIZE_DP)); imageReceiver.draw(canvas); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AttachableDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AttachableDrawable.java new file mode 100644 index 00000000000..c98b50cf017 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AttachableDrawable.java @@ -0,0 +1,8 @@ +package org.telegram.ui.Components; + +import org.telegram.messenger.ImageReceiver; + +public interface AttachableDrawable { + void onAttachedToWindow(ImageReceiver parent); + void onDetachedFromWindow(ImageReceiver parent); +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java index ae8ac9a14f6..35129789311 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java @@ -1391,7 +1391,7 @@ private void onSubItemClick(int id) { } Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); DialogsActivity fragment = new DialogsActivity(args); final ArrayList fmessages = new ArrayList<>(); fmessages.add(messageObject); @@ -1424,6 +1424,7 @@ private void onSubItemClick(int id) { fragment1.finishFragment(); } } + return true; }); parentActivity.presentFragment(fragment); dismiss(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarConstructorFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarConstructorFragment.java new file mode 100644 index 00000000000..5568e12bbad --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarConstructorFragment.java @@ -0,0 +1,1395 @@ +package org.telegram.ui.Components; + +import static org.telegram.ui.Components.ImageUpdater.FOR_TYPE_CHANNEL; +import static org.telegram.ui.Components.ImageUpdater.FOR_TYPE_GROUP; +import static org.telegram.ui.Components.ImageUpdater.TYPE_SUGGEST_PHOTO_FOR_USER; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.Rect; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.core.graphics.ColorUtils; +import androidx.core.view.NestedScrollingParent; +import androidx.core.view.NestedScrollingParentHelper; +import androidx.recyclerview.widget.LinearLayoutManager; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.DocumentObject; +import org.telegram.messenger.ImageLocation; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.SvgHelper; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.AdjustPanLayoutHelper; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BackDrawable; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.BottomSheet; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.SelectAnimatedEmojiDialog; + +import java.util.ArrayList; +import java.util.Objects; + +public class AvatarConstructorFragment extends BaseFragment { + + public final static float STICKER_DEFAULT_SCALE = 0.7f; + public final static float STICKER_DEFAULT_ROUND_RADIUS = 0.13f; + PreviewView previewView; + private SelectAnimatedEmojiDialog selectAnimatedEmojiDialog; + + int collapsedHeight; + int expandedHeight; + View colorPickerPreviewView; + boolean colorPickerInAnimatoin; + boolean drawForBlur; + boolean wasChanged; + LinearLayout linearLayout; + + boolean forGroup; + private FrameLayout button; + + float progressToExpand; + boolean expandWithKeyboard; + ValueAnimator expandAnimator; + + protected ActionBar overlayActionBar; + + Delegate delegate; + private BackgroundSelectView backgroundSelectView; + CanvasButton avatarClickableArea; + boolean keyboardVisible; + + ValueAnimator keyboardVisibilityAnimator; + float keyboardVisibleProgress; + Paint actionBarPaint = new Paint(); + private int gradientBackgroundItemWidth; + + public String[] keys_avatar_background = {Theme.key_avatar_backgroundBlue, Theme.key_avatar_backgroundCyan, Theme.key_avatar_backgroundGreen, Theme.key_avatar_backgroundOrange, Theme.key_avatar_backgroundRed, Theme.key_avatar_backgroundPink, Theme.key_avatar_backgroundViolet}; + public String[] keys_avatar_background2 = {Theme.key_avatar_background2Blue, Theme.key_avatar_background2Cyan, Theme.key_avatar_background2Green, Theme.key_avatar_background2Orange, Theme.key_avatar_background2Red, Theme.key_avatar_background2Pink, Theme.key_avatar_background2Violet}; + public boolean finishOnDone = true; + private ActionBarMenuItem setPhotoItem; + private BottomSheet bottomSheet; + final ImageUpdater.AvatarFor avatarFor; + boolean isLandscapeMode; + private TextView chooseEmojiHint; + private TextView chooseBackgroundHint; + ImageUpdater imageUpdater; + + public AvatarConstructorFragment(ImageUpdater imageUpdater, ImageUpdater.AvatarFor avatarFor) { + this.imageUpdater = imageUpdater; + this.avatarFor = avatarFor; + } + + @Override + public View createView(Context context) { + hasOwnBackground = true; + actionBar.setBackgroundDrawable(null); + actionBar.setCastShadows(false); + actionBar.setAddToContainer(false); + actionBar.setOccupyStatusBar(true); + actionBar.setTitleColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + actionBar.setItemsColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText), false); + actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_listSelector), false); + actionBar.setBackButtonDrawable(new BackDrawable(false)); + actionBar.setAllowOverlayTitle(false); + actionBar.setTitle(LocaleController.getString("PhotoEditor", R.string.PhotoEditor)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + discardEditor(); + } + } + }); + actionBar.getTitleTextView().setAlpha(0); + + overlayActionBar = new ActionBar(getContext()); + overlayActionBar.setCastShadows(false); + overlayActionBar.setAddToContainer(false); + overlayActionBar.setOccupyStatusBar(true); + overlayActionBar.setClipChildren(false); + int selectorColor = ColorUtils.setAlphaComponent(Color.WHITE, 60); + overlayActionBar.setItemsColor(Color.WHITE, false); + + overlayActionBar.setBackButtonDrawable(new BackDrawable(false)); + overlayActionBar.setAllowOverlayTitle(false); + overlayActionBar.setItemsBackgroundColor(selectorColor, false); + ActionBarMenu menuOverlay = overlayActionBar.createMenu(); + menuOverlay.setClipChildren(false); + setPhotoItem = menuOverlay.addItem(1, avatarFor != null && avatarFor.type == TYPE_SUGGEST_PHOTO_FOR_USER ? + LocaleController.getString("SuggestPhoto", R.string.SuggestPhoto) : + LocaleController.getString("SetPhoto", R.string.SetPhoto) + ); + setPhotoItem.setBackground(Theme.createSelectorDrawable(selectorColor, Theme.RIPPLE_MASK_CIRCLE_TO_BOUND_EDGE)); + overlayActionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + discardEditor(); + } + if (id == 1) { + onDonePressed(); + } + } + }); + + linearLayout = new LinearLayout(getContext()) { + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (child == previewView) { + return true; + } + return super.drawChild(canvas, child, drawingTime); + } + }; + + ContainerLayout nestedSizeNotifierLayout = new ContainerLayout(context) { + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + measureKeyboardHeight(); + boolean isLandscapeModeLocal = MeasureSpec.getSize(widthMeasureSpec) > (MeasureSpec.getSize(heightMeasureSpec) + keyboardHeight); + if (isLandscapeModeLocal != isLandscapeMode) { + isLandscapeMode = isLandscapeModeLocal; + AndroidUtilities.removeFromParent(previewView); + AndroidUtilities.requestAdjustNothing(getParentActivity(), getClassGuid()); + if (isLandscapeMode) { + setProgressToExpand(0, false); + previewView.setExpanded(false); + addView(previewView, 0, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + } else { + linearLayout.addView(previewView, 0, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } + AndroidUtilities.requestAdjustResize(getParentActivity(), getClassGuid()); + } + if (isLandscapeMode) { + int avatarWidth = (int) (MeasureSpec.getSize(widthMeasureSpec) * 0.45f); + int contentWidth = (int) (MeasureSpec.getSize(widthMeasureSpec) * 0.55f); + ((MarginLayoutParams) linearLayout.getLayoutParams()).bottomMargin = 0; + ((MarginLayoutParams) linearLayout.getLayoutParams()).leftMargin = avatarWidth; + ((MarginLayoutParams) previewView.getLayoutParams()).rightMargin = contentWidth; + ((MarginLayoutParams) button.getLayoutParams()).rightMargin = contentWidth + AndroidUtilities.dp(16); + ((MarginLayoutParams) chooseBackgroundHint.getLayoutParams()).topMargin = 0; + ((MarginLayoutParams) chooseEmojiHint.getLayoutParams()).topMargin = AndroidUtilities.dp(10); + } else { + ((MarginLayoutParams) linearLayout.getLayoutParams()).bottomMargin = AndroidUtilities.dp(64); + ((MarginLayoutParams) linearLayout.getLayoutParams()).leftMargin = 0; + ((MarginLayoutParams) previewView.getLayoutParams()).rightMargin = 0; + ((MarginLayoutParams) button.getLayoutParams()).rightMargin = AndroidUtilities.dp(16); + ((MarginLayoutParams) chooseBackgroundHint.getLayoutParams()).topMargin = AndroidUtilities.dp(10); + ((MarginLayoutParams) chooseEmojiHint.getLayoutParams()).topMargin = AndroidUtilities.dp(18); + } + boolean oldKeyboardVisible = keyboardVisible; + keyboardVisible = keyboardHeight >= AndroidUtilities.dp(20); + + if (oldKeyboardVisible != keyboardVisible) { + int newMargin; + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (keyboardVisible) { + newMargin = -selectAnimatedEmojiDialog.getTop() + actionBar.getMeasuredHeight() + AndroidUtilities.dp(8); + } else { + newMargin = 0; + } + linearLayout.setTranslationY(linearLayout.getTranslationY() + ((MarginLayoutParams) linearLayout.getLayoutParams()).topMargin - newMargin); + ((MarginLayoutParams) linearLayout.getLayoutParams()).topMargin = newMargin; + createKeyboardVisibleAnimator(keyboardVisible); + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + collapsedHeight = previewView.getMeasuredHeight(); + expandedHeight = previewView.getMeasuredWidth(); + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (child == overlayActionBar) { + return true; + } + if (child == actionBar && keyboardVisibleProgress > 0) { + actionBarPaint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + actionBarPaint.setAlpha((int) (255 * keyboardVisibleProgress)); + canvas.drawRect(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight(), actionBarPaint); + getParentLayout().drawHeaderShadow(canvas, (int) (255 * keyboardVisibleProgress), child.getMeasuredHeight()); + } + return super.drawChild(canvas, child, drawingTime); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + int count = canvas.save(); + super.dispatchDraw(canvas); + if (!isLandscapeMode) { + if (!drawForBlur) { + canvas.save(); + float x = linearLayout.getX() + previewView.getX(); + float y = linearLayout.getY() + previewView.getY(); + int additionalH = expandedHeight - collapsedHeight; + int yKeyboardVisible = AndroidUtilities.statusBarHeight + ((ActionBar.getCurrentActionBarHeight() - collapsedHeight) >> 1); + y = AndroidUtilities.lerp(y, yKeyboardVisible, keyboardVisibleProgress); + canvas.translate(x, y); + previewView.draw(canvas); + AndroidUtilities.rectTmp.set(x, y - additionalH / 2f * progressToExpand, x + previewView.getMeasuredWidth(), y + previewView.getMeasuredHeight() + additionalH / 2f * progressToExpand); + float cx = x + previewView.cx; + float cy = y + previewView.cy; + avatarClickableArea.setRect((int) (cx - previewView.size), (int) (cy - previewView.size), (int) (cx + previewView.size), (int) (cy + previewView.size)); + canvas.restore(); + } + canvas.restoreToCount(count); + + + float alpha = previewView.expandProgress.get() * (1f - (colorPickerPreviewView.getVisibility() == View.VISIBLE ? colorPickerPreviewView.getAlpha() : 0)); + if (alpha != 0) { + overlayActionBar.setVisibility(View.VISIBLE); + count = canvas.save(); + canvas.translate(overlayActionBar.getX(), overlayActionBar.getY()); + + if (alpha != 1) { + canvas.saveLayerAlpha(0, 0, overlayActionBar.getMeasuredWidth(), overlayActionBar.getMeasuredHeight(), (int) (255 * alpha), Canvas.ALL_SAVE_FLAG); + } + overlayActionBar.draw(canvas); + canvas.restoreToCount(count); + } else { + overlayActionBar.setVisibility(View.GONE); + } + } + if (colorPickerInAnimatoin) { + invalidate(); + } + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (keyboardVisibleProgress == 0 && AndroidUtilities.findClickableView(this, ev.getX(), ev.getY())) { + return false; + } + return onTouchEvent(ev); + } + + boolean maybeScroll; + boolean isScrolling; + float startFromProgressToExpand; + float scrollFromX, scrollFromY; + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (avatarClickableArea.checkTouchEvent(event)) { + return true; + } + + if (!isLandscapeMode) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + selectAnimatedEmojiDialog.getHitRect(AndroidUtilities.rectTmp2); + AndroidUtilities.rectTmp2.offset(0, (int) linearLayout.getY()); + if (keyboardVisibleProgress == 0 && !AndroidUtilities.rectTmp2.contains((int) event.getX(), (int) event.getY())) { + maybeScroll = true; + scrollFromX = event.getX(); + scrollFromY = event.getY(); + } + } else if (event.getAction() == MotionEvent.ACTION_MOVE && (maybeScroll || isScrolling)) { + if (maybeScroll) { + if (Math.abs(scrollFromY - event.getY()) > AndroidUtilities.touchSlop) { + maybeScroll = false; + isScrolling = true; + startFromProgressToExpand = progressToExpand; + scrollFromX = event.getX(); + scrollFromY = event.getY(); + } + } else { + float dy = scrollFromY - event.getY(); + float progressToExpand = startFromProgressToExpand + (-dy / (float) expandedHeight); + progressToExpand = Utilities.clamp(progressToExpand, 1f, 0f); + setProgressToExpand(progressToExpand, true); + } + } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + if (isScrolling) { + setExpanded(progressToExpand > 0.5f, false, false); + } + maybeScroll = false; + isScrolling = false; + } + } + return isScrolling || super.onTouchEvent(event) || maybeScroll; + } + }; + nestedSizeNotifierLayout.setFitsSystemWindows(true); + nestedSizeNotifierLayout.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + + + linearLayout.setClipChildren(false); + linearLayout.setClipToPadding(false); + linearLayout.setPadding(0, AndroidUtilities.statusBarHeight, 0, 0); + linearLayout.setOrientation(LinearLayout.VERTICAL); + linearLayout.addView(previewView = new PreviewView(getContext()) { + @Override + public void invalidate() { + super.invalidate(); + nestedSizeNotifierLayout.invalidate(); + } + }); + + chooseBackgroundHint = new TextView(getContext()); + chooseBackgroundHint.setText(LocaleController.getString("ChooseBackground", R.string.ChooseBackground)); + chooseBackgroundHint.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText)); + chooseBackgroundHint.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + chooseBackgroundHint.setGravity(Gravity.CENTER); + linearLayout.addView(chooseBackgroundHint, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 21, 10, 21, 10)); + + FrameLayout backgroundContainer = new FrameLayout(getContext()) { + + private Path path = new Path(); + private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + + @Override + protected void dispatchDraw(Canvas canvas) { + Theme.applyDefaultShadow(paint); + paint.setColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground, getResourceProvider())); + paint.setAlpha((int) (255 * getAlpha())); + + AndroidUtilities.rectTmp.set( + 0, 0, getMeasuredWidth(), getMeasuredHeight() + ); + path.rewind(); + path.addRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(12), AndroidUtilities.dp(12), Path.Direction.CW); + canvas.drawPath(path, paint); + super.dispatchDraw(canvas); + } + }; + backgroundContainer.addView(backgroundSelectView = new BackgroundSelectView(getContext())); + linearLayout.addView(backgroundContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, 0, 12, 0, 12, 0)); + + chooseEmojiHint = new TextView(getContext()); + chooseEmojiHint.setText(LocaleController.getString("ChooseEmojiOrSticker", R.string.ChooseEmojiOrSticker)); + chooseEmojiHint.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText)); + chooseEmojiHint.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + chooseEmojiHint.setGravity(Gravity.CENTER); + linearLayout.addView(chooseEmojiHint, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 21, 18, 21, 10)); + + selectAnimatedEmojiDialog = new SelectAnimatedEmojiDialog(this, getContext(), false, null, SelectAnimatedEmojiDialog.TYPE_AVATAR_CONSTRUCTOR, null) { + + private boolean firstLayout = true; + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (firstLayout) { + firstLayout = false; + selectAnimatedEmojiDialog.onShow(null); + } + } + + protected void onEmojiSelected(View view, Long documentId, TLRPC.Document document, Integer until) { + long docId = documentId == null ? 0 : documentId; + previewView.documentId = docId; + previewView.document = document; + if (docId == 0) { + previewView.backupImageView.setAnimatedEmojiDrawable(null); + SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(document, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f); + previewView.backupImageView.getImageReceiver().setImage(ImageLocation.getForDocument(document), "100_100", null, null, svgThumb, 0, "tgs", document, 0); + } else { + previewView.backupImageView.setAnimatedEmojiDrawable(new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW, currentAccount, docId)); + previewView.backupImageView.getImageReceiver().clearImage(); + } + if (previewView.getImageReceiver() != null && previewView.getImageReceiver().getAnimation() != null) { + previewView.getImageReceiver().getAnimation().seekTo(0, true); + } + if (previewView.getImageReceiver() != null && previewView.getImageReceiver().getLottieAnimation() != null) { + previewView.getImageReceiver().getLottieAnimation().setCurrentFrame(0, false, true); + } + wasChanged = true; + } + }; + + selectAnimatedEmojiDialog.setAnimationsEnabled(fragmentBeginToShow); + selectAnimatedEmojiDialog.setClipChildren(false); + linearLayout.addView(selectAnimatedEmojiDialog, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 0, 12, 0, 12, 12)); + + linearLayout.setClipChildren(false); + nestedSizeNotifierLayout.addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 0, 0, 0, 0, 64)); + + colorPickerPreviewView = new View(getContext()); + colorPickerPreviewView.setVisibility(View.GONE); + + + button = new FrameLayout(getContext()); + button.setBackground(Theme.AdaptiveRipple.filledRect(Theme.key_featuredStickers_addButton, 8)); + + TextView textView = new TextView(getContext()); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + if (imageUpdater.setForType == FOR_TYPE_CHANNEL) { + textView.setText(LocaleController.getString("SetChannelPhoto", R.string.SetChannelPhoto)); + } else if (imageUpdater.setForType == FOR_TYPE_GROUP) { + textView.setText(LocaleController.getString("SetGroupPhoto", R.string.SetGroupPhoto)); + } else if (avatarFor != null && avatarFor.type == TYPE_SUGGEST_PHOTO_FOR_USER) { + textView.setText(LocaleController.getString("SuggestPhoto", R.string.SuggestPhoto)); + } else { + textView.setText(LocaleController.getString("SetProfilePhotoAvatarConstructor", R.string.SetProfilePhotoAvatarConstructor)); + } + textView.setGravity(Gravity.CENTER); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); + button.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + button.setOnClickListener(v -> onDonePressed()); + + nestedSizeNotifierLayout.addView(button, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM, 16, 16, 16, 16)); + nestedSizeNotifierLayout.addView(actionBar); + + nestedSizeNotifierLayout.addView(overlayActionBar); + nestedSizeNotifierLayout.addView(colorPickerPreviewView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + avatarClickableArea = new CanvasButton(nestedSizeNotifierLayout); + avatarClickableArea.setDelegate(() -> { + onPreviewClick(); + }); + fragmentView = nestedSizeNotifierLayout; + return fragmentView; + } + + private void discardEditor() { + if (getParentActivity() == null) { + return; + } + if (wasChanged) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.getString("PhotoEditorDiscardAlert", R.string.PhotoEditorDiscardAlert)); + builder.setTitle(LocaleController.getString("DiscardChanges", R.string.DiscardChanges)); + builder.setPositiveButton(LocaleController.getString("PassportDiscard", R.string.PassportDiscard), (dialogInterface, i) -> finishFragment()); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + AlertDialog dialog = builder.create(); + showDialog(dialog); + dialog.redPositive(); + } else { + finishFragment(); + } + } + + private void createKeyboardVisibleAnimator(boolean keyboardVisible) { + if (isLandscapeMode) { + return; + } + keyboardVisibilityAnimator = ValueAnimator.ofFloat(keyboardVisibleProgress, keyboardVisible ? 1f : 0f); + float offsetY = (expandedHeight - collapsedHeight - AndroidUtilities.statusBarHeight) * progressToExpand; + float translationYFrom, translationYTo; + if (keyboardVisible) { + previewView.setExpanded(false); + translationYFrom = linearLayout.getTranslationY(); + translationYTo = 0; + } else { + translationYFrom = offsetY; + translationYTo = linearLayout.getTranslationY(); + } + if (expandWithKeyboard && !keyboardVisible) { + previewView.setExpanded(true); + } else { + expandWithKeyboard = false; + } + keyboardVisibilityAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + keyboardVisibleProgress = (float) animation.getAnimatedValue(); + float offset = AndroidUtilities.lerp(translationYFrom, translationYTo, keyboardVisibleProgress); + actionBar.getTitleTextView().setAlpha(keyboardVisibleProgress); + if (expandWithKeyboard && !keyboardVisible) { + setProgressToExpand(1f - keyboardVisibleProgress, false); + } + linearLayout.setTranslationY(offset); + button.setTranslationY(offset); + fragmentView.invalidate(); + actionBar.invalidate(); + } + }); + keyboardVisibilityAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + setProgressToExpand(expandWithKeyboard ? 1f : 0f, false); + expandWithKeyboard = false; + } + }); + keyboardVisibilityAnimator.setDuration(AdjustPanLayoutHelper.keyboardDuration); + keyboardVisibilityAnimator.setInterpolator(AdjustPanLayoutHelper.keyboardInterpolator); + keyboardVisibilityAnimator.start(); + } + + private void onDonePressed() { + if (previewView.getImageReceiver() == null || !previewView.getImageReceiver().hasImageLoaded()) { + return; + } + if (delegate != null) { + delegate.onDone(previewView.backgroundGradient, previewView.documentId, previewView.document, previewView); + } + if (finishOnDone) { + finishFragment(); + } + } + + + private void setExpanded(boolean expanded, boolean fromClick, boolean withColorPicker) { + if (isLandscapeMode) { + return; + } +// if (this.expanded != expanded) { +// this.expanded = expanded; + cancelExpandAnimator(); + expandAnimator = ValueAnimator.ofFloat(progressToExpand, expanded ? 1f : 0f); + if (fromClick) { + previewView.overrideExpandProgress = progressToExpand; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.needCheckSystemBarColors); + } + } + expandAnimator.addUpdateListener(animation -> { + float progress = (float) animation.getAnimatedValue(); + setProgressToExpand(progress, false); + if (fromClick) { + previewView.overrideExpandProgress = progress; + previewView.invalidate(); + } + }); + expandAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + expandAnimator = null; + setProgressToExpand(expanded ? 1f : 0f, false); + if (fromClick) { + previewView.overrideExpandProgress = -1; + previewView.setExpanded(expanded); + } + + } + }); + if (withColorPicker) { + expandAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + expandAnimator.setDuration(350); + expandAnimator.setStartDelay(150); + } else { + expandAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + expandAnimator.setDuration(250); + } + expandAnimator.start(); + // } + } + + void cancelExpandAnimator() { + if (expandAnimator != null) { + expandAnimator.removeAllListeners(); + expandAnimator.cancel(); + expandAnimator = null; + } + } + + private void setProgressToExpand(float progressToExpand, boolean fromScroll) { + this.progressToExpand = progressToExpand; + + float offsetY = (expandedHeight - collapsedHeight - AndroidUtilities.statusBarHeight) * progressToExpand; + if (keyboardVisibleProgress == 0) { + linearLayout.setTranslationY(offsetY); + button.setTranslationY(offsetY); + } + previewView.setTranslationY(-(expandedHeight - collapsedHeight) / 2f * progressToExpand); + fragmentView.invalidate(); + if (fromScroll) { + previewView.setExpanded(progressToExpand > 0.5f); + } + } + + public void startFrom(AvatarConstructorPreviewCell previewCell) { + BackgroundGradient gradient = previewCell.getBackgroundGradient(); + previewView.setGradient(gradient); + if (previewCell.getAnimatedEmoji() != null) { + long docId = previewCell.getAnimatedEmoji().getDocumentId(); + previewView.documentId = docId; + previewView.backupImageView.setAnimatedEmojiDrawable(new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW, currentAccount, docId)); + } + backgroundSelectView.selectGradient(gradient); + selectAnimatedEmojiDialog.setForUser(previewCell.forUser); + } + + public class PreviewView extends FrameLayout { + + public long documentId; + public TLRPC.Document document; + BackupImageView backupImageView; + GradientTools gradientTools = new GradientTools(); + GradientTools outGradientTools = new GradientTools(); + float changeBackgroundProgress = 1f; + BackgroundGradient backgroundGradient; + + AnimatedFloat expandProgress = new AnimatedFloat(this, 200, CubicBezierInterpolator.EASE_OUT); + boolean expanded; + float overrideExpandProgress = -1f; + private float size; + private float cx, cy; + + public PreviewView(Context context) { + super(context); + backupImageView = new BackupImageView(context) { + @Override + public void invalidate() { + super.invalidate(); + PreviewView.this.invalidate(); + } + + @Override + public void invalidate(Rect dirty) { + super.invalidate(dirty); + PreviewView.this.invalidate(); + } + + @Override + public void invalidate(int l, int t, int r, int b) { + super.invalidate(l, t, r, b); + PreviewView.this.invalidate(); + } + }; + backupImageView.getImageReceiver().setAutoRepeatCount(1); + backupImageView.getImageReceiver().setAspectFit(true); + setClipChildren(false); + addView(backupImageView, LayoutHelper.createFrame(70, 70, Gravity.CENTER)); + } + + public void setExpanded(boolean expanded) { + if (this.expanded == expanded) { + return; + } + this.expanded = expanded; + if (expanded) { + if (backupImageView.animatedEmojiDrawable != null && backupImageView.animatedEmojiDrawable.getImageReceiver() != null) { + backupImageView.animatedEmojiDrawable.getImageReceiver().startAnimation(); + } + backupImageView.imageReceiver.startAnimation(); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.needCheckSystemBarColors); + } + invalidate(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (isLandscapeMode) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } else { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(140), MeasureSpec.EXACTLY)); + } + } + + @Override + protected void dispatchDraw(Canvas canvas) { + cx = getMeasuredWidth() / 2f; + cy = getMeasuredHeight() / 2f; + float radius = isLandscapeMode ? getMeasuredWidth() * 0.3f : AndroidUtilities.dp(50); + expandProgress.set(expanded ? 1f : 0f); + if (overrideExpandProgress >= 0) { + expandProgress.set(overrideExpandProgress, true); + } + size = AndroidUtilities.lerp(radius, getMeasuredWidth() / 2f, expandProgress.get()); + size = AndroidUtilities.lerp(size, AndroidUtilities.dp(21), keyboardVisibleProgress); + cx = AndroidUtilities.lerp(cx, getMeasuredWidth() - AndroidUtilities.dp(12) - AndroidUtilities.dp(21), keyboardVisibleProgress); + + + canvas.save(); + int additionalH = expandedHeight - collapsedHeight; + canvas.clipRect(0, -additionalH / 2f, getMeasuredWidth(), getMeasuredHeight() + additionalH / 2f * progressToExpand); + if (backgroundGradient != null) { + gradientTools.setColors(backgroundGradient.color1, backgroundGradient.color2, backgroundGradient.color3, backgroundGradient.color4); + gradientTools.setBounds(cx - size, cy - size, cx + size, cy + size); + if (changeBackgroundProgress != 1f) { + outGradientTools.setBounds(cx - size, cy - size, cx + size, cy + size); + outGradientTools.paint.setAlpha(255); + drawBackround(canvas, cx, cy, radius, size, outGradientTools.paint); + gradientTools.paint.setAlpha((int) (255 * changeBackgroundProgress)); + drawBackround(canvas, cx, cy, radius, size, gradientTools.paint); + changeBackgroundProgress += 16 / 250f; + if (changeBackgroundProgress > 1f) { + changeBackgroundProgress = 1f; + } + invalidate(); + } else { + gradientTools.paint.setAlpha(255); + drawBackround(canvas, cx, cy, radius, size, gradientTools.paint); + } + } + int imageHeight = isLandscapeMode ? (int) (radius * 2 * STICKER_DEFAULT_SCALE) : AndroidUtilities.dp(70); + int imageHeightExpanded = (int) (getMeasuredWidth() * STICKER_DEFAULT_SCALE); + int imageHeightKeyboardVisible = (int) (AndroidUtilities.dp(42) * STICKER_DEFAULT_SCALE); + float imageSize = AndroidUtilities.lerp(imageHeight, imageHeightExpanded, expandProgress.get()); + imageSize = AndroidUtilities.lerp(imageSize, imageHeightKeyboardVisible, keyboardVisibleProgress); + imageSize /= 2; + if (backupImageView.animatedEmojiDrawable != null) { + if (backupImageView.animatedEmojiDrawable.getImageReceiver() != null) { + backupImageView.animatedEmojiDrawable.getImageReceiver().setRoundRadius((int) (imageSize * 2 * STICKER_DEFAULT_ROUND_RADIUS)); + } + backupImageView.animatedEmojiDrawable.setBounds((int) (cx - imageSize), (int) (cy - imageSize), (int) (cx + imageSize), (int) (cy + imageSize)); + backupImageView.animatedEmojiDrawable.draw(canvas); + + } else { + backupImageView.imageReceiver.setImageCoords(cx - imageSize, cy - imageSize, imageSize * 2, imageSize * 2); + backupImageView.imageReceiver.setRoundRadius((int) (imageSize * 2 * STICKER_DEFAULT_ROUND_RADIUS)); + backupImageView.imageReceiver.draw(canvas); + } + } + + private void drawBackround(Canvas canvas, float cx, float cy, float radius, float size, Paint paint) { + float p = expandProgress.get(); + if (p == 0) { + canvas.drawCircle(cx, cy, size, paint); + } else { + float roundRadius = AndroidUtilities.lerp(radius, 0, p); + AndroidUtilities.rectTmp.set(cx - size, cy - size, cx + size, cy + size); + canvas.drawRoundRect(AndroidUtilities.rectTmp, roundRadius, roundRadius, paint); + } + } + + public void setGradient(BackgroundGradient backgroundGradient) { + if (this.backgroundGradient != null) { + outGradientTools.setColors(this.backgroundGradient.color1, this.backgroundGradient.color2, this.backgroundGradient.color3, this.backgroundGradient.color4); + changeBackgroundProgress = 0f; + wasChanged = true; + } + this.backgroundGradient = backgroundGradient; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.needCheckSystemBarColors); + } + invalidate(); + } + + public long getDuration() { + ImageReceiver imageReceiver = backupImageView.getImageReceiver(); + if (backupImageView.animatedEmojiDrawable != null) { + imageReceiver = backupImageView.animatedEmojiDrawable.getImageReceiver(); + } + if (imageReceiver == null) { + return 5000; + } + if (imageReceiver.getLottieAnimation() != null) { + return imageReceiver.getLottieAnimation().getDuration(); + } + return 5000; + } + + public ImageReceiver getImageReceiver() { + ImageReceiver imageReceiver = backupImageView.getImageReceiver(); + if (backupImageView.animatedEmojiDrawable != null) { + imageReceiver = backupImageView.animatedEmojiDrawable.getImageReceiver(); + } + return imageReceiver; + } + + public boolean hasAnimation() { + return getImageReceiver().getAnimation() != null || getImageReceiver().getLottieAnimation() != null; + } + + @Override + public void invalidate() { + super.invalidate(); + fragmentView.invalidate(); + } + } + + private class BackgroundSelectView extends RecyclerListView { + + ArrayList gradients = new ArrayList<>(); + + int stableIdPointer = 200; + + int selectedItemId = -1; + + Adapter adapter; + BackgroundGradient customSelectedGradient; + + public BackgroundSelectView(Context context) { + super(context); + LinearLayoutManager layoutManager = new LinearLayoutManager(context); + layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); + setLayoutManager(layoutManager); + for (int i = 0; i < keys_avatar_background.length; i++) { + BackgroundGradient backgroundGradient = new BackgroundGradient(); + backgroundGradient.stableId = stableIdPointer++; + backgroundGradient.color1 = Theme.getColor(keys_avatar_background[i]); + backgroundGradient.color2 = Theme.getColor(keys_avatar_background2[i]); + gradients.add(backgroundGradient); + } + setOnItemClickListener((view, position) -> { + if (view instanceof GradientSelectorView && !((GradientSelectorView) view).isCustom) { + selectedItemId = ((GradientSelectorView) view).backgroundGradient.stableId; + previewView.setGradient(((GradientSelectorView) view).backgroundGradient); + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + } else { + if (selectedItemId != 1 && customSelectedGradient != null) { + selectedItemId = 1; + previewView.setGradient(customSelectedGradient); + if (adapter != null) { + adapter.notifyDataSetChanged(); + } + } else { + showColorPicker(); + } + } + }); + setAdapter(adapter = new Adapter() { + + private final static int VIEW_TYPE_GRADIENT = 0; + private final static int VIEW_TYPE_ADD_CUSTOM = 1; + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + switch (viewType) { + case VIEW_TYPE_ADD_CUSTOM: + case VIEW_TYPE_GRADIENT: + default: + view = new GradientSelectorView(getContext()); + break; + } + return new Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + if (holder.getItemViewType() == VIEW_TYPE_GRADIENT) { + GradientSelectorView gradientSelectorView = (GradientSelectorView) holder.itemView; + gradientSelectorView.setGradient(gradients.get(position)); + gradientSelectorView.setSelectedInternal(selectedItemId == gradients.get(position).stableId, true); + } else { + GradientSelectorView gradientSelectorView = (GradientSelectorView) holder.itemView; + gradientSelectorView.setCustom(true); + gradientSelectorView.setGradient(customSelectedGradient); + gradientSelectorView.setSelectedInternal(selectedItemId == 1, true); + } + } + + @Override + public int getItemCount() { + return gradients.size() + 1; + } + + @Override + public long getItemId(int position) { + if (position >= gradients.size()) { + return 1; + } + return gradients.get(position).stableId; + } + + @Override + public int getItemViewType(int position) { + if (position >= gradients.size()) { + return VIEW_TYPE_ADD_CUSTOM; + } + return VIEW_TYPE_GRADIENT; + } + }); + setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); + } + + @Override + protected void onMeasure(int widthSpec, int heightSpec) { + int availableWidth = MeasureSpec.getSize(widthSpec); + int itemsCount = adapter.getItemCount(); + gradientBackgroundItemWidth = availableWidth / itemsCount; + if (gradientBackgroundItemWidth < AndroidUtilities.dp(36)) { + gradientBackgroundItemWidth = AndroidUtilities.dp(36); + } else if (gradientBackgroundItemWidth > AndroidUtilities.dp(150)) { + gradientBackgroundItemWidth = AndroidUtilities.dp(48); + } + super.onMeasure(widthSpec, heightSpec); + } + + public void selectGradient(BackgroundGradient gradient) { + boolean isDefault = false; + for (int i = 0; i < gradients.size(); i++) { + if (gradients.get(i).equals(gradient)) { + selectedItemId = gradients.get(i).stableId; + isDefault = true; + break; + } + } + if (!isDefault) { + customSelectedGradient = gradient; + selectedItemId = 1; + } + adapter.notifyDataSetChanged(); + } + } + + BackgroundGradient colorPickerGradient; + + private void showColorPicker() { + if (bottomSheet != null) { + return; + } + if (!previewView.expanded) { + setExpanded(true, true, true); + } + + BackgroundGradient prevGradient = null; + if (previewView.backgroundGradient != null) { + prevGradient = previewView.backgroundGradient; + } + boolean[] onDoneButtonPressed = new boolean[]{false}; + BackgroundGradient finalPrevGradient = prevGradient; + AndroidUtilities.requestAdjustNothing(getParentActivity(), getClassGuid()); + bottomSheet = new BottomSheet(getContext(), true) { + @Override + public void dismiss() { + super.dismiss(); + backgroundSelectView.selectGradient(colorPickerGradient); + colorPickerInAnimatoin = true; + fragmentView.invalidate(); + colorPickerPreviewView.animate().setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + colorPickerInAnimatoin = false; + colorPickerPreviewView.setVisibility(View.GONE); + } + }).alpha(0f).setDuration(200).start(); + } + + @Override + public void dismissInternal() { + super.dismissInternal(); + AndroidUtilities.requestAdjustResize(getParentActivity(), getClassGuid()); + bottomSheet = null; + } + }; + bottomSheet.fixNavigationBar(); + bottomSheet.pauseAllHeavyOperations = false; + + drawForBlur = true; + colorPickerPreviewView.setBackground(new BitmapDrawable(getContext().getResources(), AndroidUtilities.makeBlurBitmap(fragmentView, 12f, 10))); + drawForBlur = false; + colorPickerPreviewView.setVisibility(View.VISIBLE); + colorPickerPreviewView.setAlpha(0); + colorPickerInAnimatoin = true; + fragmentView.invalidate(); + colorPickerPreviewView.animate().setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + colorPickerInAnimatoin = false; + } + }).alpha(1f).setDuration(200).start(); + + colorPickerGradient = new BackgroundGradient(); + ColorPicker colorPicker = new ColorPicker(getContext(), false, (color, num, applyNow) -> { + switch (num) { + case 0: + if (colorPickerGradient.color1 != color && (colorPickerGradient.color1 == 0 || color == 0)) { + colorPickerGradient = colorPickerGradient.copy(); + previewView.setGradient(colorPickerGradient); + } + colorPickerGradient.color1 = color; + break; + case 1: + if (colorPickerGradient.color2 != color && (colorPickerGradient.color2 == 0 || color == 0)) { + colorPickerGradient = colorPickerGradient.copy(); + previewView.setGradient(colorPickerGradient); + } + colorPickerGradient.color2 = color; + break; + case 2: + if (colorPickerGradient.color3 != color && (colorPickerGradient.color3 == 0 || color == 0)) { + colorPickerGradient = colorPickerGradient.copy(); + previewView.setGradient(colorPickerGradient); + } + colorPickerGradient.color3 = color; + break; + case 3: + if (colorPickerGradient.color4 != color && (colorPickerGradient.color4 == 0 || color == 0)) { + colorPickerGradient = colorPickerGradient.copy(); + previewView.setGradient(colorPickerGradient); + } + colorPickerGradient.color4 = color; + break; + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.needCheckSystemBarColors); + } + previewView.invalidate(); + }) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(300), MeasureSpec.EXACTLY)); + } + }; + + if (previewView.backgroundGradient != null) { + colorPicker.setColor(colorPickerGradient.color4 = previewView.backgroundGradient.color4, 3); + colorPicker.setColor(colorPickerGradient.color3 = previewView.backgroundGradient.color3, 2); + colorPicker.setColor(colorPickerGradient.color2 = previewView.backgroundGradient.color2, 1); + colorPicker.setColor(colorPickerGradient.color1 = previewView.backgroundGradient.color1, 0); + } + + colorPicker.setType(-1, true, 4, colorPickerGradient.colorsCount(), false, 0, false); + + previewView.setGradient(colorPickerGradient); + + LinearLayout colorPickerContainer = new LinearLayout(getContext()); + colorPickerContainer.setOrientation(LinearLayout.VERTICAL); + colorPickerContainer.setPadding(0, AndroidUtilities.dp(8), 0, 0); + colorPickerContainer.addView(colorPicker); + + FrameLayout button = new FrameLayout(getContext()); + button.setBackground(Theme.AdaptiveRipple.filledRect(Theme.key_featuredStickers_addButton, 8)); + + TextView textView = new TextView(getContext()); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setText(LocaleController.getString("SetColor", R.string.SetColor)); + textView.setGravity(Gravity.CENTER); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); + button.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + + colorPickerContainer.addView(button, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, 0, 16, -8, 16, 16)); + button.setOnClickListener(v -> { + onDoneButtonPressed[0] = true; + backgroundSelectView.selectGradient(colorPickerGradient); + bottomSheet.dismiss(); + }); + bottomSheet.setCustomView(colorPickerContainer); + bottomSheet.smoothKeyboardAnimationEnabled = true; + bottomSheet.setDimBehind(false); + bottomSheet.show(); + isLightStatusBar(); + } + + public static class BackgroundGradient { + + public int stableId; + + int color1; + int color2; + int color3; + int color4; + + public BackgroundGradient copy() { + BackgroundGradient backgroundGradient = new BackgroundGradient(); + backgroundGradient.color1 = color1; + backgroundGradient.color2 = color2; + backgroundGradient.color3 = color3; + backgroundGradient.color4 = color4; + return backgroundGradient; + } + + public int colorsCount() { + if (color4 != 0) { + return 4; + } + if (color3 != 0) { + return 3; + } + if (color2 != 0) { + return 2; + } + return 1; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof BackgroundGradient)) return false; + BackgroundGradient that = (BackgroundGradient) o; + return color1 == that.color1 && color2 == that.color2 && color3 == that.color3 && color4 == that.color4; + } + + @Override + public int hashCode() { + return Objects.hash(stableId, color1, color2, color3, color4); + } + + public int getAverageColor() { + int color = color1; + if (color2 != 0) { + color = ColorUtils.blendARGB(color, color2, 0.5f); + } + if (color3 != 0) { + color = ColorUtils.blendARGB(color, color3, 0.5f); + } + if (color4 != 0) { + color = ColorUtils.blendARGB(color, color4, 0.5f); + } + return color; + } + } + + private class GradientSelectorView extends View { + + BackgroundGradient backgroundGradient; + + AnimatedFloat progressToSelect = new AnimatedFloat(400, AndroidUtilities.overshootInterpolator); + boolean selected; + boolean isCustom; + + GradientTools gradientTools = new GradientTools(); + Drawable addIcon; + Paint optionsPaint; + Paint defaultPaint; + + public GradientSelectorView(Context context) { + super(context); + progressToSelect.setParent(this); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(gradientBackgroundItemWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(48), MeasureSpec.EXACTLY)); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + progressToSelect.set(selected ? 1f : 0, false); + float cx = getMeasuredWidth() / 2f; + float cy = getMeasuredHeight() / 2f; + + Paint paint; + if (backgroundGradient != null) { + gradientTools.setColors(backgroundGradient.color1, backgroundGradient.color2, backgroundGradient.color3, backgroundGradient.color4); + gradientTools.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); + paint = gradientTools.paint; + } else { + if (defaultPaint == null) { + defaultPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + defaultPaint.setColor(Theme.getColor(Theme.key_chat_emojiPanelBackground)); + } + paint = defaultPaint; + } + if (progressToSelect.get() == 0) { + canvas.drawCircle(cx, cy, AndroidUtilities.dp(15), paint); + } else { + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeWidth(AndroidUtilities.dp(2)); + canvas.drawCircle(cx, cy, AndroidUtilities.dpf2(13.5f), paint); + paint.setStyle(Paint.Style.FILL); + canvas.drawCircle(cx, cy, AndroidUtilities.dp(10) + AndroidUtilities.dp(5) * (1f - progressToSelect.get()), paint); + } + + if (isCustom) { + if (backgroundGradient == null) { + if (addIcon == null) { + addIcon = ContextCompat.getDrawable(getContext(), R.drawable.msg_filled_plus); + addIcon.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_emojiSearchIcon), PorterDuff.Mode.MULTIPLY)); + } + addIcon.setBounds((int) (cx - addIcon.getIntrinsicWidth() / 2f), (int) (cy - addIcon.getIntrinsicHeight() / 2f), + (int) (cx + addIcon.getIntrinsicWidth() / 2f), (int) (cy + addIcon.getIntrinsicHeight() / 2f)); + addIcon.draw(canvas); + } else { + if (optionsPaint == null) { + optionsPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + optionsPaint.setColor(0xffffffff); + } + optionsPaint.setAlpha(Math.round(255f * Utilities.clamp(progressToSelect.get(), 1f, 0f))); + canvas.drawCircle(cx, cy, AndroidUtilities.dp(1.5f), optionsPaint); + canvas.drawCircle(cx - AndroidUtilities.dp(5) * progressToSelect.get(), cy, AndroidUtilities.dp(1.5f), optionsPaint); + canvas.drawCircle(cx + AndroidUtilities.dp(5) * progressToSelect.get(), cy, AndroidUtilities.dp(1.5f), optionsPaint); + + } + } + } + + void setGradient(BackgroundGradient backgroundGradient) { + this.backgroundGradient = backgroundGradient; + } + + void setSelectedInternal(boolean selected, boolean animated) { + if (this.selected != selected) { + this.selected = selected; + invalidate(); + } + if (!animated) { + progressToSelect.set(selected ? 1f : 0, false); + } + } + + public void setCustom(boolean b) { + isCustom = b; + } + } + + boolean isLightInternal = false; + float progressToLightStatusBar = 0f; + ValueAnimator lightProgressAnimator; + + @Override + public boolean isLightStatusBar() { + boolean isLight; + if (previewView != null && (previewView.expanded || previewView.overrideExpandProgress >= 0 && previewView.backgroundGradient != null)) { + int averageColor = previewView.backgroundGradient.getAverageColor(); + isLight = AndroidUtilities.computePerceivedBrightness(averageColor) > 0.721f; + } else { + isLight = AndroidUtilities.computePerceivedBrightness(Theme.getColor(Theme.key_windowBackgroundGray)) > 0.721f; + } + if (isLightInternal != isLight) { + isLightInternal = isLight; + if (actionBar.getAlpha() == 0) { + setProgressToLightStatusBar(isLight ? 0f : 1f); + } else { + if (lightProgressAnimator != null) { + lightProgressAnimator.removeAllListeners(); + lightProgressAnimator.cancel(); + } + lightProgressAnimator = ValueAnimator.ofFloat(progressToLightStatusBar, isLight ? 0f : 1f); + lightProgressAnimator.addUpdateListener(animation -> { + setProgressToLightStatusBar((Float) animation.getAnimatedValue()); + }); + lightProgressAnimator.setDuration(150).start(); + } + } + if (bottomSheet != null) { + AndroidUtilities.setLightStatusBar(bottomSheet.getWindow(), isLight); + } + return isLight; + } + + private void setProgressToLightStatusBar(float value) { + if (progressToLightStatusBar != value) { + progressToLightStatusBar = value; + int color = ColorUtils.blendARGB(Color.BLACK, Color.WHITE, progressToLightStatusBar); + int selectorColor = ColorUtils.setAlphaComponent(color, 60); + overlayActionBar.setItemsColor(color, false); + setPhotoItem.setBackground(Theme.createSelectorDrawable(selectorColor, Theme.RIPPLE_MASK_CIRCLE_TO_BOUND_EDGE)); + } + } + + public void setDelegate(Delegate delegate) { + this.delegate = delegate; + } + + public void onPreviewClick() { + if (isLandscapeMode) { + return; + } + if (keyboardVisibleProgress > 0) { + if (keyboardVisibilityAnimator != null) { + progressToExpand = 1f; + expandWithKeyboard = true; + } + AndroidUtilities.hideKeyboard(fragmentView); + return; + } + setExpanded(!previewView.expanded, true, false); + } + + private class ContainerLayout extends SizeNotifierFrameLayout implements NestedScrollingParent { + + private NestedScrollingParentHelper nestedScrollingParentHelper; + + public ContainerLayout(Context context) { + super(context); + nestedScrollingParentHelper = new NestedScrollingParentHelper(this); + } + + @Override + public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) { + if (keyboardVisibleProgress > 0 || isLandscapeMode) { + return false; + } + return true; + } + + @Override + public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) { + nestedScrollingParentHelper.onNestedScrollAccepted(child, target, nestedScrollAxes); + cancelExpandAnimator(); + } + + @Override + public void onStopNestedScroll(View target) { + nestedScrollingParentHelper.onStopNestedScroll(target); + setExpanded(progressToExpand > 0.5f, false, false); + } + + @Override + public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) { + if (keyboardVisibleProgress > 0 || isLandscapeMode) { + return; + } + if (dyUnconsumed != 0) { + cancelExpandAnimator(); + float progressToExpand = AvatarConstructorFragment.this.progressToExpand - dyUnconsumed / (float) expandedHeight; + progressToExpand = Utilities.clamp(progressToExpand, 1f, 0f); + setProgressToExpand(progressToExpand, true); + } + } + + @Override + public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) { + if (keyboardVisibleProgress > 0 || isLandscapeMode) { + return; + } + if (dy > 0 && AvatarConstructorFragment.this.progressToExpand > 0) { + cancelExpandAnimator(); + float progressToExpand = AvatarConstructorFragment.this.progressToExpand - dy / (float) expandedHeight; + progressToExpand = Utilities.clamp(progressToExpand, 1f, 0f); + setProgressToExpand(progressToExpand, true); + consumed[1] = dy; + } + } + + @Override + public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) { + return false; + } + + @Override + public boolean onNestedPreFling(View target, float velocityX, float velocityY) { + return false; + } + + @Override + public int getNestedScrollAxes() { + return nestedScrollingParentHelper.getNestedScrollAxes(); + } + } + + @Override + public boolean isSwipeBackEnabled(MotionEvent event) { + return false; + } + + @Override + public boolean onBackPressed() { + discardEditor(); + return false; + } + + public interface Delegate { + void onDone(BackgroundGradient backgroundGradient, long documentId, TLRPC.Document document, PreviewView previewView); + } + + @Override + public void onResume() { + super.onResume(); + AndroidUtilities.requestAdjustResize(getParentActivity(), getClassGuid()); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarConstructorPreviewCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarConstructorPreviewCell.java new file mode 100644 index 00000000000..c7ac8625654 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarConstructorPreviewCell.java @@ -0,0 +1,217 @@ +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.util.TypedValue; +import android.view.Gravity; +import android.widget.FrameLayout; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; + +import java.util.ArrayList; + +public class AvatarConstructorPreviewCell extends FrameLayout { + + private AnimatedEmojiDrawable animatedEmojiDrawable; + BackupImageView currentImage; + BackupImageView nextImage; + + Drawable currentBackgroundDrawable; + Drawable nextBackgroundDrawable; + TextView textView; + + TLRPC.TL_emojiList emojiList; + + public final boolean forUser; + private final int currentAccount = UserConfig.selectedAccount; + + int backgroundIndex = 0; + int emojiIndex = 0; + + float progressToNext = 1f; + + Runnable scheduleSwitchToNextRunnable = new Runnable() { + @Override + public void run() { + AndroidUtilities.runOnUIThread(scheduleSwitchToNextRunnable, 1000); + if (emojiList == null || emojiList.document_id.isEmpty() || progressToNext != 1f) { + + return; + } + emojiIndex++; + backgroundIndex++; + + if (emojiIndex > emojiList.document_id.size() - 1) { + emojiIndex = 0; + } + if (backgroundIndex > Theme.keys_avatar_background.length - 1) { + backgroundIndex = 0; + } + animatedEmojiDrawable = new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_LARGE, currentAccount, emojiList.document_id.get(emojiIndex)); + nextImage.setAnimatedEmojiDrawable(animatedEmojiDrawable); + + + int color1 = Theme.getColor(Theme.keys_avatar_background[backgroundIndex]); + int color2 = Theme.getColor(Theme.keys_avatar_background2[backgroundIndex]); + + nextBackgroundDrawable = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[]{color1, color2}); + + progressToNext = 0f; + invalidate(); + } + }; + + public AvatarConstructorPreviewCell(Context context, boolean forUser) { + super(context); + this.forUser = forUser; + if (forUser) { + emojiList = MediaDataController.getInstance(currentAccount).profileAvatarConstructorDefault; + } else { + emojiList = MediaDataController.getInstance(currentAccount).groupAvatarConstructorDefault; + } + + if (emojiList == null || emojiList.document_id.isEmpty()) { + ArrayList installedEmojipacks = MediaDataController.getInstance(currentAccount).getStickerSets(MediaDataController.TYPE_EMOJIPACKS); + emojiList = new TLRPC.TL_emojiList(); + if (installedEmojipacks.isEmpty()) { + ArrayList featured = MediaDataController.getInstance(currentAccount).getFeaturedEmojiSets(); + for (int i = 0; i < featured.size(); i++) { + TLRPC.StickerSetCovered set = featured.get(i); + if (set.cover != null) { + emojiList.document_id.add(set.cover.id); + } else if (set instanceof TLRPC.TL_stickerSetFullCovered) { + TLRPC.TL_stickerSetFullCovered setFullCovered = ((TLRPC.TL_stickerSetFullCovered) set); + if (!setFullCovered.documents.isEmpty()) { + emojiList.document_id.add(setFullCovered.documents.get(0).id); + } + } + } + } else { + for (int i = 0; i < installedEmojipacks.size(); i++) { + TLRPC.TL_messages_stickerSet set = installedEmojipacks.get(i); + if (!set.documents.isEmpty()) { + int index = Math.abs(Utilities.fastRandom.nextInt() % set.documents.size()); + emojiList.document_id.add(set.documents.get(index).id); + } + } + } + + } + currentImage = new BackupImageView(context); + nextImage = new BackupImageView(context); + addView(currentImage, LayoutHelper.createFrame(50, 50, Gravity.CENTER_HORIZONTAL)); + addView(nextImage, LayoutHelper.createFrame(50, 50, Gravity.CENTER_HORIZONTAL)); + + if (emojiList != null && !emojiList.document_id.isEmpty()) { + animatedEmojiDrawable = new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_LARGE, currentAccount, emojiList.document_id.get(0)); + currentImage.setAnimatedEmojiDrawable(animatedEmojiDrawable); + } + int color1 = Theme.getColor(Theme.keys_avatar_background[backgroundIndex]); + int color2 = Theme.getColor(Theme.keys_avatar_background2[backgroundIndex]); + + currentBackgroundDrawable = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[]{color1, color2}); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); + textView.setTextColor(Theme.getColor(Theme.key_avatar_text)); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setGravity(Gravity.CENTER); + textView.setText(LocaleController.getString("UseEmoji", R.string.UseEmoji)); + + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 28, Gravity.BOTTOM, 10, 10, 10, 10)); + + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int availableHeight = textView.getTop(); + int imageHeight = (int) (availableHeight * 0.7f); + int padding = (int) ((availableHeight - imageHeight) * 0.7f); + + currentImage.getLayoutParams().width = currentImage.getLayoutParams().height = imageHeight; + nextImage.getLayoutParams().width = nextImage.getLayoutParams().height = imageHeight; + ((LayoutParams) currentImage.getLayoutParams()).topMargin = padding; + ((LayoutParams) nextImage.getLayoutParams()).topMargin = padding; + } + + @Override + protected void dispatchDraw(Canvas canvas) { + if (currentBackgroundDrawable != null) { + currentBackgroundDrawable.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); + } + if (nextBackgroundDrawable != null) { + nextBackgroundDrawable.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); + } + if (progressToNext == 1f) { + currentBackgroundDrawable.setAlpha(255); + currentBackgroundDrawable.draw(canvas); + currentImage.setAlpha(1f); + currentImage.setScaleX(1f); + currentImage.setScaleY(1f); + nextImage.setAlpha(0f); + } else { + float progressInternal = CubicBezierInterpolator.DEFAULT.getInterpolation(progressToNext); + + currentBackgroundDrawable.setAlpha(255); + currentBackgroundDrawable.draw(canvas); + nextBackgroundDrawable.setAlpha((int) (255 * progressInternal)); + nextBackgroundDrawable.draw(canvas); + + progressToNext += 16 / 250f; + + currentImage.setAlpha(1f - progressInternal); + currentImage.setScaleX(1f - progressInternal); + currentImage.setScaleY(1f - progressInternal); + currentImage.setPivotY(0); + nextImage.setAlpha(progressInternal); + nextImage.setScaleX(progressInternal); + nextImage.setScaleY(progressInternal); + nextImage.setPivotY(nextImage.getMeasuredHeight()); + if (progressToNext > 1f) { + progressToNext = 1f; + currentBackgroundDrawable = nextBackgroundDrawable; + + BackupImageView tmp = currentImage; + currentImage = nextImage; + nextImage = tmp; + } + invalidate(); + } + super.dispatchDraw(canvas); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + AndroidUtilities.runOnUIThread(scheduleSwitchToNextRunnable, 1000); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + AndroidUtilities.cancelRunOnUIThread(scheduleSwitchToNextRunnable); + } + + public AvatarConstructorFragment.BackgroundGradient getBackgroundGradient() { + AvatarConstructorFragment.BackgroundGradient backgroundGradient = new AvatarConstructorFragment.BackgroundGradient(); + backgroundGradient.color1 = Theme.getColor(Theme.keys_avatar_background[backgroundIndex]); + backgroundGradient.color2 = Theme.getColor(Theme.keys_avatar_background2[backgroundIndex]); + return backgroundGradient; + } + + public AnimatedEmojiDrawable getAnimatedEmoji() { + return animatedEmojiDrawable; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java index fb9176d3f80..38f06f49976 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BackupImageView.java @@ -175,8 +175,12 @@ public void setImage(ImageLocation imageLocation, String imageFilter, ImageLocat onNewImageSet(); } - public void setImageMedia(ImageLocation mediaLocation, String mediaFilter, ImageLocation imageLocation, String imageFilter, ImageLocation thumbLocation, String thumbFilter, String ext, int size, int cacheType, Object parentObject) { - imageReceiver.setImage(mediaLocation, mediaFilter, imageLocation, imageFilter, thumbLocation, thumbFilter, null, size, ext, parentObject, cacheType); + public void setImageMedia(VectorAvatarThumbDrawable vectorAvatar, ImageLocation mediaLocation, String mediaFilter, ImageLocation imageLocation, String imageFilter, ImageLocation thumbLocation, String thumbFilter, String ext, int size, int cacheType, Object parentObject) { + if (vectorAvatar != null) { + imageReceiver.setImageBitmap(vectorAvatar); + } else { + imageReceiver.setImage(mediaLocation, mediaFilter, imageLocation, imageFilter, thumbLocation, thumbFilter, null, size, ext, parentObject, cacheType); + } onNewImageSet(); } @@ -316,6 +320,7 @@ public void setAnimatedEmojiDrawable(AnimatedEmojiDrawable animatedEmojiDrawable if (attached && animatedEmojiDrawable != null) { animatedEmojiDrawable.addView(this); } + invalidate(); } ValueAnimator roundRadiusAnimator; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotKeyboardView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotKeyboardView.java index 6a34acdefdd..b19911ebf64 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotKeyboardView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotKeyboardView.java @@ -120,18 +120,11 @@ public void setButtons(TLRPC.TL_replyKeyboardMarkup buttons) { float weight = 1.0f / row.buttons.size(); for (int b = 0; b < row.buttons.size(); b++) { TLRPC.KeyboardButton button = row.buttons.get(b); - TextView textView = new TextView(getContext()); - textView.setTag(button); - textView.setTextColor(getThemedColor(Theme.key_chat_botKeyboardButtonText)); - textView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), getThemedColor(Theme.key_chat_botKeyboardButtonBackground), getThemedColor(Theme.key_chat_botKeyboardButtonBackgroundPressed))); - textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - textView.setGravity(Gravity.CENTER); + Button textView = new Button(getContext(), button); FrameLayout frame = new FrameLayout(getContext()); frame.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - textView.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0); - textView.setText(Emoji.replaceEmoji(button.text, textView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(16), false)); layout.addView(frame, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, weight, 0, 0, b != row.buttons.size() - 1 ? 10 : 0, 0)); textView.setOnClickListener(v -> delegate.didPressedButton((TLRPC.KeyboardButton) v.getTag())); buttonViews.add(textView); @@ -151,6 +144,20 @@ public void setButtons(TLRPC.TL_replyKeyboardMarkup buttons) { } } + private class Button extends TextView { + public Button(Context context, TLRPC.KeyboardButton button) { + super(context); + + setTag(button); + setTextColor(getThemedColor(Theme.key_chat_botKeyboardButtonText)); + setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), getThemedColor(Theme.key_chat_botKeyboardButtonBackground), getThemedColor(Theme.key_chat_botKeyboardButtonBackgroundPressed))); + setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + setGravity(Gravity.CENTER); + setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0); + setText(Emoji.replaceEmoji(button.text, getPaint().getFontMetricsInt(), false)); + } + } + public int getKeyboardHeight() { if (botButtons == null) { return 0; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java index 778ee314b28..b08af4de51d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java @@ -7,6 +7,7 @@ import android.app.Activity; import android.app.Dialog; import android.content.Context; +import android.content.ContextWrapper; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; @@ -127,6 +128,8 @@ public class BotWebViewSheet extends Dialog implements NotificationCenter.Notifi private VerticalPositionAutoAnimator mainButtonAutoAnimator, radialProgressAutoAnimator; + private PasscodeView passcodeView; + private Runnable pollRunnable = () -> { if (!dismissed) { TLRPC.TL_messages_prolongWebView prolongWebView = new TLRPC.TL_messages_prolongWebView(); @@ -357,19 +360,21 @@ public void onAnimationEnd(Animator animation) { protected void onDraw(Canvas canvas) { super.onDraw(canvas); - if (!overrideBackgroundColor) { - backgroundPaint.setColor(getColor(Theme.key_windowBackgroundWhite)); - } - AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); - canvas.drawRect(AndroidUtilities.rectTmp, dimPaint); + if (passcodeView.getVisibility() != View.VISIBLE) { + if (!overrideBackgroundColor) { + backgroundPaint.setColor(getColor(Theme.key_windowBackgroundWhite)); + } + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + canvas.drawRect(AndroidUtilities.rectTmp, dimPaint); - actionBarPaint.setColor(ColorUtils.blendARGB(actionBarColor, getColor(Theme.key_windowBackgroundWhite), actionBarTransitionProgress)); - float radius = AndroidUtilities.dp(16) * (AndroidUtilities.isTablet() ? 1f : 1f - actionBarTransitionProgress); - AndroidUtilities.rectTmp.set(swipeContainer.getLeft(), AndroidUtilities.lerp(swipeContainer.getTranslationY(), 0, actionBarTransitionProgress), swipeContainer.getRight(), swipeContainer.getTranslationY() + AndroidUtilities.dp(24) + radius); - canvas.drawRoundRect(AndroidUtilities.rectTmp, radius, radius, actionBarPaint); + actionBarPaint.setColor(ColorUtils.blendARGB(actionBarColor, getColor(Theme.key_windowBackgroundWhite), actionBarTransitionProgress)); + float radius = AndroidUtilities.dp(16) * (AndroidUtilities.isTablet() ? 1f : 1f - actionBarTransitionProgress); + AndroidUtilities.rectTmp.set(swipeContainer.getLeft(), AndroidUtilities.lerp(swipeContainer.getTranslationY(), 0, actionBarTransitionProgress), swipeContainer.getRight(), swipeContainer.getTranslationY() + AndroidUtilities.dp(24) + radius); + canvas.drawRoundRect(AndroidUtilities.rectTmp, radius, radius, actionBarPaint); - AndroidUtilities.rectTmp.set(swipeContainer.getLeft(), swipeContainer.getTranslationY() + AndroidUtilities.dp(24), swipeContainer.getRight(), getHeight()); - canvas.drawRect(AndroidUtilities.rectTmp, backgroundPaint); + AndroidUtilities.rectTmp.set(swipeContainer.getLeft(), swipeContainer.getTranslationY() + AndroidUtilities.dp(24), swipeContainer.getRight(), getHeight()); + canvas.drawRect(AndroidUtilities.rectTmp, backgroundPaint); + } } @Override @@ -536,9 +541,38 @@ public void onAnimationEnd(Animator animation) { swipeContainer.setTopActionBarOffsetY(ActionBar.getCurrentActionBarHeight() + AndroidUtilities.statusBarHeight - AndroidUtilities.dp(24)); swipeContainer.setIsKeyboardVisible(obj -> frameLayout.getKeyboardHeight() >= AndroidUtilities.dp(20)); + passcodeView = new PasscodeView(context); + frameLayout.addView(passcodeView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + setContentView(frameLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); } + @Override + protected void onStart() { + super.onStart(); + + Context context = getContext(); + if (context instanceof ContextWrapper && !(context instanceof LaunchActivity)) { + context = ((ContextWrapper) context).getBaseContext(); + } + if (context instanceof LaunchActivity) { + ((LaunchActivity) context).addOverlayPasscodeView(passcodeView); + } + } + + @Override + protected void onStop() { + super.onStop(); + + Context context = getContext(); + if (context instanceof ContextWrapper && !(context instanceof LaunchActivity)) { + context = ((ContextWrapper) context).getBaseContext(); + } + if (context instanceof LaunchActivity) { + ((LaunchActivity) context).removeOverlayPasscodeView(passcodeView); + } + } + public void setParentActivity(Activity parentActivity) { this.parentActivity = parentActivity; } @@ -828,6 +862,12 @@ public void onLayoutChange(View v, int left, int top, int right, int bottom, int @Override public void onBackPressed() { + if (passcodeView.getVisibility() == View.VISIBLE) { + if (getOwnerActivity() != null) { + getOwnerActivity().finish(); + } + return; + } if (webViewContainer.onBackPressed()) { return; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java index df5aae36fe3..422dbacc411 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java @@ -41,6 +41,7 @@ import androidx.annotation.IntDef; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.core.util.Consumer; import androidx.core.view.ViewCompat; import androidx.dynamicanimation.animation.DynamicAnimation; @@ -209,6 +210,9 @@ public Bulletin show(boolean top) { layout.onAttach(this); containerLayout.addOnLayoutChangeListener(containerLayoutListener = (v, left, top1, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { + if (currentDelegate != null && !currentDelegate.allowLayoutChanges()) { + return; + } if (!top) { int newOffset = currentDelegate != null ? currentDelegate.getBottomOffset(tag) : 0; if (lastBottomOffset != newOffset) { @@ -580,6 +584,10 @@ default void onShow(Bulletin bulletin) { default void onHide(Bulletin bulletin) { } + + default boolean allowLayoutChanges() { + return true; + } } //endregion @@ -1264,6 +1272,7 @@ public void setAnimation(int resId, int w, int h, String... layers) { } public void setAnimation(TLRPC.Document document, int w, int h, String... layers) { + imageView.setAutoRepeat(true); imageView.setAnimation(document, w, h); for (String layer : layers) { imageView.setLayerColor(layer + ".**", textColor); @@ -1746,6 +1755,7 @@ public int getTopOffset(int tag) { } catch (Exception ignore) {} } + @RequiresApi(api = Build.VERSION_CODES.KITKAT_WATCH) private void applyInsets(WindowInsets insets) { if (container != null) { container.setPadding( diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java index b18cd59706c..8771b2780e1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java @@ -154,6 +154,15 @@ public Bulletin createSimpleBulletin(int iconRawId, CharSequence text) { return create(layout, text.length() < 20 ? Bulletin.DURATION_SHORT : Bulletin.DURATION_LONG); } + public Bulletin createSimpleBulletin(int iconRawId, CharSequence text, int maxLines) { + final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getContext(), resourcesProvider); + layout.setAnimation(iconRawId, 36, 36); + layout.textView.setText(text); + layout.textView.setSingleLine(false); + layout.textView.setMaxLines(maxLines); + return create(layout, text.length() < 20 ? Bulletin.DURATION_SHORT : Bulletin.DURATION_LONG); + } + public Bulletin createSimpleBulletin(int iconRawId, CharSequence text, CharSequence subtext) { final Bulletin.TwoLineLottieLayout layout = new Bulletin.TwoLineLottieLayout(getContext(), resourcesProvider); layout.setAnimation(iconRawId, 36, 36); @@ -170,6 +179,7 @@ public Bulletin createSimpleBulletin(int iconRawId, CharSequence text, CharSeque final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getContext(), resourcesProvider); layout.setAnimation(iconRawId, 36, 36); layout.textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + layout.textView.setTextDirection(View.TEXT_DIRECTION_LOCALE); layout.textView.setSingleLine(false); layout.textView.setMaxLines(3); layout.textView.setText(text); @@ -291,12 +301,28 @@ public Bulletin createEmojiBulletin(String emoji, String text, String button, Ru return createEmojiBulletin(MediaDataController.getInstance(UserConfig.selectedAccount).getEmojiAnimatedSticker(emoji), text, button, onButtonClick); } + public Bulletin createEmojiBulletin(TLRPC.Document document, CharSequence text) { + final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getContext(), resourcesProvider); + if (MessageObject.isTextColorEmoji(document)) { + layout.imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_undo_infoColor), PorterDuff.Mode.SRC_IN)); + } + layout.setAnimation(document, 36, 36); + layout.textView.setText(text); + layout.textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + layout.textView.setSingleLine(false); + layout.textView.setMaxLines(3); + return create(layout, Bulletin.DURATION_LONG); + } + public Bulletin createEmojiBulletin(TLRPC.Document document, CharSequence text, CharSequence button, Runnable onButtonClick) { final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(getContext(), resourcesProvider); if (MessageObject.isTextColorEmoji(document)) { layout.imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_undo_infoColor), PorterDuff.Mode.SRC_IN)); } layout.setAnimation(document, 36, 36); + if (layout.imageView.getImageReceiver() != null) { + layout.imageView.getImageReceiver().setRoundRadius(AndroidUtilities.dp(4)); + } layout.textView.setText(text); layout.textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); layout.textView.setSingleLine(false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CacheChart.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CacheChart.java index d1ca26bcdb3..9b6ed55c327 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CacheChart.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CacheChart.java @@ -5,7 +5,9 @@ import static org.telegram.messenger.AndroidUtilities.lerp; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.LinearGradient; @@ -35,11 +37,15 @@ public class CacheChart extends View { + public static final int TYPE_CACHE = 0; + public static final int TYPE_NETWORK = 1; + + private RectF chartMeasureBounds = new RectF(); private RectF chartBounds = new RectF(); private RectF chartInnerBounds = new RectF(); - private static final int SECTIONS_COUNT = 9; - private static final String[] colorKeys = new String[] { + private static final int DEFAULT_SECTIONS_COUNT = 9; + private static final String[] DEFAULT_COLORS = new String[] { Theme.key_statisticChartLine_lightblue, Theme.key_statisticChartLine_blue, Theme.key_statisticChartLine_green, @@ -51,7 +57,7 @@ public class CacheChart extends View { Theme.key_statisticChartLine_golden }; - private static final int[] particles = new int[] { + private static final int[] DEFAULT_PARTICLES = new int[] { R.raw.cache_photos, R.raw.cache_videos, R.raw.cache_documents, @@ -63,13 +69,19 @@ public class CacheChart extends View { R.raw.cache_other }; + private final int sectionsCount; + private final String[] colorKeys; + private final int type; + private final boolean svgParticles; + private final int[] particles; + private boolean loading = true; public AnimatedFloat loadingFloat = new AnimatedFloat(this, 750, CubicBezierInterpolator.EASE_OUT_QUINT); private boolean complete = false; - private AnimatedFloat completeFloat = new AnimatedFloat(this, 750, CubicBezierInterpolator.EASE_OUT_QUINT); + private AnimatedFloat completeFloat = new AnimatedFloat(this, 650, CubicBezierInterpolator.EASE_OUT_QUINT); - private Sector[] sectors = new Sector[SECTIONS_COUNT]; + private Sector[] sectors; private float[] segmentsTmp = new float[2]; private RectF roundingRect = new RectF(); @@ -79,12 +91,15 @@ public class CacheChart extends View { private Path completePath = new Path(); private Paint completePaintStroke = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint completePaint = new Paint(Paint.ANTI_ALIAS_FLAG); - private LinearGradient completeGradient; - private Matrix completeGradientMatrix; + private LinearGradient completeGradient, completeTextGradient; + private Matrix completeGradientMatrix, completeTextGradientMatrix; private AnimatedTextView.AnimatedTextDrawable topText = new AnimatedTextView.AnimatedTextDrawable(false, true, true); private AnimatedTextView.AnimatedTextDrawable bottomText = new AnimatedTextView.AnimatedTextDrawable(false, true, true); + private AnimatedTextView.AnimatedTextDrawable topCompleteText = new AnimatedTextView.AnimatedTextDrawable(false, true, true); + private AnimatedTextView.AnimatedTextDrawable bottomCompleteText = new AnimatedTextView.AnimatedTextDrawable(false, true, true); + private StarParticlesView.Drawable completeDrawable; private static long particlesStart = -1; @@ -244,6 +259,7 @@ private void drawParticles( float time = (now - particlesStart) / 10000f; if (particle != null) { int sz = particle.getWidth(); + float szs = AndroidUtilities.dpf2(15) / sz; float stepangle = 7f; @@ -272,7 +288,7 @@ private void drawParticles( particleAlpha = Math.max(0, Math.min(1, particleAlpha)); particlePaint.setAlpha((int) (0xFF * particleAlpha)); - float s = (float) (.75f * (.25f * (float) (Math.sin(t * Math.PI) - 1) + 1) * (.8f + (Math.sin(angle) + 1) * .25f)); + float s = szs * (float) (.75f * (.25f * (float) (Math.sin(t * Math.PI) - 1) + 1) * (.8f + (Math.sin(angle) + 1) * .25f)); canvas.save(); canvas.translate(x, y); @@ -336,14 +352,27 @@ void draw( } public CacheChart(Context context) { + this(context, DEFAULT_SECTIONS_COUNT, DEFAULT_COLORS, TYPE_CACHE, DEFAULT_PARTICLES); + } + + public CacheChart(Context context, int count, String[] colorKeys, int type, int[] particles) { super(context); + this.sectionsCount = count; + this.colorKeys = colorKeys; + this.particles = particles; + this.type = type; + this.svgParticles = type == TYPE_CACHE; + this.sectors = new Sector[this.sectionsCount]; + loadingBackgroundPaint.setStyle(Paint.Style.STROKE); loadingBackgroundPaint.setColor(Theme.getColor(Theme.key_listSelector)); completePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); completeGradient = new LinearGradient(0, 0, 0, AndroidUtilities.dp(200), new int[] { 0x006ED556, 0xFF6ED556, 0xFF41BA71, 0x0041BA71 }, new float[] { 0, .07f, .93f, 1 }, Shader.TileMode.CLAMP); + completeTextGradient = new LinearGradient(0, 0, 0, AndroidUtilities.dp(200), new int[] { 0x006ED556, 0xFF6ED556, 0xFF41BA71, 0x0041BA71 }, new float[] { 0, .07f, .93f, 1 }, Shader.TileMode.CLAMP); completeGradientMatrix = new Matrix(); + completeTextGradientMatrix = new Matrix(); completePaintStroke.setShader(completeGradient); completePaint.setShader(completeGradient); completePaintStroke.setStyle(Paint.Style.STROKE); @@ -361,7 +390,19 @@ public CacheChart(Context context) { bottomText.setTextSize(AndroidUtilities.dp(12)); bottomText.setGravity(Gravity.CENTER); - for (int i = 0; i < SECTIONS_COUNT; ++i) { + topCompleteText.setAnimationProperties(.2f, 0, 450, CubicBezierInterpolator.EASE_OUT_QUINT); + topCompleteText.getPaint().setShader(completeTextGradient); + topCompleteText.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + topCompleteText.setTextSize(AndroidUtilities.dp(32)); + topCompleteText.setGravity(Gravity.CENTER); + + bottomCompleteText.setAnimationProperties(.6f, 0, 450, CubicBezierInterpolator.EASE_OUT_QUINT); + bottomCompleteText.getPaint().setShader(completeTextGradient); + bottomCompleteText.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + bottomCompleteText.setTextSize(AndroidUtilities.dp(12)); + bottomCompleteText.setGravity(Gravity.CENTER); + + for (int i = 0; i < sectors.length; ++i) { Sector sector = sectors[i] = new Sector(); final int color2 = Theme.blendOver(Theme.getColor(colorKeys[i]), 0x03000000); final int color1 = Theme.blendOver(Theme.getColor(colorKeys[i]), 0x30ffffff); @@ -369,7 +410,40 @@ public CacheChart(Context context) { sector.gradient = new RadialGradient(0, 0, dp(86), new int[]{ color1, color2 }, new float[] { .3f, 1 }, Shader.TileMode.CLAMP); sector.gradient.setLocalMatrix(sector.gradientMatrix = new Matrix()); sector.paint.setShader(sector.gradient); - sector.particle = SvgHelper.getBitmap(particles[i], AndroidUtilities.dp(16), AndroidUtilities.dp(16), 0xffffffff); + } + } + + private boolean interceptTouch = true; + public void setInterceptTouch(boolean value) { + this.interceptTouch = value; + } + + private boolean isAttached; + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + isAttached = true; + for (int i = 0; i < sectors.length; ++i) { + if (sectors[i].particle == null) { + if (svgParticles) { + sectors[i].particle = SvgHelper.getBitmap(particles[i], AndroidUtilities.dp(16), AndroidUtilities.dp(16), 0xffffffff); + } else { + sectors[i].particle = BitmapFactory.decodeResource(getContext().getResources(), particles[i]); + } + } + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + isAttached = false; + for (int i = 0; i < sectors.length; ++i) { + if (sectors[i].particle != null) { + sectors[i].particle.recycle(); + sectors[i].particle = null; + } } } @@ -399,7 +473,7 @@ public boolean dispatchTouchEvent(MotionEvent event) { setSelected(index); if (index >= 0) { onSectionDown(index, index != -1); - if (getParent() != null) { + if (getParent() != null && interceptTouch) { getParent().requestDisallowInterceptTouchEvent(true); } } @@ -459,8 +533,12 @@ public void setSelected(int index) { public static class SegmentSize { int index; - boolean selected; - long size; + public boolean selected; + public long size; + + public static SegmentSize of(long size) { + return of(size, true); + } public static SegmentSize of(long size, boolean selected) { SegmentSize segment = new SegmentSize(); @@ -470,20 +548,35 @@ public static SegmentSize of(long size, boolean selected) { } } - public void setSegments(long totalSize, SegmentSize ...segments) { + public void setSegments(long totalSize, boolean animated, SegmentSize ...segments) { if (segments == null || segments.length == 0) { - loading = true; + loading = false; complete = totalSize == 0; - topText.setText(""); - bottomText.setText(""); + if (!animated) { + loadingFloat.set(loading ? 1 : 0, true); + completeFloat.set(complete ? 1 : 0, true); + } + topCompleteText.setText(topText.getText(), false); + topText.setText("0", animated); + topCompleteText.setText("0", animated); + + bottomCompleteText.setText(bottomText.getText(), false); + bottomText.setText("KB", animated); + bottomCompleteText.setText("KB", animated); for (int i = 0; i < sectors.length; ++i) { sectors[i].textAlpha = 0; + if (!animated) { + sectors[i].textAlphaAnimated.set(0, true); + } } invalidate(); return; } loading = false; + if (!animated) { + loadingFloat.set(0, true); + } SpannableString percent = new SpannableString("%"); // percent.setSpan(new RelativeSizeSpan(0.733f), 0, percent.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); @@ -505,12 +598,23 @@ public void setSegments(long totalSize, SegmentSize ...segments) { } if (segmentsSum <= 0) { - loading = true; + loading = false; complete = totalSize <= 0; - topText.setText(""); - bottomText.setText(""); + if (!animated) { + loadingFloat.set(loading ? 1 : 0, true); + completeFloat.set(complete ? 1 : 0, true); + } + topCompleteText.setText(topText.getText(), false); + topText.setText("0", animated); + topCompleteText.setText("0", animated); + bottomCompleteText.setText(bottomText.getText(), false); + bottomText.setText("KB", animated); + bottomCompleteText.setText("KB", animated); for (int i = 0; i < sectors.length; ++i) { sectors[i].textAlpha = 0; + if (!animated) { + sectors[i].textAlphaAnimated.set(0, true); + } } invalidate(); return; @@ -537,14 +641,16 @@ public void setSegments(long totalSize, SegmentSize ...segments) { tempFloat[i] = segments[i] == null || !segments[i].selected ? 0 : segments[i].size / (float) segmentsSum; } AndroidUtilities.roundPercents(tempFloat, tempPercents); - Arrays.sort(segments, (a, b) -> Long.compare(a.size, b.size)); - for (int i = 0; i < segments.length - 1; ++i) { - if (segments[i].index == segments.length - 1) { - int from = i, to = 0; - SegmentSize temp = segments[to]; - segments[to] = segments[from]; - segments[from] = temp; - break; + if (type == TYPE_CACHE) { // putting "other" section to being the first one + Arrays.sort(segments, (a, b) -> Long.compare(a.size, b.size)); + for (int i = 0; i < segments.length - 1; ++i) { + if (segments[i].index == segments.length - 1) { + int from = i, to = 0; + SegmentSize temp = segments[to]; + segments[to] = segments[from]; + segments[from] = temp; + break; + } } } @@ -559,8 +665,13 @@ public void setSegments(long totalSize, SegmentSize ...segments) { sectors[i].textAlpha = progress > .05 && progress < 1 ? 1f : 0f; sectors[i].textScale = progress < .08f || tempPercents[i] >= 100 ? .85f : 1f; sectors[i].particlesAlpha = 1; + if (!animated) { + sectors[i].textAlphaAnimated.set(sectors[i].textAlpha, true); + sectors[i].textScaleAnimated.set(sectors[i].textScale, true); + sectors[i].particlesAlphaAnimated.set(sectors[i].particlesAlpha, true); + } if (sectors[i].textAlpha > 0) { - sectors[i].text.setText(string); + sectors[i].text.setText(string, animated); } if (progress < .02f && progress > 0) { progress = .02f; @@ -573,10 +684,19 @@ public void setSegments(long totalSize, SegmentSize ...segments) { sectors[i].angleCenter = (angleFrom + angleTo) / 2; sectors[i].angleSize = Math.abs(angleTo - angleFrom) / 2; sectors[i].textAlpha = 0; + if (!animated) { + sectors[i].angleCenterAnimated.set(sectors[i].angleCenter, true); + sectors[i].angleSizeAnimated.set(sectors[i].angleSize, true); + sectors[i].textAlphaAnimated.set(sectors[i].textAlpha, true); + } continue; } sectors[i].angleCenter = (angleFrom + angleTo) / 2; sectors[i].angleSize = Math.abs(angleTo - angleFrom) / 2; + if (!animated) { + sectors[i].angleCenterAnimated.set(sectors[i].angleCenter, true); + sectors[i].angleSizeAnimated.set(sectors[i].angleSize, true); + } prev += progress; k++; } @@ -586,9 +706,17 @@ public void setSegments(long totalSize, SegmentSize ...segments) { if (top.length() >= 4 && segmentsSum < 1024L * 1024L * 1024L) { top = top.split("\\.")[0]; } - topText.setText(top); - bottomText.setText(fileSize.length > 1 ? fileSize[1] : ""); + topText.setText(top, animated); + bottomText.setText(fileSize.length > 1 ? fileSize[1] : "", animated); + if (completeFloat.get() > 0) { + topCompleteText.setText(topText.getText(), animated); + bottomCompleteText.setText(bottomText.getText(), animated); + } + complete = false; + if (!animated) { + completeFloat.set(complete ? 1 : 0, true); + } invalidate(); } @@ -618,8 +746,12 @@ protected void dispatchDraw(Canvas canvas) { final float loading = loadingFloat.set(this.loading ? 1f : 0f); final float complete = completeFloat.set(this.complete ? 1f : 0f); + chartBounds.set(chartMeasureBounds); + final float minusDp = lerp(0, dpf2(padInsideDp()), complete); + chartBounds.inset(minusDp, minusDp); + chartInnerBounds.set(chartBounds); - final float thickness = lerp(dpf2(38), dpf2(10), loading); + final float thickness = lerp(dpf2(38), dpf2(10), Math.max(loading, complete)); chartInnerBounds.inset(thickness, thickness); final float rounding = lerp(0, dp(60), loading); @@ -647,7 +779,7 @@ protected void dispatchDraw(Canvas canvas) { boolean wouldUpdate = loading > 0 || complete > 0; - for (int i = 0; i < SECTIONS_COUNT; ++i) { + for (int i = 0; i < sectors.length; ++i) { Sector sector = sectors[i]; CircularProgressDrawable.getSegments((loadingTime + i * 80) % 5400, segmentsTmp); @@ -672,30 +804,47 @@ protected void dispatchDraw(Canvas canvas) { sector.draw(canvas, chartBounds, chartInnerBounds, angleCenter, angleSize, rounding, 1f - complete, 1f - loading); } - topText.setAlpha((int) (255 * (1f - loading) * (1f - complete))); - topText.setBounds((int) (chartBounds.centerX()), (int) (chartBounds.centerY() - AndroidUtilities.dp(5)), (int) (chartBounds.centerX()), (int) (chartBounds.centerY() - AndroidUtilities.dp(3))); - topText.draw(canvas); - wouldUpdate = topText.isAnimating() || wouldUpdate; - - bottomText.setAlpha((int) (255 * (1f - loading) * (1f - complete))); - bottomText.setBounds((int) (chartBounds.centerX()), (int) (chartBounds.centerY() + AndroidUtilities.dp(22)), (int) (chartBounds.centerX()), (int) (chartBounds.centerY() + AndroidUtilities.dp(22))); - bottomText.draw(canvas); - wouldUpdate = bottomText.isAnimating() || wouldUpdate; + if (type == TYPE_CACHE) { + float textAlpha = (1f - loading) * (1f - complete); + float topTextX = chartBounds.centerX(); + float topTextY = chartBounds.centerY() - dpf2(5); + wouldUpdate = drawAnimatedText(canvas, topText, topTextX, topTextY, 1f, textAlpha) || wouldUpdate; + + float bottomTextX = chartBounds.centerX(); + float bottomTextY = chartBounds.centerY() + dpf2(22); + wouldUpdate = drawAnimatedText(canvas, bottomText, bottomTextX, bottomTextY, 1f, textAlpha) || wouldUpdate; + } else if (type == TYPE_NETWORK) { + float textAlpha = 1f - loading; + float topTextX = chartBounds.centerX() - AndroidUtilities.lerp(0, dpf2(4), complete); + float topTextY = chartBounds.centerY() - AndroidUtilities.lerp(dpf2(5), 0, complete); + float topTextScale = AndroidUtilities.lerp(1f, 2.25f, complete); + wouldUpdate = drawAnimatedText(canvas, topCompleteText, topTextX, topTextY, topTextScale, textAlpha * complete) || wouldUpdate; + wouldUpdate = drawAnimatedText(canvas, topText, topTextX, topTextY, topTextScale, textAlpha * (1f - complete)) || wouldUpdate; + + float bottomTextX = chartBounds.centerX() + AndroidUtilities.lerp(0, dpf2(26), complete); + float bottomTextY = chartBounds.centerY() + AndroidUtilities.lerp(dpf2(22), -dpf2(18), complete); + float bottomTextScale = AndroidUtilities.lerp(1f, 1.4f, complete); + wouldUpdate = drawAnimatedText(canvas, bottomCompleteText, bottomTextX, bottomTextY, bottomTextScale, textAlpha * complete) || wouldUpdate; + wouldUpdate = drawAnimatedText(canvas, bottomText, bottomTextX, bottomTextY, bottomTextScale, textAlpha * (1f - complete)) || wouldUpdate; + } if (complete > 0) { + boolean init = false; if (completeDrawable == null) { completeDrawable = new StarParticlesView.Drawable(25); completeDrawable.type = 100; - completeDrawable.roundEffect = false; + completeDrawable.roundEffect = true; completeDrawable.useRotate = true; completeDrawable.useBlur = false; completeDrawable.checkBounds = true; completeDrawable.size1 = 18; completeDrawable.distributionAlgorithm = false; completeDrawable.excludeRadius = AndroidUtilities.dp(80); - completeDrawable.k1 = completeDrawable.k2 = completeDrawable.k3 = 0.7f; + completeDrawable.k1 = completeDrawable.k2 = completeDrawable.k3 = .85f; completeDrawable.init(); - + init = true; + } + if (init || completePathBounds == null || !completePathBounds.equals(chartMeasureBounds)) { float d = Math.min(getMeasuredHeight(), Math.min(getMeasuredWidth(), AndroidUtilities.dp(150))); completeDrawable.rect.set(0, 0, d, d); completeDrawable.rect.offset((getMeasuredWidth() - completeDrawable.rect.width()) / 2, (getMeasuredHeight() - completeDrawable.rect.height()) / 2); @@ -713,36 +862,71 @@ protected void dispatchDraw(Canvas canvas) { completePaintStroke.setAlpha((int) (0xFF * complete)); canvas.drawCircle(chartBounds.centerX(), chartBounds.centerY(), (chartBounds.width() - thickness) / 2, completePaintStroke); - if (completePathBounds == null || completePathBounds.equals(chartBounds)) { + if (completePathBounds == null || !completePathBounds.equals(chartMeasureBounds)) { if (completePathBounds == null) { completePathBounds = new RectF(); } - completePathBounds.set(chartBounds); + completePathBounds.set(chartMeasureBounds); completePath.rewind(); - completePath.moveTo(chartBounds.left + chartBounds.width() * .348f, chartBounds.top + chartBounds.height() * .538f); - completePath.lineTo(chartBounds.left + chartBounds.width() * .447f, chartBounds.top + chartBounds.height() * .636f); - completePath.lineTo(chartBounds.left + chartBounds.width() * .678f, chartBounds.top + chartBounds.height() * .402f); + if (type == TYPE_CACHE) { + completePath.moveTo(chartBounds.width() * .348f, chartBounds.height() * .538f); + completePath.lineTo(chartBounds.width() * .447f, chartBounds.height() * .636f); + completePath.lineTo(chartBounds.width() * .678f, chartBounds.height() * .402f); + } else if (type == TYPE_NETWORK) { + completePath.moveTo(chartBounds.width() * .2929f, chartBounds.height() * .4369f); + completePath.lineTo(chartBounds.width() * .381f, chartBounds.height() * .35f); + completePath.lineTo(chartBounds.width() * .4691f, chartBounds.height() * .4369f); + completePath.moveTo(chartBounds.width() * .381f, chartBounds.height() * .35f); + completePath.lineTo(chartBounds.width() * .381f, chartBounds.height() * .6548f); + + completePath.moveTo(chartBounds.width() * .5214f, chartBounds.height() * .5821f); + completePath.lineTo(chartBounds.width() * .6095f, chartBounds.height() * .669f); + completePath.lineTo(chartBounds.width() * .6976f, chartBounds.height() * .5821f); + completePath.moveTo(chartBounds.width() * .6095f, chartBounds.height() * .669f); + completePath.lineTo(chartBounds.width() * .6095f, chartBounds.height() * .3643f); + } + completePath.offset(chartBounds.left, chartBounds.top); + } + if (type == TYPE_CACHE) { + completePaintStroke.setStrokeWidth(dpf2(10)); + canvas.drawPath(completePath, completePaintStroke); } - completePaintStroke.setStrokeWidth(AndroidUtilities.dp(10)); - canvas.drawPath(completePath, completePaintStroke); } - if (wouldUpdate || true) { + if ((wouldUpdate || true) && isAttached) { invalidate(); } } + private boolean drawAnimatedText(Canvas canvas, AnimatedTextView.AnimatedTextDrawable textDrawable, float x, float y, float scale, float alpha) { + if (alpha <= 0) { + return false; + } + textDrawable.setAlpha((int) (0xFF * alpha)); + textDrawable.setBounds(0, 0, 0, 0); + canvas.save(); + canvas.translate(x, y); + canvas.scale(scale, scale); + textDrawable.draw(canvas); + canvas.restore(); + return textDrawable.isAnimating(); + } + protected int heightDp() { return 200; } + protected int padInsideDp() { + return 0; + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int width = MeasureSpec.getSize(widthMeasureSpec); final int height = dp(heightDp()); final int d = dp(172); - chartBounds.set( + chartMeasureBounds.set( (width - d) / 2f, (height - d) / 2f, (width + d) / 2f, @@ -750,8 +934,11 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { ); completeGradientMatrix.reset(); - completeGradientMatrix.setTranslate(chartBounds.left, 0); + completeGradientMatrix.setTranslate(chartMeasureBounds.left, 0); completeGradient.setLocalMatrix(completeGradientMatrix); + completeTextGradientMatrix.reset(); + completeTextGradientMatrix.setTranslate(chartMeasureBounds.left, -chartMeasureBounds.centerY()); + completeTextGradient.setLocalMatrix(completeTextGradientMatrix); if (completeDrawable != null) { completeDrawable.rect.set(0, 0, AndroidUtilities.dp(140), AndroidUtilities.dp(140)); @@ -765,4 +952,10 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) ); } + + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + requestLayout(); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CanvasButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CanvasButton.java index 97303f65a1d..818635b1d0f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CanvasButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CanvasButton.java @@ -260,4 +260,9 @@ public void cancelRipple() { } } + + public void setRect(int x, int y, int x1, int y1) { + AndroidUtilities.rectTmp.set(x, y, x1, y1); + setRect(AndroidUtilities.rectTmp); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java index ebd0c99a3bc..96e8f52d481 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java @@ -114,6 +114,7 @@ import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; +import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.NotificationsController; import org.telegram.messenger.R; @@ -127,6 +128,7 @@ import org.telegram.messenger.browser.Browser; import org.telegram.messenger.camera.CameraController; import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.SerializedData; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenuSubItem; @@ -159,6 +161,9 @@ public class ChatActivityEnterView extends BlurredFrameLayout implements NotificationCenter.NotificationCenterDelegate, SizeNotifierFrameLayout.SizeNotifierFrameLayoutDelegate, StickersAlert.StickersAlertDelegate { + private final int commonInputType; + private boolean stickersEnabled; + public interface ChatActivityEnterViewDelegate { default void onEditTextScroll() {}; @@ -312,6 +317,12 @@ default TLRPC.TL_channels_sendAsPeers getSendAsPeers() { private float searchToOpenProgress; private float chatSearchExpandOffset; + private boolean sendRoundEnabled = true; + private boolean sendVoiceEnabled = true; + private boolean sendPlainEnabled = true; + private boolean emojiButtonRestricted; + + private HashMap animationParamsX = new HashMap<>(); private class SeekBarWaveformView extends View { @@ -1844,6 +1855,10 @@ protected void onDraw(Canvas canvas) { if (adjustPanLayoutHelper != null && adjustPanLayoutHelper.animationInProgress()) { return; } + if (emojiButtonRestricted) { + showRestrictedHint(); + return; + } if (hasBotWebView() && botCommandsMenuIsShowing()) { botWebViewMenuContainer.dismiss(v::callOnClick); return; @@ -1885,6 +1900,8 @@ protected void onDraw(Canvas canvas) { messageEditText = new EditTextCaption(context, resourcesProvider) { + CanvasButton canvasButton; + @Override protected void onScrollChanged(int horiz, int vert, int oldHoriz, int oldVert) { super.onScrollChanged(horiz, vert, oldHoriz, oldVert); @@ -1958,6 +1975,16 @@ public boolean onTouchEvent(MotionEvent event) { if (stickersDragging || stickersExpansionAnim != null) { return false; } + if (!sendPlainEnabled && !isEditingMessage()) { + if (canvasButton == null) { + canvasButton = new CanvasButton(this); + canvasButton.setDelegate(() -> { + showRestrictedHint(); + }); + } + canvasButton.setRect(0, 0, getMeasuredWidth(), getMeasuredHeight()); + return canvasButton.checkTouchEvent(event); + } if (isPopupShowing() && event.getAction() == MotionEvent.ACTION_DOWN) { if (searchingType != 0) { setSearchingTypeInternal(0, false); @@ -2131,6 +2158,22 @@ public boolean canCaptureMorePhotos() { protected Theme.ResourcesProvider getResourcesProvider() { return resourcesProvider; } + + @Override + public boolean requestFocus(int direction, Rect previouslyFocusedRect) { + if (!sendPlainEnabled && !isEditingMessage()) { + return false; + } + return super.requestFocus(direction, previouslyFocusedRect); + } + + @Override + public void setOffsetY(float offset) { + super.setOffsetY(offset); + if (sizeNotifierLayout.getForeground() != null) { + sizeNotifierLayout.invalidateDrawable(sizeNotifierLayout.getForeground()); + } + } }; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { messageEditText.setFallbackLineSpacing(false); @@ -2145,13 +2188,13 @@ protected Theme.ResourcesProvider getResourcesProvider() { messageEditText.setWindowView(parentActivity.getWindow().getDecorView()); TLRPC.EncryptedChat encryptedChat = parentFragment != null ? parentFragment.getCurrentEncryptedChat() : null; messageEditText.setAllowTextEntitiesIntersection(supportsSendingNewEntities()); - updateFieldHint(false); int flags = EditorInfo.IME_FLAG_NO_EXTRACT_UI; if (encryptedChat != null) { flags |= 0x01000000; //EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING; } messageEditText.setImeOptions(flags); - messageEditText.setInputType(messageEditText.getInputType() | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE); + messageEditText.setInputType(commonInputType = (messageEditText.getInputType() | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE)); + updateFieldHint(false); messageEditText.setSingleLine(false); messageEditText.setMaxLines(6); messageEditText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); @@ -2166,6 +2209,7 @@ protected Theme.ResourcesProvider getResourcesProvider() { messageEditText.setCursorColor(getThemedColor(Theme.key_chat_messagePanelCursor)); messageEditText.setHandlesColor(getThemedColor(Theme.key_chat_TextSelectionCursor)); frameLayout.addView(messageEditText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM, 52, 0, isChat ? 50 : 2, 0)); + ((LayoutParams) messageEditText.getLayoutParams()).bottomMargin = AndroidUtilities.dp(1.5f); messageEditText.setOnKeyListener(new OnKeyListener() { boolean ctrlPressed = false; @@ -2555,6 +2599,8 @@ public void onDismiss() { if (botReplyMarkup != null) { if (!isPopupShowing() || currentPopupContentType != POPUP_CONTENT_BOT_KEYBOARD) { showPopup(1, POPUP_CONTENT_BOT_KEYBOARD); + } else if (isPopupShowing() && currentPopupContentType == POPUP_CONTENT_BOT_KEYBOARD) { + showPopup(0, POPUP_CONTENT_BOT_KEYBOARD); } } else if (hasBotCommands) { setFieldText("/"); @@ -3107,7 +3153,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { if (parentFragment != null) { TLRPC.Chat chat = parentFragment.getCurrentChat(); TLRPC.UserFull userFull = parentFragment.getCurrentUserInfo(); - if (chat != null && !ChatObject.canSendMedia(chat) || userFull != null && userFull.voice_messages_forbidden) { + if (chat != null && !(ChatObject.canSendVoice(chat) || (ChatObject.canSendRoundVideo(chat) && hasRecordVideo)) || userFull != null && userFull.voice_messages_forbidden) { delegate.needShowMediaBanHint(); return true; } @@ -3161,8 +3207,12 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { } else { if (recordAudioVideoRunnableStarted) { AndroidUtilities.cancelRunOnUIThread(recordAudioVideoRunnable); - delegate.onSwitchRecordMode(!isInVideoMode()); - setRecordVideoButtonVisible(!isInVideoMode(), true); + if (sendVoiceEnabled && sendRoundEnabled) { + delegate.onSwitchRecordMode(!isInVideoMode()); + setRecordVideoButtonVisible(!isInVideoMode(), true); + } else { + delegate.needShowMediaBanHint(); + } performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP); sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); } else if (!hasRecordVideo || calledRecordRunnable) { @@ -3170,6 +3220,8 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { if (hasRecordVideo && isInVideoMode()) { CameraController.getInstance().cancelOnInitRunnable(onFinishInitCameraRunnable); delegate.needStartRecordVideo(1, true, 0); + } else if (!sendVoiceEnabled) { + delegate.needShowMediaBanHint(); } else { if (recordingAudioVideo && isInScheduleMode()) { AlertsCreator.createScheduleDatePickerDialog(parentActivity, parentFragment.getDialogId(), (notify, scheduleDate) -> MediaController.getInstance().stopRecording(1, notify, scheduleDate), () -> MediaController.getInstance().stopRecording(0, false, 0), resourcesProvider); @@ -3515,6 +3567,13 @@ public boolean onTouchEvent(MotionEvent event) { frameLayout.addView(botWebViewButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.BOTTOM)); } + private void showRestrictedHint() { + if (DialogObject.isChatDialog(dialog_id)) { + TLRPC.Chat chat = accountInstance.getMessagesController().getChat(-dialog_id); + BulletinFactory.of(parentFragment).createSimpleBulletin(R.raw.passcode_lock_close, LocaleController.formatString("SendPlainTextRestrictionHint", R.string.SendPlainTextRestrictionHint, ChatObject.getAllowedSendString(chat)), 3).show(); + } + } + private void openWebViewMenu() { Runnable onRequestWebView = () -> { AndroidUtilities.hideKeyboard(this); @@ -4291,14 +4350,44 @@ public void checkChannelRights() { } TLRPC.Chat chat = parentFragment.getCurrentChat(); TLRPC.UserFull userFull = parentFragment.getCurrentUserInfo(); + emojiButtonRestricted = false; + stickersEnabled = true; + sendPlainEnabled = true; + sendRoundEnabled = true; + sendVoiceEnabled = true; if (chat != null) { - audioVideoButtonContainer.setAlpha(ChatObject.canSendMedia(chat) ? 1.0f : 0.5f); - if (emojiView != null) { - emojiView.setStickersBanned(!ChatObject.canSendStickers(chat), chat.id); + audioVideoButtonContainer.setAlpha(ChatObject.canSendVoice(chat) || (ChatObject.canSendRoundVideo(chat) && hasRecordVideo)? 1.0f : 0.5f); + + stickersEnabled = ChatObject.canSendStickers(chat); + sendPlainEnabled = ChatObject.canSendPlain(chat); + sendPlainEnabled = ChatObject.canSendPlain(chat); + emojiButtonRestricted = !stickersEnabled && !sendPlainEnabled; + emojiButton.setAlpha(emojiButtonRestricted ? 0.5f : 1.0f); + if (!emojiButtonRestricted) { + if (emojiView != null) { + emojiView.setStickersBanned(!ChatObject.canSendPlain(chat), !ChatObject.canSendStickers(chat), chat.id); + } } + sendRoundEnabled = ChatObject.canSendRoundVideo(chat); + sendVoiceEnabled = ChatObject.canSendVoice(chat); + } else if (userFull != null) { audioVideoButtonContainer.setAlpha(userFull.voice_messages_forbidden ? 0.5f : 1.0f); } + updateFieldHint(false); + + boolean currentModeVideo = isInVideoMode; + if (!sendRoundEnabled && currentModeVideo) { + currentModeVideo = false; + } + if (!sendVoiceEnabled && !currentModeVideo) { + if (hasRecordVideo) { + currentModeVideo = true; + } else { + currentModeVideo = false; + } + } + setRecordVideoButtonVisible(currentModeVideo, false); } public void onBeginHide() { @@ -4400,8 +4489,15 @@ public void setDialogId(long id, int account) { NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.sendingMessagesChanged); } + sendPlainEnabled = true; + if (DialogObject.isChatDialog(dialog_id)) { + TLRPC.Chat chat = accountInstance.getMessagesController().getChat(-dialog_id); + sendPlainEnabled = ChatObject.canSendPlain(chat); + } + updateScheduleButton(false); checkRoundVideo(); + checkChannelRights(); updateFieldHint(false); updateSendAsButton(parentFragment != null && parentFragment.getFragmentBeginToShow()); } @@ -4424,6 +4520,8 @@ public void checkRoundVideo() { return; } hasRecordVideo = true; + sendRoundEnabled = true; + sendVoiceEnabled = true; boolean isChannel = false; if (DialogObject.isChatDialog(dialog_id)) { TLRPC.Chat chat = accountInstance.getMessagesController().getChat(-dialog_id); @@ -4431,20 +4529,32 @@ public void checkRoundVideo() { if (isChannel && !chat.creator && (chat.admin_rights == null || !chat.admin_rights.post_messages)) { hasRecordVideo = false; } + sendRoundEnabled = ChatObject.canSendRoundVideo(chat); + sendVoiceEnabled = ChatObject.canSendVoice(chat); } if (!SharedConfig.inappCamera) { hasRecordVideo = false; } + boolean currentModeVideo = false; if (hasRecordVideo) { if (SharedConfig.hasCameraCache) { CameraController.getInstance().initCamera(null); } SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - boolean currentModeVideo = preferences.getBoolean(isChannel ? "currentModeVideoChannel" : "currentModeVideo", isChannel); - setRecordVideoButtonVisible(currentModeVideo, false); - } else { - setRecordVideoButtonVisible(false, false); + currentModeVideo = preferences.getBoolean(isChannel ? "currentModeVideoChannel" : "currentModeVideo", isChannel); + } + + if (!sendRoundEnabled && currentModeVideo) { + currentModeVideo = false; + } + if (!sendVoiceEnabled && !currentModeVideo) { + if (hasRecordVideo) { + currentModeVideo = true; + } else { + currentModeVideo = false; + } } + setRecordVideoButtonVisible(currentModeVideo, false); } public boolean isInVideoMode() { @@ -4460,6 +4570,18 @@ public MessageObject getReplyingMessageObject() { } public void updateFieldHint(boolean animated) { + if (!sendPlainEnabled && !isEditingMessage()) { + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(" d " + LocaleController.getString("PlainTextRestrictedHint", R.string.PlainTextRestrictedHint)); + spannableStringBuilder.setSpan(new ColoredImageSpan(R.drawable.msg_mini_lock3), 1, 2, 0); + messageEditText.setHintText(spannableStringBuilder, animated); + messageEditText.setText(null); + messageEditText.setEnabled(false); + messageEditText.setInputType(EditorInfo.IME_ACTION_NONE); + return; + } else { + messageEditText.setEnabled(true); + messageEditText.setInputType(commonInputType); + } if (replyingMessageObject != null && replyingMessageObject.messageOwner.reply_markup != null && !TextUtils.isEmpty(replyingMessageObject.messageOwner.reply_markup.placeholder)) { messageEditText.setHintText(replyingMessageObject.messageOwner.reply_markup.placeholder, animated); } else if (editingMessageObject != null) { @@ -4551,7 +4673,7 @@ private void hideRecordedAudioPanel(boolean wasSent) { recordPannelAnimation = new AnimatorSet(); recordPannelAnimation.playTogether( - ObjectAnimator.ofFloat(emojiButton, View.ALPHA, 1.0f), + ObjectAnimator.ofFloat(emojiButton, View.ALPHA, emojiButtonRestricted ? 0.5f : 1.0f), ObjectAnimator.ofFloat(emojiButton, View.SCALE_X, 1.0f), ObjectAnimator.ofFloat(emojiButton, View.SCALE_Y, 1.0f), ObjectAnimator.ofFloat(recordDeleteImageView, View.ALPHA, 0.0f), @@ -4642,7 +4764,7 @@ public void onAnimationEnd(Animator animation) { ObjectAnimator.ofFloat(recordDeleteImageView, View.SCALE_Y, 0.0f), ObjectAnimator.ofFloat(recordDeleteImageView, View.ALPHA, 0.0f), - ObjectAnimator.ofFloat(emojiButton, View.ALPHA, 1.0f), + ObjectAnimator.ofFloat(emojiButton, View.ALPHA, emojiButtonRestricted ? 0.5f : 1.0f), ObjectAnimator.ofFloat(emojiButton, View.SCALE_X, 1.0f), ObjectAnimator.ofFloat(emojiButton, View.SCALE_Y, 1.0f) ); @@ -4793,9 +4915,6 @@ public static boolean checkPremiumAnimatedEmoji(int currentAccount, long dialogI if (message == null || parentFragment == null) { return false; } - if (container == null) { - container = parentFragment.getLayoutContainer(); - } final boolean isPremium = UserConfig.getInstance(currentAccount).isPremium(); if (!isPremium && UserConfig.getInstance(currentAccount).getClientUserId() != dialogId && message instanceof Spanned) { AnimatedEmojiSpan[] animatedEmojis = ((Spanned) message).getSpans(0, message.length(), AnimatedEmojiSpan.class); @@ -4806,20 +4925,75 @@ public static boolean checkPremiumAnimatedEmoji(int currentAccount, long dialogI if (emoji == null) { emoji = AnimatedEmojiDrawable.findDocument(currentAccount, animatedEmojis[i].getDocumentId()); } - if (emoji != null && !MessageObject.isFreeEmoji(emoji)) { - BulletinFactory.of(container, parentFragment.getResourceProvider()) - .createEmojiBulletin( - emoji, - AndroidUtilities.replaceTags(LocaleController.getString("UnlockPremiumEmojiHint", R.string.UnlockPremiumEmojiHint)), - LocaleController.getString("PremiumMore", R.string.PremiumMore), - () -> { - if (parentFragment != null) { - new PremiumFeatureBottomSheet(parentFragment, PremiumPreviewFragment.PREMIUM_FEATURE_ANIMATED_EMOJI, false).show(); - } else if (parentFragment.getContext() instanceof LaunchActivity) { - ((LaunchActivity) parentFragment.getContext()).presentFragment(new PremiumPreviewFragment(null)); - } - } - ).show(); + long documentId = animatedEmojis[i].getDocumentId(); + if (emoji == null) { + ArrayList sets1 = MediaDataController.getInstance(currentAccount).getStickerSets(MediaDataController.TYPE_EMOJIPACKS); + for (TLRPC.TL_messages_stickerSet set : sets1) { + if (set != null && set.documents != null && !set.documents.isEmpty()) { + for (TLRPC.Document document : set.documents) { + if (document.id == documentId) { + emoji = document; + break; + } + } + } + if (emoji != null) { + break; + } + } + } + if (emoji == null) { + ArrayList sets2 = MediaDataController.getInstance(currentAccount).getFeaturedEmojiSets(); + for (TLRPC.StickerSetCovered set : sets2) { + if (set != null && set.covers != null && !set.covers.isEmpty()) { + for (TLRPC.Document document : set.covers) { + if (document.id == documentId) { + emoji = document; + break; + } + } + } + if (emoji != null) { + break; + } + ArrayList documents = null; + if (set instanceof TLRPC.TL_stickerSetFullCovered) { + documents = ((TLRPC.TL_stickerSetFullCovered) set).documents; + } else if (set instanceof TLRPC.TL_stickerSetNoCovered && set.set != null) { + TLRPC.TL_inputStickerSetID inputStickerSetID = new TLRPC.TL_inputStickerSetID(); + inputStickerSetID.id = set.set.id; + TLRPC.TL_messages_stickerSet fullSet = MediaDataController.getInstance(currentAccount).getStickerSet(inputStickerSetID, true); + if (fullSet != null && fullSet.documents != null) { + documents = fullSet.documents; + } + } + if (documents != null && !documents.isEmpty()) { + for (TLRPC.Document document : documents) { + if (document.id == documentId) { + emoji = document; + break; + } + } + } + if (emoji != null) { + break; + } + } + } + if (emoji == null || !MessageObject.isFreeEmoji(emoji)) { + BulletinFactory.of(parentFragment) + .createEmojiBulletin( + emoji, + AndroidUtilities.replaceTags(LocaleController.getString("UnlockPremiumEmojiHint", R.string.UnlockPremiumEmojiHint)), + LocaleController.getString("PremiumMore", R.string.PremiumMore), + () -> { + if (parentFragment != null) { + new PremiumFeatureBottomSheet(parentFragment, PremiumPreviewFragment.PREMIUM_FEATURE_ANIMATED_EMOJI, false).show(); + } else if (parentFragment.getContext() instanceof LaunchActivity) { + ((LaunchActivity) parentFragment.getContext()).presentFragment(new PremiumPreviewFragment(null)); + } + } + ).show(); return true; } } @@ -5564,7 +5738,7 @@ public void onAnimationCancel(Animator animation) { TLRPC.Chat chat = parentFragment.getCurrentChat(); TLRPC.UserFull userFull = parentFragment.getCurrentUserInfo(); if (chat != null) { - alpha = ChatObject.canSendMedia(chat) ? 1.0f : 0.5f; + alpha = (ChatObject.canSendVoice(chat) || ChatObject.canSendRoundVideo(chat)) ? 1.0f : 0.5f; } else if (userFull != null) { alpha = userFull.voice_messages_forbidden ? 0.5f : 1.0f; } @@ -5885,7 +6059,7 @@ public void onAnimationEnd(Animator animator) { runningAnimationAudio.playTogether( ObjectAnimator.ofFloat(emojiButton, View.SCALE_Y, 1), ObjectAnimator.ofFloat(emojiButton, View.SCALE_X, 1), - ObjectAnimator.ofFloat(emojiButton, View.ALPHA, 1), + ObjectAnimator.ofFloat(emojiButton, View.ALPHA, emojiButtonRestricted ? 0.5f : 1.0f), ObjectAnimator.ofFloat(recordDot, View.SCALE_Y, 0), ObjectAnimator.ofFloat(recordDot, View.SCALE_X, 0), ObjectAnimator.ofFloat(recordCircle, recordCircleScale, 0.0f), @@ -6096,7 +6270,7 @@ public void onAnimationEnd(Animator animation) { iconsAnimator.playTogether( ObjectAnimator.ofFloat(emojiButton, View.SCALE_Y, 1), ObjectAnimator.ofFloat(emojiButton, View.SCALE_X, 1), - ObjectAnimator.ofFloat(emojiButton, View.ALPHA, 1), + ObjectAnimator.ofFloat(emojiButton, View.ALPHA, emojiButtonRestricted ? 0.5f : 1.0f), ObjectAnimator.ofFloat(recordDot, View.SCALE_Y, 0), ObjectAnimator.ofFloat(recordDot, View.SCALE_X, 0) ); @@ -6240,7 +6414,7 @@ public void onAnimationEnd(Animator animation) { iconsAnimator.playTogether( ObjectAnimator.ofFloat(emojiButton, View.SCALE_Y, 1), ObjectAnimator.ofFloat(emojiButton, View.SCALE_X, 1), - ObjectAnimator.ofFloat(emojiButton, View.ALPHA, 1), + ObjectAnimator.ofFloat(emojiButton, View.ALPHA, emojiButtonRestricted ? 0.5f : 1.0f), ObjectAnimator.ofFloat(recordDot, View.SCALE_Y, 0), ObjectAnimator.ofFloat(recordDot, View.SCALE_X, 0), ObjectAnimator.ofFloat(audioVideoButtonContainer, View.ALPHA, 1.0f) @@ -6750,7 +6924,7 @@ public void setFieldFocused(boolean focus) { if (AndroidUtilities.isTablet()) { if (parentActivity instanceof LaunchActivity) { LaunchActivity launchActivity = (LaunchActivity) parentActivity; - View layout = launchActivity.getLayersActionBarLayout().getView(); + View layout = launchActivity != null && launchActivity.getLayersActionBarLayout() != null ? launchActivity.getLayersActionBarLayout().getView() : null; allowFocus = layout == null || layout.getVisibility() != View.VISIBLE; } else { allowFocus = true; @@ -7239,7 +7413,7 @@ public void run() { } else { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 1); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_BOT_SHARE); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate((fragment1, dids, message, param) -> { long uid = messageObject.messageOwner.from_id.user_id; @@ -7249,7 +7423,7 @@ public void run() { TLRPC.User user = accountInstance.getMessagesController().getUser(uid); if (user == null) { fragment1.finishFragment(); - return; + return true; } long did = dids.get(0).dialogId; MediaDataController.getInstance(currentAccount).saveDraft(did, 0, "@" + UserObject.getPublicUsername(user) + " " + button.query, null, null, true); @@ -7262,7 +7436,7 @@ public void run() { args1.putLong("chat_id", -did); } if (!accountInstance.getMessagesController().checkCanOpenChat(args1, fragment1)) { - return; + return true; } ChatActivity chatActivity = new ChatActivity(args1); if (parentFragment.presentFragment(chatActivity, true)) { @@ -7278,6 +7452,7 @@ public void run() { } else { fragment1.finishFragment(); } + return true; }); parentFragment.presentFragment(fragment); } @@ -7288,6 +7463,44 @@ public void run() { ProfileActivity fragment = new ProfileActivity(args); parentFragment.presentFragment(fragment); } + } else if (button instanceof TLRPC.TL_keyboardButtonRequestPeer) { + TLRPC.TL_keyboardButtonRequestPeer btn = (TLRPC.TL_keyboardButtonRequestPeer) button; + if (btn.peer_type != null && messageObject != null && messageObject.messageOwner != null) { + Bundle args = new Bundle(); + args.putBoolean("onlySelect", true); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER); + if (messageObject != null && messageObject.messageOwner != null && messageObject.messageOwner.from_id instanceof TLRPC.TL_peerUser) { + args.putLong("requestPeerBotId", messageObject.messageOwner.from_id.user_id); + } + try { + SerializedData buffer = new SerializedData(btn.peer_type.getObjectSize()); + btn.peer_type.serializeToStream(buffer); + args.putByteArray("requestPeerType", buffer.toByteArray()); + buffer.cleanup(); + } catch (Exception e) { + FileLog.e(e); + } + DialogsActivity fragment = new DialogsActivity(args); + fragment.setDelegate(new DialogsActivity.DialogsActivityDelegate() { + @Override + public boolean didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param) { + if (dids != null && !dids.isEmpty()) { + TLRPC.TL_messages_sendBotRequestedPeer req = new TLRPC.TL_messages_sendBotRequestedPeer(); + req.peer = MessagesController.getInstance(currentAccount).getInputPeer(messageObject.messageOwner.peer_id); + req.msg_id = messageObject.getId(); + req.button_id = btn.button_id; + req.requested_peer = MessagesController.getInstance(currentAccount).getInputPeer(dids.get(0).dialogId); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, null); + } + fragment.finishFragment(); + return true; + } + }); + parentFragment.presentFragment(fragment); + return false; + } else { + FileLog.e("button.peer_type is null"); + } } return true; } @@ -7989,6 +8202,9 @@ private void setEmojiButtonImage(boolean byOpen, boolean animated) { } ChatActivityEnterViewAnimatedIconView.State nextIcon; if (byOpen && currentPopupContentType == 0) { + if (!sendPlainEnabled) { + return; + } nextIcon = ChatActivityEnterViewAnimatedIconView.State.KEYBOARD; } else { int currentPage; @@ -8009,6 +8225,11 @@ private void setEmojiButtonImage(boolean byOpen, boolean animated) { } } } + if (!sendPlainEnabled && nextIcon == ChatActivityEnterViewAnimatedIconView.State.SMILE) { + nextIcon = ChatActivityEnterViewAnimatedIconView.State.GIF; + } else if (!stickersEnabled && nextIcon != ChatActivityEnterViewAnimatedIconView.State.SMILE) { + nextIcon = ChatActivityEnterViewAnimatedIconView.State.SMILE; + } emojiButton.setState(nextIcon, animated); onEmojiIconChanged(nextIcon); @@ -8802,7 +9023,7 @@ public void draw(Canvas canvas) { return; } paint.setAlpha(Math.round(102 * stickersExpansionProgress)); - canvas.drawRect(0, 0, getWidth(), emojiView.getY() - getHeight() + Theme.chat_composeShadowDrawable.getIntrinsicHeight(), paint); + canvas.drawRect(0, 0, getWidth(), emojiView.getY() - getHeight() + Theme.chat_composeShadowDrawable.getIntrinsicHeight() + messageEditText.getOffsetY(), paint); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java index 47e1f0a8364..5d9625b8ca7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java @@ -16,6 +16,7 @@ import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.content.Context; +import android.content.ContextWrapper; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; @@ -98,6 +99,7 @@ import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.BasePermissionsActivity; import org.telegram.ui.ChatActivity; +import org.telegram.ui.LaunchActivity; import org.telegram.ui.PassportActivity; import org.telegram.ui.PaymentFormActivity; import org.telegram.ui.PhotoPickerActivity; @@ -115,6 +117,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N public ChatActivity.ThemeDelegate parentThemeDelegate; private final NumberTextView captionLimitView; + public boolean forUser; private int currentLimit; private int codepointCount; @@ -122,6 +125,10 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private boolean isSoundPicker = false; private ImageUpdater.AvatarFor setAvatarFor; + private PasscodeView passcodeView; + private ChatAttachRestrictedLayout restrictedLayout; + public ImageUpdater parentImageUpdater; + public void setCanOpenPreview(boolean canOpenPreview) { this.canOpenPreview = canOpenPreview; selectedArrowImageView.setVisibility(canOpenPreview && avatarPicker != 2 ? View.VISIBLE : View.GONE); @@ -343,6 +350,10 @@ public ImageUpdater.AvatarFor getAvatarFor() { return setAvatarFor; } + public void setImageUpdater(ImageUpdater imageUpdater) { + parentImageUpdater = imageUpdater; + } + public interface ChatAttachViewDelegate { void didPressedButton(int button, boolean arg, boolean notify, int scheduleDate, boolean forceDocument); @@ -512,7 +523,7 @@ void onOpenAnimationEnd() { } - void onInit(boolean mediaEnabled) { + void onInit(boolean hasVideo, boolean hasPhoto, boolean hasDocuments) { } @@ -678,8 +689,12 @@ public void onPanTransitionEnd() { protected int currentAccount = UserConfig.selectedAccount; - private boolean mediaEnabled = true; + private boolean documentsEnabled = true; + private boolean photosEnabled = true; + private boolean videosEnabled = true; + private boolean musicEnabled = true; private boolean pollsEnabled = true; + private boolean plainTextEnabled = true; protected int maxSelectedPhotos = -1; protected boolean allowOrder = true; @@ -1093,7 +1108,7 @@ public ChatAttachAlert(Context context, final BaseFragment parentFragment, boole private Bulletin.Delegate bulletinDelegate = new Bulletin.Delegate() { @Override public int getBottomOffset(int tag) { - return getHeight() - frameLayout2.getTop(); + return getHeight() - frameLayout2.getTop() + AndroidUtilities.dp(52); } }; private int lastNotifyWidth; @@ -1663,14 +1678,14 @@ protected void onAttachedToWindow() { adjustPanLayoutHelper.setResizableView(this); adjustPanLayoutHelper.onAttach(); commentTextView.setAdjustPanLayoutHelper(adjustPanLayoutHelper); - Bulletin.addDelegate(this, bulletinDelegate); + // Bulletin.addDelegate(this, bulletinDelegate); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); adjustPanLayoutHelper.onDetach(); - Bulletin.removeDelegate(this); + // Bulletin.removeDelegate(this); } }; sizeNotifierFrameLayout.setDelegate(new SizeNotifierFrameLayout.SizeNotifierFrameLayoutDelegate() { @@ -1955,6 +1970,9 @@ public void setTranslationY(float translationY) { if (view instanceof AttachButton) { int num = (Integer) view.getTag(); if (num == 1) { + if (!photosEnabled && !videosEnabled) { + showLayout(restrictedLayout = new ChatAttachRestrictedLayout(1, this, getContext(), resourcesProvider)); + } showLayout(photoLayout); } else if (num == 3) { if (Build.VERSION.SDK_INT >= 23 && baseFragment.getParentActivity().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { @@ -1969,7 +1987,7 @@ public void setTranslationY(float translationY) { } openDocumentsLayout(true); } else if (num == 5) { - if (Build.VERSION.SDK_INT >= 23) { + if (Build.VERSION.SDK_INT >= 23 && plainTextEnabled) { if (baseFragment.getParentActivity().checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { baseFragment.getParentActivity().requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, BasePermissionsActivity.REQUEST_CODE_ATTACH_CONTACT); return; @@ -1980,17 +1998,27 @@ public void setTranslationY(float translationY) { if (!AndroidUtilities.isMapsInstalled(baseFragment)) { return; } - if (locationLayout == null) { - layouts[5] = locationLayout = new ChatAttachAlertLocationLayout(this, getContext(), resourcesProvider); - locationLayout.setDelegate((location, live, notify, scheduleDate) -> ((ChatActivity) baseFragment).didSelectLocation(location, live, notify, scheduleDate)); + if (!plainTextEnabled) { + restrictedLayout = new ChatAttachRestrictedLayout(6, this, getContext(), resourcesProvider); + showLayout(restrictedLayout); + } else { + if (locationLayout == null) { + layouts[5] = locationLayout = new ChatAttachAlertLocationLayout(this, getContext(), resourcesProvider); + locationLayout.setDelegate((location, live, notify, scheduleDate) -> ((ChatActivity) baseFragment).didSelectLocation(location, live, notify, scheduleDate)); + } + showLayout(locationLayout); } - showLayout(locationLayout); } else if (num == 9) { - if (pollLayout == null) { - layouts[1] = pollLayout = new ChatAttachAlertPollLayout(this, getContext(), resourcesProvider); - pollLayout.setDelegate((poll, params, notify, scheduleDate) -> ((ChatActivity) baseFragment).sendPoll(poll, params, notify, scheduleDate)); + if (!pollsEnabled) { + restrictedLayout = new ChatAttachRestrictedLayout(9, this, getContext(), resourcesProvider); + showLayout(restrictedLayout); + } else { + if (pollLayout == null) { + layouts[1] = pollLayout = new ChatAttachAlertPollLayout(this, getContext(), resourcesProvider); + pollLayout.setDelegate((poll, params, notify, scheduleDate) -> ((ChatActivity) baseFragment).sendPoll(poll, params, notify, scheduleDate)); + } + showLayout(pollLayout); } - showLayout(pollLayout); } else { delegate.didPressedButton((Integer) view.getTag(), true, true, 0, false); } @@ -2499,6 +2527,35 @@ protected void onDraw(Canvas canvas) { checkColors(); navBarColorKey = null; } + + passcodeView = new PasscodeView(context); + containerView.addView(passcodeView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + } + + @Override + protected void onStart() { + super.onStart(); + + Context context = getContext(); + if (context instanceof ContextWrapper && !(context instanceof LaunchActivity)) { + context = ((ContextWrapper) context).getBaseContext(); + } + if (context instanceof LaunchActivity) { + ((LaunchActivity) context).addOverlayPasscodeView(passcodeView); + } + } + + @Override + protected void onStop() { + super.onStop(); + + Context context = getContext(); + if (context instanceof ContextWrapper && !(context instanceof LaunchActivity)) { + context = ((ContextWrapper) context).getBaseContext(); + } + if (context instanceof LaunchActivity) { + ((LaunchActivity) context).removeOverlayPasscodeView(passcodeView); + } } private void showCaptionLimitBulletin(BaseFragment parentFragment) { @@ -2621,7 +2678,9 @@ private void sendPressed(boolean notify, int scheduleDate) { private void showLayout(AttachAlertLayout layout) { long newId = selectedId; - if (layout == photoLayout) { + if (layout == restrictedLayout) { + newId = restrictedLayout.id; + } else if (layout == photoLayout) { newId = 1; } else if (layout == audioLayout) { newId = 3; @@ -2841,6 +2900,10 @@ public void onRequestPermissionsResultFragment(int requestCode, String[] permiss } private void openContactsLayout() { + if (!plainTextEnabled) { + restrictedLayout = new ChatAttachRestrictedLayout(5, this, getContext(), resourcesProvider); + showLayout(restrictedLayout); + } if (contactsLayout == null) { layouts[2] = contactsLayout = new ChatAttachAlertContactsLayout(this, getContext(), resourcesProvider); contactsLayout.setDelegate((user, notify, scheduleDate) -> ((ChatActivity) baseFragment).sendContact(user, notify, scheduleDate)); @@ -2849,6 +2912,12 @@ private void openContactsLayout() { } private void openAudioLayout(boolean show) { + if (!musicEnabled) { + if (show) { + restrictedLayout = new ChatAttachRestrictedLayout(3, this, getContext(), resourcesProvider); + showLayout(restrictedLayout); + } + } if (audioLayout == null) { layouts[3] = audioLayout = new ChatAttachAlertAudioLayout(this, getContext(), resourcesProvider); audioLayout.setDelegate((audios, caption, notify, scheduleDate) -> ((ChatActivity) baseFragment).sendAudio(audios, caption, notify, scheduleDate)); @@ -2864,6 +2933,12 @@ private void openAudioLayout(boolean show) { } private void openDocumentsLayout(boolean show) { + if (!documentsEnabled) { + if (show) { + restrictedLayout = new ChatAttachRestrictedLayout(4, this, getContext(), resourcesProvider); + showLayout(restrictedLayout); + } + } if (documentLayout == null) { int type = isSoundPicker ? ChatAttachAlertDocumentLayout.TYPE_RINGTONE : ChatAttachAlertDocumentLayout.TYPE_DEFAULT; layouts[4] = documentLayout = new ChatAttachAlertDocumentLayout(this, getContext(), type, resourcesProvider); @@ -3438,8 +3513,13 @@ private void updateActionBarVisibility(boolean show, boolean animated) { actionBarAnimation.cancel(); actionBarAnimation = null; } - boolean needsSearchItem = avatarSearch || currentAttachLayout == photoLayout && !menuShowed && baseFragment instanceof ChatActivity && ((ChatActivity) baseFragment).allowSendGifs(); - boolean needMoreItem = avatarPicker != 0 || !menuShowed && currentAttachLayout == photoLayout && mediaEnabled; + + boolean needsSearchItem = avatarSearch || currentAttachLayout == photoLayout && !menuShowed && baseFragment instanceof ChatActivity && ((ChatActivity) baseFragment).allowSendGifs() && ((ChatActivity) baseFragment).allowSendPhotos(); + boolean needMoreItem = avatarPicker != 0 || !menuShowed && currentAttachLayout == photoLayout && (photosEnabled || videosEnabled); + if (currentAttachLayout == restrictedLayout) { + needsSearchItem = false; + needMoreItem = false; + } if (show) { if (needsSearchItem) { searchItem.setVisibility(View.VISIBLE); @@ -3670,15 +3750,20 @@ public void init() { TLRPC.Chat chat = ((ChatActivity) baseFragment).getCurrentChat(); TLRPC.User user = ((ChatActivity) baseFragment).getCurrentUser(); if (chat != null) { - mediaEnabled = ChatObject.canSendMedia(chat); + // mediaEnabled = ChatObject.canSendMedia(chat); + photosEnabled = ChatObject.canSendPhoto(chat); + videosEnabled = ChatObject.canSendVideo(chat); + musicEnabled = ChatObject.canSendMusic(chat); pollsEnabled = ChatObject.canSendPolls(chat); + plainTextEnabled = ChatObject.canSendPlain(chat); + documentsEnabled = ChatObject.canSendDocument(chat); } else { pollsEnabled = user != null && user.bot; } } else { commentTextView.setVisibility(View.INVISIBLE); } - photoLayout.onInit(mediaEnabled); + photoLayout.onInit(videosEnabled, photosEnabled, documentsEnabled); commentTextView.hidePopup(true); enterCommentEventSent = false; setFocusable(false); @@ -3800,6 +3885,9 @@ public void setAvatarPicker(int type, boolean search) { } else { typeButtonsAvailable = true; } + if (photoLayout != null) { + photoLayout.updateAvatarPicker(); + } } public TextView getSelectedTextView() { @@ -3956,9 +4044,8 @@ public void notifyDataSetChanged() { musicButton = buttonsCount++; } } else { - if (mediaEnabled) { - galleryButton = buttonsCount++; - + galleryButton = buttonsCount++; + if (photosEnabled || videosEnabled) { if (baseFragment instanceof ChatActivity && !((ChatActivity) baseFragment).isInScheduleMode() && !((ChatActivity) baseFragment).isSecretChat()) { ChatActivity chatActivity = (ChatActivity) baseFragment; @@ -3973,18 +4060,20 @@ public void notifyDataSetChanged() { buttonsCount += attachMenuBots.size(); attachBotsEndRow = buttonsCount; } + } + documentButton = buttonsCount++; - documentButton = buttonsCount++; + if (plainTextEnabled) { + locationButton = buttonsCount++; } - locationButton = buttonsCount++; + if (pollsEnabled) { pollButton = buttonsCount++; - } else { + } else if (plainTextEnabled) { contactButton = buttonsCount++; } - if (mediaEnabled) { - musicButton = buttonsCount++; - } + musicButton = buttonsCount++; + TLRPC.User user = baseFragment instanceof ChatActivity ? ((ChatActivity) baseFragment).getCurrentUser() : null; if (user != null && user.bot) { contactButton = buttonsCount++; @@ -4044,6 +4133,12 @@ private void removeFromRoot() { @Override public void onBackPressed() { + if (passcodeView.getVisibility() == View.VISIBLE) { + if (getOwnerActivity() != null) { + getOwnerActivity().finish(); + } + return; + } if (actionBar.isSearchFieldVisible()) { actionBar.closeSearchField(); return; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java index 4d1ff0685ac..de472de14fd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java @@ -1800,7 +1800,7 @@ private void searchGlobal(long dialogId, long minDate, long maxDate, FiltersView resultArray = new ArrayList<>(); ArrayList resultArrayNames = new ArrayList<>(); ArrayList encUsers = new ArrayList<>(); - accountInstance.getMessagesStorage().localSearch(0, query, resultArray, resultArrayNames, encUsers, -1); + accountInstance.getMessagesStorage().localSearch(0, query, resultArray, resultArrayNames, encUsers, null, -1); } final TLRPC.TL_messages_searchGlobal req = new TLRPC.TL_messages_searchGlobal(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java index 87b3154fea4..a248e83207c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java @@ -67,6 +67,7 @@ import org.telegram.messenger.MediaController; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SendMessagesHelper; @@ -90,8 +91,10 @@ import org.telegram.ui.ChatActivity; import org.telegram.ui.PhotoViewer; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -100,6 +103,8 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayout implements NotificationCenter.NotificationCenterDelegate { + private static final int VIEW_TYPE_AVATAR_CONSTRUCTOR = 4; + private RecyclerListView cameraPhotoRecyclerView; private LinearLayoutManager cameraPhotoLayoutManager; private PhotoAttachAdapter cameraAttachAdapter; @@ -164,6 +169,9 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou private boolean checkCameraWhenShown; private boolean mediaEnabled; + private boolean videoEnabled; + private boolean photoEnabled; + private boolean documentsEnabled; private float pinchStartDistance; private float cameraZoom; @@ -210,6 +218,11 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou boolean forceDarkTheme; private int animationIndex = -1; + private boolean showAvatarConstructor; + + public void updateAvatarPicker() { + showAvatarConstructor = parentAlert.avatarPicker != 0; + } private class BasePhotoProvider extends PhotoViewer.EmptyPhotoViewerProvider { @Override @@ -227,6 +240,9 @@ public int setPhotoChecked(int index, VideoEditedInfo videoEditedInfo) { if (photoEntry == null) { return -1; } + if (checkSendMediaEnabled(photoEntry)) { + return -1; + } boolean add = true; int num; if ((num = addToSelectedPhotos(photoEntry, -1)) == -1) { @@ -538,6 +554,7 @@ public ChatAttachAlertPhotoLayout(ChatAttachAlert alert, Context context, boolea NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.albumsDidLoad); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.cameraInitied); FrameLayout container = alert.getContainer(); + showAvatarConstructor = parentAlert.avatarPicker != 0; cameraDrawable = context.getResources().getDrawable(R.drawable.instant_camera).mutate(); @@ -699,6 +716,173 @@ public int getSpanSize(int position) { if (selectedAlbumEntry == galleryAlbumEntry) { position--; } + if (showAvatarConstructor) { + if (position == 0) { + if (!(view instanceof AvatarConstructorPreviewCell)) { + return; + } + AvatarConstructorFragment avatarConstructorFragment = new AvatarConstructorFragment(parentAlert.parentImageUpdater, parentAlert.getAvatarFor()); + avatarConstructorFragment.finishOnDone = !(parentAlert.getAvatarFor() != null && parentAlert.getAvatarFor().type == ImageUpdater.TYPE_SUGGEST_PHOTO_FOR_USER); + AvatarConstructorPreviewCell previewCell = (AvatarConstructorPreviewCell) view; + parentAlert.baseFragment.presentFragment(avatarConstructorFragment); + avatarConstructorFragment.startFrom(previewCell); + avatarConstructorFragment.setDelegate((gradient, documentId, document, previewView) -> { + selectedPhotos.clear(); + Bitmap bitmap = Bitmap.createBitmap(800, 800, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + GradientTools gradientTools = new GradientTools(); + gradientTools.setColors(gradient.color1, gradient.color2, gradient.color3, gradient.color4); + gradientTools.setBounds(0, 0, 800, 800); + canvas.drawRect(0, 0, 800, 800, gradientTools.paint); + + File file = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), SharedConfig.getLastLocalId() + "avatar_background.png"); + try { + file.createNewFile(); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos); + byte[] bitmapdata = bos.toByteArray(); + + FileOutputStream fos = new FileOutputStream(file); + fos.write(bitmapdata); + fos.flush(); + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + float scale = AvatarConstructorFragment.STICKER_DEFAULT_SCALE; + int imageX, imageY; + imageX = imageY = (int) (800 * (1f - scale) / 2f); + int imageSize = (int) (800 * scale); + + ImageReceiver imageReceiver = previewView.getImageReceiver(); + if (imageReceiver.getAnimation() != null) { + Bitmap firstFrame = imageReceiver.getAnimation().getFirstFrame(null); + ImageReceiver firstFrameReceiver = new ImageReceiver(); + firstFrameReceiver.setImageBitmap(firstFrame); + firstFrameReceiver.setImageCoords(imageX, imageY, imageSize, imageSize); + firstFrameReceiver.setRoundRadius((int) (imageSize * AvatarConstructorFragment.STICKER_DEFAULT_ROUND_RADIUS)); + firstFrameReceiver.draw(canvas); + firstFrameReceiver.clearImage(); + firstFrame.recycle(); + } else { + if (imageReceiver.getLottieAnimation() != null) { + imageReceiver.getLottieAnimation().setCurrentFrame(0, false, true); + } + imageReceiver.setImageCoords(imageX, imageY, imageSize, imageSize); + imageReceiver.setRoundRadius((int) (imageSize * AvatarConstructorFragment.STICKER_DEFAULT_ROUND_RADIUS)); + imageReceiver.draw(canvas); + } + + File thumb = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), SharedConfig.getLastLocalId() + "avatar_background.png"); + try { + thumb.createNewFile(); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos); + byte[] bitmapdata = bos.toByteArray(); + + FileOutputStream fos = new FileOutputStream(thumb); + fos.write(bitmapdata); + fos.flush(); + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + MediaController.PhotoEntry photoEntry; + if (previewView.hasAnimation()) { + photoEntry = new MediaController.PhotoEntry(0, 0, 0, file.getPath(), 0, false, 0, 0, 0); + photoEntry.thumbPath = thumb.getPath(); + + if (previewView.documentId != 0) { + TLRPC.TL_videoSizeEmojiMarkup emojiMarkup = new TLRPC.TL_videoSizeEmojiMarkup(); + emojiMarkup.emoji_id = previewView.documentId; + emojiMarkup.background_colors.add(previewView.backgroundGradient.color1); + if (previewView.backgroundGradient.color2 != 0) { + emojiMarkup.background_colors.add(previewView.backgroundGradient.color2); + } + if (previewView.backgroundGradient.color3 != 0) { + emojiMarkup.background_colors.add(previewView.backgroundGradient.color3); + } + if (previewView.backgroundGradient.color4 != 0) { + emojiMarkup.background_colors.add(previewView.backgroundGradient.color4); + } + photoEntry.emojiMarkup = emojiMarkup; + } else if (previewView.document != null) { + TLRPC.TL_videoSizeStickerMarkup emojiMarkup = new TLRPC.TL_videoSizeStickerMarkup(); + emojiMarkup.sticker_id = previewView.document.id; + emojiMarkup.stickerset = MessageObject.getInputStickerSet(previewView.document); + emojiMarkup.background_colors.add(previewView.backgroundGradient.color1); + if (previewView.backgroundGradient.color2 != 0) { + emojiMarkup.background_colors.add(previewView.backgroundGradient.color2); + } + if (previewView.backgroundGradient.color3 != 0) { + emojiMarkup.background_colors.add(previewView.backgroundGradient.color3); + } + if (previewView.backgroundGradient.color4 != 0) { + emojiMarkup.background_colors.add(previewView.backgroundGradient.color4); + } + photoEntry.emojiMarkup = emojiMarkup; + } + + photoEntry.editedInfo = new VideoEditedInfo(); + photoEntry.editedInfo.originalPath = file.getPath(); + photoEntry.editedInfo.resultWidth = 800; + photoEntry.editedInfo.resultHeight = 800; + photoEntry.editedInfo.originalWidth = 800; + photoEntry.editedInfo.originalHeight = 800; + photoEntry.editedInfo.isPhoto = true; + photoEntry.editedInfo.bitrate = -1; + photoEntry.editedInfo.muted = true; + + photoEntry.editedInfo.start = photoEntry.editedInfo.startTime = 0; + photoEntry.editedInfo.endTime = previewView.getDuration(); + photoEntry.editedInfo.framerate = 30; + + photoEntry.editedInfo.avatarStartTime = 0; + photoEntry.editedInfo.estimatedSize = (int) (photoEntry.editedInfo.endTime / 1000.0f * 115200); + photoEntry.editedInfo.estimatedDuration = photoEntry.editedInfo.endTime; + + VideoEditedInfo.MediaEntity mediaEntity = new VideoEditedInfo.MediaEntity(); + mediaEntity.type = 0; + + if (document == null) { + document = AnimatedEmojiDrawable.findDocument(UserConfig.selectedAccount, documentId); + } + if (document == null) { + return; + } + mediaEntity.viewWidth = (int) (800 * scale); + mediaEntity.viewHeight = (int) (800 * scale); + mediaEntity.width = scale; + mediaEntity.height = scale; + mediaEntity.x = (1f - scale) / 2f; + mediaEntity.y = (1f - scale) / 2f; + mediaEntity.document = document; + mediaEntity.parentObject = null; + mediaEntity.text = FileLoader.getInstance(UserConfig.selectedAccount).getPathToAttach(document, true).getAbsolutePath(); + mediaEntity.roundRadius = AvatarConstructorFragment.STICKER_DEFAULT_ROUND_RADIUS; + if (MessageObject.isAnimatedStickerDocument(document, true) || MessageObject.isVideoStickerDocument(document)) { + boolean isAnimatedSticker = MessageObject.isAnimatedStickerDocument(document, true); + mediaEntity.subType |= isAnimatedSticker ? 1 : 4; + } + + photoEntry.editedInfo.mediaEntities = new ArrayList<>(); + photoEntry.editedInfo.mediaEntities.add(mediaEntity); + } else { + photoEntry = new MediaController.PhotoEntry(0, 0, 0, thumb.getPath(), 0, false, 0, 0, 0); + } + selectedPhotos.put(-1, photoEntry); + selectedPhotosOrder.add(-1); + parentAlert.delegate.didPressedButton(7, true, false, 0, false); + }); + + parentAlert.dismiss(); + } + position--; + } ArrayList arrayList = getAllPhotosArray(); if (position < 0 || position >= arrayList.size()) { return; @@ -742,7 +926,13 @@ public int getSpanSize(int position) { } boolean hasSpoiler = arrayList.get(position) instanceof MediaController.PhotoEntry && ((MediaController.PhotoEntry) arrayList.get(position)).hasSpoiler; - + Object object = arrayList.get(position); + if (object instanceof MediaController.PhotoEntry) { + MediaController.PhotoEntry photoEntry = (MediaController.PhotoEntry) object; + if (checkSendMediaEnabled(photoEntry)) { + return; + } + } if (hasSpoiler) { setCurrentSpoilerVisible(position, false); } @@ -947,6 +1137,10 @@ public boolean shutterLongPressed() { if (parentAlert.avatarPicker != 2 && !(parentAlert.baseFragment instanceof ChatActivity) || takingPhoto || parentAlert.baseFragment == null || parentAlert.baseFragment.getParentActivity() == null || cameraView == null) { return false; } + if (!videoEnabled) { + BulletinFactory.of(cameraView, resourcesProvider).createErrorBulletin(LocaleController.getString(R.string.GlobalAttachVideoRestricted)).show(); + return false; + } if (Build.VERSION.SDK_INT >= 23) { if (parentAlert.baseFragment.getParentActivity().checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { requestingPermissions = true; @@ -1022,6 +1216,10 @@ public void shutterReleased() { shutterButton.setState(ShutterButton.State.DEFAULT, true); return; } + if (!photoEnabled) { + BulletinFactory.of(cameraView, resourcesProvider).createErrorBulletin(LocaleController.getString(R.string.GlobalAttachPhotoRestricted)).show(); + return; + } final File cameraFile = AndroidUtilities.generatePicturePath(parentAlert.baseFragment instanceof ChatActivity && ((ChatActivity) parentAlert.baseFragment).isSecretChat(), null); final boolean sameTakePictureOrientation = cameraView.getCameraSession().isSameTakePictureOrientation(); cameraView.getCameraSession().setFlipFront(parentAlert.baseFragment instanceof ChatActivity || parentAlert.avatarPicker == 2); @@ -1196,6 +1394,21 @@ public boolean supportsPredictiveItemAnimations() { }); } + private boolean checkSendMediaEnabled(MediaController.PhotoEntry photoEntry) { + if (!videoEnabled && photoEntry.isVideo) { + BulletinFactory.of(parentAlert.sizeNotifierFrameLayout, resourcesProvider).createErrorBulletin( + LocaleController.getString("GlobalAttachVideoRestricted", R.string.GlobalAttachVideoRestricted) + ).show(); + return true; + } else if (!photoEnabled && !photoEntry.isVideo) { + BulletinFactory.of(parentAlert.sizeNotifierFrameLayout, resourcesProvider).createErrorBulletin( + LocaleController.getString("GlobalAttachPhotoRestricted", R.string.GlobalAttachPhotoRestricted) + ).show(); + return true; + } + return false; + } + private int addToSelectedPhotos(MediaController.PhotoEntry object, int index) { Object key = object.imageId; if (selectedPhotos.containsKey(key)) { @@ -1860,6 +2073,13 @@ public void showCamera() { } if (cameraView == null) { cameraView = new CameraView(parentAlert.baseFragment.getParentActivity(), parentAlert.openWithFrontFaceCamera) { + + Bulletin.Delegate bulletinDelegate = new Bulletin.Delegate() { + @Override + public int getBottomOffset(int tag) { + return AndroidUtilities.dp(126) + parentAlert.getBottomInset(); + } + }; @Override protected void dispatchDraw(Canvas canvas) { if (Build.VERSION.SDK_INT >= 21) { @@ -1878,6 +2098,18 @@ protected void dispatchDraw(Canvas canvas) { canvas.restore(); } } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + Bulletin.addDelegate(cameraView, bulletinDelegate); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + Bulletin.removeDelegate(cameraView); + } }; cameraView.setRecordFile(AndroidUtilities.generateVideoPath(parentAlert.baseFragment instanceof ChatActivity && ((ChatActivity) parentAlert.baseFragment).isSecretChat())); cameraView.setFocusable(true); @@ -2735,6 +2967,7 @@ void onSelectedItemsCountChanged(int count) { if (count != 0) { parentAlert.selectedMenuItem.hideSubItem(open_in); } + compressItem.setVisibility(documentsEnabled ? View.VISIBLE : View.GONE); if (count > 1) { parentAlert.selectedMenuItem.showSubItem(preview_gap); parentAlert.selectedMenuItem.showSubItem(preview); @@ -2881,8 +3114,11 @@ void checkColors() { } @Override - void onInit(boolean hasMedia) { - mediaEnabled = hasMedia; + void onInit(boolean hasVideo, boolean hasPhoto, boolean hasDocuments) { + mediaEnabled = hasVideo || hasPhoto; + videoEnabled = hasVideo; + photoEnabled = hasPhoto; + documentsEnabled = hasDocuments; if (cameraView != null) { cameraView.setAlpha(mediaEnabled ? 1.0f : 0.2f); cameraView.setEnabled(mediaEnabled); @@ -3440,10 +3676,16 @@ public RecyclerListView.Holder createHolder() { @Override public void getOutline(View view, Outline outline) { PhotoAttachPhotoCell photoCell = (PhotoAttachPhotoCell) view; + if (photoCell.getTag() == null) { + return; + } int position = (Integer) photoCell.getTag(); if (needCamera && selectedAlbumEntry == galleryAlbumEntry) { position++; } + if (showAvatarConstructor) { + position++; + } if (position == 0) { int rad = AndroidUtilities.dp(8 * parentAlert.cornerRadius); outline.setRoundRect(0, 0, view.getMeasuredWidth() + rad, view.getMeasuredHeight() + rad, rad); @@ -3463,6 +3705,9 @@ public void getOutline(View view, Outline outline) { } int index = (Integer) v.getTag(); MediaController.PhotoEntry photoEntry = v.getPhotoEntry(); + if (checkSendMediaEnabled(photoEntry)) { + return; + } boolean added = !selectedPhotos.containsKey(photoEntry.imageId); if (added && parentAlert.maxSelectedPhotos >= 0 && selectedPhotos.size() >= parentAlert.maxSelectedPhotos) { if (parentAlert.allowOrder && parentAlert.baseFragment instanceof ChatActivity) { @@ -3515,6 +3760,9 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (needCamera && selectedAlbumEntry == galleryAlbumEntry) { position--; } + if (showAvatarConstructor) { + position--; + } PhotoAttachPhotoCell cell = (PhotoAttachPhotoCell) holder.itemView; if (this == adapter) { cell.setItemSize(itemSize); @@ -3526,12 +3774,22 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } MediaController.PhotoEntry photoEntry = getPhotoEntryAtPosition(position); + if (photoEntry == null) { + return; + } cell.setPhotoEntry(photoEntry, needCamera && selectedAlbumEntry == galleryAlbumEntry, position == getItemCount() - 1); if (parentAlert.baseFragment instanceof ChatActivity && parentAlert.allowOrder) { cell.setChecked(selectedPhotosOrder.indexOf(photoEntry.imageId), selectedPhotos.containsKey(photoEntry.imageId), false); } else { cell.setChecked(-1, selectedPhotos.containsKey(photoEntry.imageId), false); } + if (!videoEnabled && photoEntry.isVideo) { + cell.setAlpha(0.3f); + } else if (!photoEnabled && !photoEntry.isVideo) { + cell.setAlpha(0.3f); + } else { + cell.setAlpha(1f); + } cell.getImageView().setTag(position); cell.setTag(position); break; @@ -3598,6 +3856,15 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { default: holder = new RecyclerListView.Holder(new PhotoAttachPermissionCell(mContext, resourcesProvider)); break; + case 4: + AvatarConstructorPreviewCell avatarConstructorPreviewCell = new AvatarConstructorPreviewCell(mContext, parentAlert.forUser) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(itemSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(itemSize, MeasureSpec.EXACTLY)); + } + }; + holder = new RecyclerListView.Holder(avatarConstructorPreviewCell); + break; } return holder; } @@ -3619,6 +3886,9 @@ public int getItemCount() { if (needCamera && selectedAlbumEntry == galleryAlbumEntry) { count++; } + if (showAvatarConstructor) { + count++; + } if (noGalleryPermissions && this == adapter) { count++; } @@ -3637,6 +3907,7 @@ public int getItemViewType(int position) { if (!mediaEnabled) { return 2; } + int localPosition = position; if (needCamera && position == 0 && selectedAlbumEntry == galleryAlbumEntry) { if (noCameraPermissions) { return 3; @@ -3644,6 +3915,12 @@ public int getItemViewType(int position) { return 1; } } + if (needCamera) { + localPosition--; + } + if (showAvatarConstructor && localPosition == 0) { + return VIEW_TYPE_AVATAR_CONSTRUCTOR; + } if (this == adapter && position == itemsCount - 1) { return 2; } else if (noGalleryPermissions) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachRestrictedLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachRestrictedLayout.java new file mode 100644 index 00000000000..133099d3672 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachRestrictedLayout.java @@ -0,0 +1,154 @@ +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.LinearSmoothScroller; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; + +public class ChatAttachRestrictedLayout extends ChatAttachAlert.AttachAlertLayout { + + private final EmptyTextProgressView progressView; + private final RecyclerListView listView; + public final int id; + private final RecyclerView.Adapter adapter; + private int gridExtraSpace; + + public ChatAttachRestrictedLayout(int id, ChatAttachAlert alert, Context context, Theme.ResourcesProvider resourcesProvider) { + super(alert, context, resourcesProvider); + this.id = id; + progressView = new EmptyTextProgressView(context, null, resourcesProvider); + progressView.setText(LocaleController.getString("NoPhotos", R.string.NoPhotos)); + progressView.setOnTouchListener(null); + progressView.setTextSize(16); + addView(progressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + progressView.setLottie(R.raw.media_forbidden, 150, 150); + TLRPC.Chat chat = ((ChatActivity) parentAlert.baseFragment).getCurrentChat(); + if (id == 1) { + progressView.setText(ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_MEDIA)); + } else if (id == 3) { + progressView.setText(ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_MUSIC)); + } else if (id == 4) { + progressView.setText(ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_DOCUMENTS)); + } else { + progressView.setText(ChatObject.getRestrictedErrorText(chat, ChatObject.ACTION_SEND_PLAIN)); + } + progressView.showTextView(); + + listView = new RecyclerListView(context, resourcesProvider); + listView.setSectionsType(RecyclerListView.SECTIONS_TYPE_DATE); + listView.setVerticalScrollBarEnabled(false); + listView.setLayoutManager(new LinearLayoutManager(context)); + listView.setClipToPadding(false); + listView.setAdapter(adapter = new RecyclerView.Adapter() { + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = new View(getContext()) { + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(gridExtraSpace, MeasureSpec.EXACTLY)); + } + }; + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + + } + + @Override + public int getItemCount() { + return 1; + } + }); + listView.setPadding(0, 0, 0, AndroidUtilities.dp(48)); + listView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + parentAlert.updateLayout(ChatAttachRestrictedLayout.this, true, dy); + } + }); + addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + } + + + @Override + int getCurrentItemTop() { + if (listView.getChildCount() <= 0) { + return Integer.MAX_VALUE; + } + View child = listView.getChildAt(0); + RecyclerListView.Holder holder = (RecyclerListView.Holder) listView.findContainingViewHolder(child); + int top = child.getTop() - AndroidUtilities.dp(8); + int newOffset = top > 0 && holder != null && holder.getAdapterPosition() == 0 ? top : 0; + if (top >= 0 && holder != null && holder.getAdapterPosition() == 0) { + newOffset = top; + // runShadowAnimation(false); + } else { +// runShadowAnimation(true); + } + progressView.setTranslationY(newOffset + (getMeasuredHeight() - newOffset - AndroidUtilities.dp(50) - progressView.getMeasuredHeight()) / 2); +// frameLayout.setTranslationY(newOffset); + return newOffset + AndroidUtilities.dp(12); + } + + @Override + public void setTranslationY(float translationY) { + super.setTranslationY(translationY); + parentAlert.getSheetContainer().invalidate(); + } + + @Override + int getFirstOffset() { + return getListTopPadding() + AndroidUtilities.dp(4); + } + + @Override + int getListTopPadding() { + return listView.getPaddingTop(); + } + + @Override + void onPreMeasure(int availableWidth, int availableHeight) { + super.onPreMeasure(availableWidth, availableHeight); + int newSize = Math.max(0, availableHeight - ActionBar.getCurrentActionBarHeight()); + if (gridExtraSpace != newSize) { + gridExtraSpace = newSize; + adapter.notifyDataSetChanged(); + } + int paddingTop; + if (!AndroidUtilities.isTablet() && AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + paddingTop = (int) (availableHeight / 3.5f); + } else { + paddingTop = (availableHeight / 5 * 2); + } + paddingTop -= AndroidUtilities.dp(52); + if (paddingTop < 0) { + paddingTop = 0; + } + if (listView.getPaddingTop() != paddingTop) { + listView.setPadding(AndroidUtilities.dp(6), paddingTop, AndroidUtilities.dp(6), AndroidUtilities.dp(48)); + } + } + + +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java index d545913d444..6b0209555be 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java @@ -935,7 +935,7 @@ public void checkAndUpdateAvatar() { } else { avatarDrawable.setScaleSize(1f); if (avatarImageView != null) { - avatarImageView.imageReceiver.setForUserOrChat(user, avatarDrawable, null, true); + avatarImageView.imageReceiver.setForUserOrChat(user, avatarDrawable, null, true, VectorAvatarThumbDrawable.TYPE_STATIC); } } } else if (chat != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBox2.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBox2.java index 6626ca270d1..29342743df0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBox2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBox2.java @@ -3,16 +3,23 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.CheckBox; +import androidx.core.content.ContextCompat; + +import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.GenericProvider; import org.telegram.ui.ActionBar.Theme; public class CheckBox2 extends View { private CheckBoxBase checkBoxBase; + Drawable iconDrawable; + int currentIcon; public CheckBox2(Context context, int sz) { this(context, sz, null); @@ -93,7 +100,19 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto @Override protected void onDraw(Canvas canvas) { - checkBoxBase.draw(canvas); + if (iconDrawable != null) { + int cx = getMeasuredWidth() >> 1; + int cy = getMeasuredHeight() >> 1; + iconDrawable.setBounds(cx - iconDrawable.getIntrinsicWidth() / 2, cy - iconDrawable.getIntrinsicHeight() / 2, cx + iconDrawable.getIntrinsicWidth() / 2, cy + iconDrawable.getIntrinsicHeight() / 2); + iconDrawable.draw(canvas); + Paint paint = new Paint(); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeWidth(AndroidUtilities.dp(1.2f)); + paint.setColor(Theme.getColor(Theme.key_switch2Track)); + canvas.drawCircle(cx, cy, cx - AndroidUtilities.dp(1.5f), paint); + } else { + checkBoxBase.draw(canvas); + } } @Override @@ -103,4 +122,20 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { info.setChecked(isChecked()); info.setCheckable(true); } + + public void setIcon(int icon) { + if (icon != currentIcon) { + currentIcon = icon; + if (icon == 0) { + iconDrawable = null; + } else { + iconDrawable = ContextCompat.getDrawable(getContext(), icon).mutate(); + iconDrawable.setColorFilter(Theme.getColor(Theme.key_switch2Track), PorterDuff.Mode.MULTIPLY); + } + } + } + + public boolean hasIcon() { + return iconDrawable != null; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBoxBase.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBoxBase.java index 296f5e061ea..703eb7d1b1c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBoxBase.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBoxBase.java @@ -354,7 +354,7 @@ public void draw(Canvas canvas) { if (backgroundType == 9) { paint.setColor(getThemedColor(background2ColorKey)); - } else if (backgroundType == 11 || backgroundType == 6 || backgroundType == 7 || backgroundType == 10 || !drawUnchecked && backgroundColorKey != null) { + } else if (backgroundType == 11 || backgroundType == 6 || backgroundType == 7 || backgroundType == 10 || !drawUnchecked && backgroundColorKey != null || backgroundType == 14) { paint.setColor(getThemedColor(backgroundColorKey)); } else { paint.setColor(getThemedColor(enabled ? Theme.key_checkbox : Theme.key_checkboxDisabled)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CircularProgressDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CircularProgressDrawable.java index dcf35cb2ead..5d189da0150 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CircularProgressDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CircularProgressDrawable.java @@ -41,7 +41,7 @@ private void updateSegment() { } public static void getSegments(float t, float[] segments) { - segments[0] = 1520 * t / 5400f - 20; + segments[0] = Math.max(0, 1520 * t / 5400f - 20); segments[1] = 1520 * t / 5400f; for (int i = 0; i < 4; ++i) { segments[1] += interpolator.getInterpolation((t - i * 1350) / 667f) * 250; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ColorPicker.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ColorPicker.java index 92e92d53e97..e8b8c5a95b1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ColorPicker.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ColorPicker.java @@ -95,6 +95,7 @@ public class ColorPicker extends FrameLayout { private boolean colorPressed; private int selectedColor; + private int prevSelectedColor; private float pressedMoveProgress = 1.0f; private long lastUpdateTime; @@ -252,6 +253,7 @@ protected void onDraw(Canvas canvas) { boolean checked = radioButton[b] == radioButton1; radioButton[b].setChecked(checked, true); if (checked) { + prevSelectedColor = selectedColor; selectedColor = b; } } @@ -529,7 +531,11 @@ public void setAlpha(float alpha) { } radioButton[3] = button; } - radioButton[0].callOnClick(); + if (prevSelectedColor >= 0 && prevSelectedColor < selectedColor) { + radioButton[prevSelectedColor].callOnClick(); + } else { + radioButton[colorsCount - 1].callOnClick(); + } for (int a = 0; a < radioButton.length; a++) { if (a < colorsCount) { delegate.setColor(radioButton[a].getColor(), a, a == radioButton.length - 1); @@ -907,6 +913,7 @@ public void onAnimationEnd(Animator animation) { public void setType(int resetType, boolean hasChanges, int maxColorsCount, int newColorsCount, boolean myMessages, int angle, boolean animated) { if (resetType != currentResetType) { + prevSelectedColor = 0; selectedColor = 0; for (int i = 0; i < 4; i++) { radioButton[i].setChecked(i == selectedColor, true); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/DrawingInBackgroundThreadDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/DrawingInBackgroundThreadDrawable.java index b6b686484b9..53d6fe0adaf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/DrawingInBackgroundThreadDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/DrawingInBackgroundThreadDrawable.java @@ -141,7 +141,7 @@ public void draw(Canvas canvas, long time, int w, int h, float alpha) { } bitmapCanvas.save(); bitmapCanvas.translate(0, padding); - drawInUiThread(bitmapCanvas, 1f); + drawInUiThread(bitmapCanvas, alpha); bitmapCanvas.restore(); } @@ -154,7 +154,7 @@ public void draw(Canvas canvas, long time, int w, int h, float alpha) { if (bitmap != null ) { Bitmap drawingBitmap = bitmap; - paint.setAlpha((int) (255 * alpha)); + paint.setAlpha((int) (0xFF * alpha)); canvas.save(); canvas.translate(0, -padding); this.drawBitmap(canvas, drawingBitmap, paint); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiPacksAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiPacksAlert.java index d572c2db5fa..2eaeaf81003 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiPacksAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiPacksAlert.java @@ -56,6 +56,7 @@ import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; @@ -69,6 +70,7 @@ import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.Premium.PremiumButtonView; import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; +import org.telegram.ui.ContentPreviewViewer; import org.telegram.ui.LaunchActivity; import org.telegram.ui.PremiumPreviewFragment; import org.telegram.ui.ProfileActivity; @@ -87,12 +89,14 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N private EmojiPacksLoader customEmojiPacks; private RecyclerListView listView; + private Adapter adapter; private View shadowView; private FrameLayout buttonsView; private TextView addButtonView; private TextView removeButtonView; private PremiumButtonView premiumButtonView; private GridLayoutManager gridLayoutManager; + private RecyclerAnimationScrollHelper scrollHelper; private CircularProgressDrawable progressDrawable; private ActionBarPopupWindow popupWindow; @@ -102,6 +106,113 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N private float lastY; private Float fromY; + int highlightStartPosition = -1, highlightEndPosition = -1; + private AnimatedFloat highlightAlpha; + + private ContentPreviewViewer.ContentPreviewViewerDelegate previewDelegate = new ContentPreviewViewer.ContentPreviewViewerDelegate() { + @Override + public boolean can() { + return true; + } + + @Override + public boolean needSend(int contentType) { + return fragment instanceof ChatActivity && ((ChatActivity) fragment).canSendMessage() && (UserConfig.getInstance(UserConfig.selectedAccount).isPremium() || ((ChatActivity) fragment).getCurrentUser() != null && UserObject.isUserSelf(((ChatActivity) fragment).getCurrentUser())); + } + + @Override + public void sendEmoji(TLRPC.Document emoji) { + if (fragment instanceof ChatActivity) { + ((ChatActivity) fragment).sendAnimatedEmoji(emoji, true, 0); + } + onCloseByLink(); + dismiss(); + } + + @Override + public boolean needCopy() { + return UserConfig.getInstance(UserConfig.selectedAccount).isPremium(); + } + + @Override + public void copyEmoji(TLRPC.Document document) { + Spannable spannable = SpannableStringBuilder.valueOf(MessageObject.findAnimatedEmojiEmoticon(document)); + spannable.setSpan(new AnimatedEmojiSpan(document, null), 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + if (AndroidUtilities.addToClipboard(spannable)) { + BulletinFactory.of((FrameLayout) containerView, resourcesProvider).createCopyBulletin(LocaleController.getString("EmojiCopied", R.string.EmojiCopied)).show(); + } + } + + @Override + public Boolean canSetAsStatus(TLRPC.Document document) { + if (!UserConfig.getInstance(UserConfig.selectedAccount).isPremium()) { + return null; + } + TLRPC.User user = UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser(); + if (user == null) { + return null; + } + Long emojiStatusId = UserObject.getEmojiStatusDocumentId(user); + return document != null && (emojiStatusId == null || emojiStatusId != document.id); + } + + @Override + public void setAsEmojiStatus(TLRPC.Document document, Integer until) { + TLRPC.EmojiStatus status; + if (document == null) { + status = new TLRPC.TL_emojiStatusEmpty(); + } else if (until != null) { + status = new TLRPC.TL_emojiStatusUntil(); + ((TLRPC.TL_emojiStatusUntil) status).document_id = document.id; + ((TLRPC.TL_emojiStatusUntil) status).until = until; + } else { + status = new TLRPC.TL_emojiStatus(); + ((TLRPC.TL_emojiStatus) status).document_id = document.id; + } + TLRPC.User user = UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser(); + final TLRPC.EmojiStatus previousEmojiStatus = user == null ? new TLRPC.TL_emojiStatusEmpty() : user.emoji_status; + MessagesController.getInstance(currentAccount).updateEmojiStatus(status); + + Runnable undoAction = () -> MessagesController.getInstance(currentAccount).updateEmojiStatus(previousEmojiStatus); + if (document == null) { + final Bulletin.SimpleLayout layout = new Bulletin.SimpleLayout(getContext(), resourcesProvider); + layout.textView.setText(LocaleController.getString("RemoveStatusInfo", R.string.RemoveStatusInfo)); + layout.imageView.setImageResource(R.drawable.msg_settings_premium); + Bulletin.UndoButton undoButton = new Bulletin.UndoButton(getContext(), true, resourcesProvider); + undoButton.setUndoAction(undoAction); + layout.setButton(undoButton); + Bulletin.make((FrameLayout) containerView, layout, Bulletin.DURATION_SHORT).show(); + } else { + BulletinFactory.of((FrameLayout) containerView, resourcesProvider).createEmojiBulletin(document, LocaleController.getString("SetAsEmojiStatusInfo", R.string.SetAsEmojiStatusInfo), LocaleController.getString("Undo", R.string.Undo), undoAction).show(); + } + } + + @Override + public boolean canSchedule() { + return false; +// return delegate != null && delegate.canSchedule(); + } + + @Override + public boolean isInScheduleMode() { + if (fragment instanceof ChatActivity) { + return ((ChatActivity) fragment).isInScheduleMode(); + } + return false; + } + + @Override + public void openSet(TLRPC.InputStickerSet set, boolean clearsInputField) { + + } + + @Override + public long getDialogId() { + + return 0; + } + }; + @Override protected boolean canDismissWithSwipe() { return false; @@ -116,7 +227,7 @@ public EmojiPacksAlert(BaseFragment fragment, Context context, Theme.ResourcesPr } private EmojiPacksAlert(BaseFragment fragment, Context context, Theme.ResourcesProvider resourceProvider, ArrayList stickerSets, TLObject parentObject) { - super(context, false, resourceProvider); + super(context, false, resourceProvider = fragment != null && fragment.getResourceProvider() != null ? fragment.getResourceProvider() : resourceProvider); this.fragment = fragment; fixNavigationBar(); @@ -151,7 +262,7 @@ protected void dispatchDraw(Canvas canvas) { return; } paint.setColor(getThemedColor(Theme.key_dialogBackground)); - paint.setShadowLayer(dp(2), 0, dp(-0.66f), 0x1e000000); + Theme.applyDefaultShadow(paint); path.reset(); float y = lastY = getListTop(); float pad = 0; @@ -437,6 +548,12 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { }; listView = new RecyclerListView(context) { + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + boolean result = ContentPreviewViewer.getInstance().onInterceptTouchEvent(event, listView, 0, previewDelegate, resourcesProvider); + return super.onInterceptTouchEvent(event) || result; + } + @Override protected void onMeasure(int widthSpec, int heightSpec) { int width = MeasureSpec.getSize(widthSpec); @@ -460,15 +577,47 @@ protected void onDetachedFromWindow() { public boolean drawChild(Canvas canvas, View child, long drawingTime) { return false; } + + private Paint highlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + @Override + protected void dispatchDraw(Canvas canvas) { + if (highlightAlpha != null && highlightStartPosition >= 0 && highlightEndPosition >= 0 && adapter != null && isAttachedToWindow()) { + float alpha = highlightAlpha.set(0); + + if (alpha > 0) { + int top = Integer.MAX_VALUE, bottom = Integer.MIN_VALUE; + for (int i = 0; i < getChildCount(); ++i) { + View child = getChildAt(i); + int position = getChildAdapterPosition(child); + + if (position != NO_POSITION && position >= highlightStartPosition && position <= highlightEndPosition) { + top = Math.min(top, child.getTop() + (int) child.getTranslationY()); + bottom = Math.max(bottom, child.getBottom() + (int) child.getTranslationY()); + } + } + + if (top < bottom) { + highlightPaint.setColor(Theme.multAlpha(getThemedColor(Theme.key_chat_linkSelectBackground), alpha)); + canvas.drawRect(0, top, getMeasuredWidth(), bottom, highlightPaint); + } + + invalidate(); + } + } + + super.dispatchDraw(canvas); + } }; + highlightAlpha = new AnimatedFloat(0, listView, 0, 1250, CubicBezierInterpolator.EASE_IN); containerView.setPadding(backgroundPaddingLeft, AndroidUtilities.statusBarHeight, backgroundPaddingLeft, 0); containerView.setClipChildren(false); containerView.setClipToPadding(false); containerView.setWillNotDraw(false); + listView.setWillNotDraw(false); listView.setSelectorRadius(AndroidUtilities.dp(6)); listView.setSelectorDrawableColor(Theme.getColor(Theme.key_listSelector, resourceProvider)); listView.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), AndroidUtilities.dp(68)); - listView.setAdapter(new Adapter()); listView.setLayoutManager(gridLayoutManager = new GridLayoutManager(context, 8)); listView.addItemDecoration(new RecyclerView.ItemDecoration() { @Override @@ -481,7 +630,9 @@ public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull R } } }); - listView.setOnItemClickListener((view, position) -> { + final Theme.ResourcesProvider finalResourceProvider = resourceProvider; + RecyclerListView.OnItemClickListener stickersOnItemClickListener; + listView.setOnItemClickListener(stickersOnItemClickListener = (view, position) -> { if (stickerSets == null || stickerSets.size() <= 1) { if (popupWindow != null) { popupWindow.dismiss(); @@ -494,7 +645,6 @@ public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull R SpannableString text = new SpannableString(MessageObject.findAnimatedEmojiEmoticon(span.document == null ? AnimatedEmojiDrawable.findDocument(currentAccount, span.getDocumentId()) : span.document)); text.setSpan(span, 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); ((Editable) ((ChatActivity) fragment).getChatActivityEnterView().messageEditText.getText()).append(text); - ((ChatActivity) fragment).showEmojiHint(); onCloseByLink(); dismiss(); } catch (Exception ignore) {} @@ -526,7 +676,7 @@ public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull R inputStickerSet.id = stickerSet.set.id; inputStickerSet.access_hash = stickerSet.set.access_hash; inputStickerSets.add(inputStickerSet); - new EmojiPacksAlert(fragment, getContext(), resourceProvider, inputStickerSets) { + new EmojiPacksAlert(fragment, getContext(), finalResourceProvider, inputStickerSets) { @Override protected void onCloseByLink() { EmojiPacksAlert.this.dismiss(); @@ -586,6 +736,7 @@ protected void onCloseByLink() { } return false; }); + listView.setOnTouchListener((v, event) -> ContentPreviewViewer.getInstance().onTouch(event, listView, 0, stickersOnItemClickListener, previewDelegate, resourcesProvider)); gridLayoutManager.setReverseLayout(false); gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override @@ -593,6 +744,7 @@ public int getSpanSize(int position) { return listView.getAdapter() != null && listView.getAdapter().getItemViewType(position) != 1 ? gridLayoutManager.getSpanCount() : 1; } }); + scrollHelper = new RecyclerAnimationScrollHelper(listView, gridLayoutManager); containerView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); @@ -629,16 +781,26 @@ public int getSpanSize(int position) { premiumButtonView.setIcon(R.raw.unlock_icon); premiumButtonView.buttonLayout.setClickable(true); buttonsView.addView(premiumButtonView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM, 12, 10, 12, 10)); + } - updateButton(); - int currentAccount = fragment == null ? UserConfig.selectedAccount : fragment.getCurrentAccount(); - MediaDataController.getInstance(currentAccount).checkStickers(MediaDataController.TYPE_EMOJIPACKS); + @Override + public void onBackPressed() { + if (ContentPreviewViewer.getInstance().isVisible()) { + ContentPreviewViewer.getInstance().closeWithMenu(); + return; + } + super.onBackPressed(); } protected void onButtonClicked(boolean install) { } + private int highlightIndex = -1; + public void highlight(int setIndex) { + highlightIndex = setIndex; + } + private boolean shown = false; private void updateShowButton(boolean show) { boolean animated = !shown && show; @@ -847,6 +1009,20 @@ private void updateButton() { loaded = loadedNow; if (!loaded) { listView.setAlpha(0); + } else if (highlightIndex >= 0) { + int currentPosition = gridLayoutManager.findFirstVisibleItemPosition(); + int position = adapter.getSetHeaderPosition(highlightIndex); + if (Math.abs(currentPosition - position) > (1 + 16 + 1) * 3) { + scrollHelper.setScrollDirection(currentPosition < position ? RecyclerAnimationScrollHelper.SCROLL_DIRECTION_DOWN : RecyclerAnimationScrollHelper.SCROLL_DIRECTION_UP); + scrollHelper.scrollToPosition(position, AndroidUtilities.displaySize.y / 2 - AndroidUtilities.dp(170), false, true); + } else { + listView.smoothScrollToPosition(position); + } + highlightStartPosition = adapter.getSetHeaderPosition(highlightIndex); + highlightEndPosition = adapter.getSetEndPosition(highlightIndex); + highlightAlpha.set(1, true); + listView.invalidate(); + highlightIndex = -1; } if (!loaded) { @@ -867,7 +1043,7 @@ private void updateButton() { if (canInstallPacks.size() == 1) { addButtonView.setText(LocaleController.formatPluralString("AddManyEmojiCount", canInstallPacks.get(0).documents.size())); } else { - addButtonView.setText(LocaleController.formatPluralString("AddManyEmojiCount", canInstallPacks.size())); + addButtonView.setText(LocaleController.formatPluralString("AddManyEmojiPacksCount", canInstallPacks.size())); } addButtonView.setOnClickListener(ev -> { final int count = canInstallPacks.size(); @@ -940,7 +1116,14 @@ private int getListTop() { @Override public void show() { super.show(); + listView.setAdapter(adapter = new Adapter()); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 4); + + customEmojiPacks.start(); + updateButton(); + int currentAccount = fragment == null ? UserConfig.selectedAccount : fragment.getCurrentAccount(); + MediaDataController.getInstance(currentAccount).checkStickers(MediaDataController.TYPE_EMOJIPACKS); } @Override @@ -969,6 +1152,12 @@ public SeparatorView(Context context) { private class Adapter extends RecyclerListView.SelectionAdapter { + private final int VIEW_TYPE_PADDING = 0; + private final int VIEW_TYPE_EMOJI = 1; + private final int VIEW_TYPE_HEADER = 2; + private final int VIEW_TYPE_TEXT = 3; + private final int VIEW_TYPE_SEPARATOR = 4; + @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { return holder.getItemViewType() == 1; @@ -978,15 +1167,15 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = null; - if (viewType == 0) { + if (viewType == VIEW_TYPE_PADDING) { view = paddingView; - } else if (viewType == 1) { + } else if (viewType == VIEW_TYPE_EMOJI) { view = new EmojiImageView(getContext()); - } else if (viewType == 2) { + } else if (viewType == VIEW_TYPE_HEADER) { view = new EmojiPackHeader(getContext(), customEmojiPacks.data.length <= 1); - } else if (viewType == 3) { + } else if (viewType == VIEW_TYPE_TEXT) { view = new TextView(getContext()); - } else if (viewType == 4) { + } else if (viewType == VIEW_TYPE_SEPARATOR) { view = new SeparatorView(getContext()); } return new RecyclerListView.Holder(view); @@ -996,14 +1185,14 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { position--; switch (holder.getItemViewType()) { - case 3: + case VIEW_TYPE_TEXT: TextView textView = (TextView) holder.itemView; textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); textView.setTextColor(getThemedColor(Theme.key_chat_emojiPanelTrendingDescription)); textView.setText(AndroidUtilities.replaceTags(LocaleController.getString("PremiumPreviewEmojiPack", R.string.PremiumPreviewEmojiPack))); textView.setPadding(AndroidUtilities.dp(14), 0, AndroidUtilities.dp(30), AndroidUtilities.dp(14)); break; - case 1: + case VIEW_TYPE_EMOJI: if (hasDescription) { position--; } @@ -1028,11 +1217,16 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi inputStickerSet.id = customEmoji.stickerSet.set.id; inputStickerSet.short_name = customEmoji.stickerSet.set.short_name; inputStickerSet.access_hash = customEmoji.stickerSet.set.access_hash; - view.span = new AnimatedEmojiSpan(customEmoji.documentId, null); + TLRPC.Document document = customEmoji.getDocument(); + if (document != null) { + view.span = new AnimatedEmojiSpan(document, null); + } else { + view.span = new AnimatedEmojiSpan(customEmoji.documentId, null); + } } } break; - case 2: + case VIEW_TYPE_HEADER: if (hasDescription && position > 0) { position--; } @@ -1067,19 +1261,19 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi @Override public int getItemViewType(int position) { if (position == 0) { - return 0; + return VIEW_TYPE_PADDING; } position--; if (hasDescription) { if (position == 1) { - return 3; + return VIEW_TYPE_TEXT; } else if (position > 0) { position--; } } for (int i = 0, j = 0; i < customEmojiPacks.data.length; ++i) { if (position == j) { - return 2; + return VIEW_TYPE_HEADER; } int count = customEmojiPacks.data[i].size(); if (customEmojiPacks.data.length > 1) { @@ -1087,11 +1281,47 @@ public int getItemViewType(int position) { } j += 1 + count; if (position == j) { - return 4; + return VIEW_TYPE_SEPARATOR; } j++; } - return 1; + return VIEW_TYPE_EMOJI; + } + + public int getSetHeaderPosition(int setIndex) { + int position = 1; + if (hasDescription) { + position++; + } + for (int i = 0; i < customEmojiPacks.data.length; ++i) { + if (i == setIndex) { + return position; + } + int count = customEmojiPacks.data[i].size(); + if (customEmojiPacks.data.length > 1) { + count = Math.min(gridLayoutManager.getSpanCount() * 2, count); + } + position += 1 + count + 1; + } + return position; + } + + public int getSetEndPosition(int setIndex) { + int position = 1; + if (hasDescription) { + position++; + } + for (int i = 0; i < customEmojiPacks.data.length; ++i) { + int count = customEmojiPacks.data[i].size(); + if (customEmojiPacks.data.length > 1) { + count = Math.min(gridLayoutManager.getSpanCount() * 2, count); + } + if (i == setIndex) { + return position + count + 1; + } + position += 1 + count + 1; + } + return position; } @Override @@ -1156,7 +1386,9 @@ protected void onSend(androidx.collection.LongSparseArray dids, in } } } - private class EmojiImageView extends View { + + public static class EmojiImageView extends View { + public ImageReceiver.BackgroundThreadDrawHolder[] backgroundThreadDrawHolder = new ImageReceiver.BackgroundThreadDrawHolder[DrawingInBackgroundThreadDrawable.THREAD_COUNT]; public ImageReceiver imageReceiver; @@ -1166,6 +1398,18 @@ public EmojiImageView(Context context) { public AnimatedEmojiSpan span; + public TLRPC.Document getDocument() { + TLRPC.Document document = null; + if (span != null) { + document = span.document; + if (document == null) { + long documentId = span.getDocumentId(); + document = AnimatedEmojiDrawable.findDocument(UserConfig.selectedAccount, documentId); + } + } + return document; + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setPadding(AndroidUtilities.dp(2), AndroidUtilities.dp(2), AndroidUtilities.dp(2), AndroidUtilities.dp(2)); @@ -1189,7 +1433,10 @@ public void setPressed(boolean pressed) { backAnimator = ValueAnimator.ofFloat(pressedProgress, 0); backAnimator.addUpdateListener(animation -> { pressedProgress = (float) animation.getAnimatedValue(); - containerView.invalidate(); + if (getParent() instanceof View) { + ((View) getParent()).invalidate(); + } +// containerView.invalidate(); }); backAnimator.addListener(new AnimatorListenerAdapter() { @Override @@ -1501,6 +1748,7 @@ class EmojiPacksLoader implements NotificationCenter.NotificationCenterDelegate public ArrayList stickerSets; public ArrayList[] data; private int currentAccount; + private boolean started = false; public EmojiPacksLoader(int currentAccount, ArrayList inputStickerSets, TLObject parentObject) { this.currentAccount = currentAccount; @@ -1509,10 +1757,17 @@ public EmojiPacksLoader(int currentAccount, ArrayList inp } this.inputStickerSets = inputStickerSets; this.parentObject = parentObject; + } + + public void start() { + if (started) { + return; + } + started = true; init(); } - private void init() { + public void init() { if ((parentObject instanceof TLRPC.Photo || parentObject instanceof TLRPC.Document) && (this.inputStickerSets == null || this.inputStickerSets.isEmpty())) { data = new ArrayList[2]; putStickerSet(0, null); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java index 09594922ceb..dfcd5192e38 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiTabsStrip.java @@ -68,10 +68,15 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { }; private int settingsDrawableId = R.drawable.smiles_tab_settings; + private boolean forceTabsShow = !UserConfig.getInstance(UserConfig.selectedAccount).isPremium(); + private boolean showSelected = true; + private AnimatedFloat showSelectedAlpha; + private Theme.ResourcesProvider resourcesProvider; private boolean includeAnimated; public LinearLayout contentView; + public EmojiTabButton toggleEmojiStickersTab; public EmojiTabButton recentTab; private EmojiTabButton settingsTab; private EmojiTabsView emojiTabs; @@ -82,6 +87,7 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { private float selectT = 0f; private float selectAnimationT = 0f; private int selected = 0; + private int selectedFullIndex = 0; private int wasIndex = 0; public boolean animateAppear = true; @@ -89,7 +95,7 @@ public class EmojiTabsStrip extends ScrollableHorizontalScrollView { private Runnable onSettingsOpenRunnable; private boolean wasDrawn; private int animatedEmojiCacheType = AnimatedEmojiDrawable.CACHE_TYPE_TAB_STRIP; - + private int currentType; public boolean updateButtonDrawables = true; @@ -98,6 +104,7 @@ public EmojiTabsStrip(Context context, Theme.ResourcesProvider resourcesProvider this.includeAnimated = includeAnimated; this.resourcesProvider = resourcesProvider; this.onSettingsOpenRunnable = onSettingsOpen; + this.currentType = type; contentView = new LinearLayout(context) { @@ -200,6 +207,11 @@ protected void dispatchDraw(Canvas canvas) { } } + if (showSelectedAlpha == null) { + showSelectedAlpha = new AnimatedFloat(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + } + float alpha = showSelectedAlpha.set(showSelected ? 1 : 0); + int selectFrom = (int) Math.floor(selectT), selectTo = (int) Math.ceil(selectT); getChildBounds(selectFrom, from); getChildBounds(selectTo, to); @@ -211,11 +223,23 @@ protected void dispatchDraw(Canvas canvas) { rect.set(rect.centerX() - hw, rect.centerY() - hh, rect.centerX() + hw, rect.centerY() + hh); float r = AndroidUtilities.dp(AndroidUtilities.lerp(8f, 16f, isEmojiTabs)); paint.setColor(selectorColor()); + if (forceTabsShow) { + paint.setAlpha((int) (paint.getAlpha() * alpha * (1f - isEmojiTabs * .5f))); + } path.rewind(); path.addRoundRect(rect, r, r, Path.Direction.CW); canvas.drawPath(path, paint); + if (forceTabsShow) { + path.rewind(); + getChildBounds(1, rect); + path.addRoundRect(rect, AndroidUtilities.dpf2(16), AndroidUtilities.dpf2(16), Path.Direction.CW); + paint.setColor(selectorColor()); + paint.setAlpha((int) (paint.getAlpha() * .5f)); + canvas.drawPath(path, paint); + } + if (emojiTabs != null) { path.addCircle(emojiTabs.getLeft() + AndroidUtilities.dp(15), (emojiTabs.getTop() + emojiTabs.getBottom()) / 2f, AndroidUtilities.dp(15), Path.Direction.CW); } @@ -254,6 +278,9 @@ private void getChildBounds(int i, RectF out) { setHorizontalScrollBarEnabled(false); addView(contentView); + if (type == SelectAnimatedEmojiDialog.TYPE_AVATAR_CONSTRUCTOR) { + contentView.addView(toggleEmojiStickersTab = new EmojiTabButton(context, R.drawable.msg_emoji_stickers, false, false)); + } if (type == SelectAnimatedEmojiDialog.TYPE_TOPIC_ICON) { recentDrawableId = R.drawable.msg_emoji_smiles; } @@ -278,6 +305,11 @@ private void getChildBounds(int i, RectF out) { } } + public void showSelected(boolean show) { + this.showSelected = show; + this.contentView.invalidate(); + } + private boolean recentFirstChange = true; private boolean recentIsShown = true; public void showRecent(boolean show) { @@ -297,6 +329,10 @@ public void showRecent(boolean show) { recentFirstChange = false; } + protected boolean doIncludeFeatured() { + return true; + } + private boolean isFreeEmojiPack(TLRPC.StickerSet set, ArrayList documents) { if (set == null || documents == null) { return false; @@ -363,6 +399,7 @@ public void updateEmojiPacks(ArrayList emojiPacks) { appearAnimation = null; } appearCount = emojiPacks.size(); + final boolean includeFeatured = doIncludeFeatured(); final boolean isPremium = UserConfig.getInstance(UserConfig.selectedAccount).isPremium() || allowEmojisForNonPremium(); for (int i = 0; i < emojipackTabs.size(); ++i) { EmojiTabButton emojipackTab = emojipackTabs.get(i); @@ -370,6 +407,9 @@ public void updateEmojiPacks(ArrayList emojiPacks) { if (emojipackTab != null && emojipackTab.id != null) { for (int j = 0; j < emojiPacks.size(); ++j) { EmojiView.EmojiPack p = emojiPacks.get(j); + if (!includeFeatured && p.featured) { + continue; + } final int id = Objects.hash(p.set.id, p.featured); if (id == emojipackTab.id) { pack = p; @@ -406,6 +446,9 @@ public void onAnimationEnd(Animator animation) { } for (int i = 0; i < emojiPacks.size(); ++i) { EmojiView.EmojiPack pack = emojiPacks.get(i); + if (!includeFeatured && pack.featured) { + continue; + } final int id = Objects.hash(pack.set.id, pack.featured); EmojiTabButton emojipackTab = null; for (int j = 0; j < emojipackTabs.size(); ++j) { @@ -438,7 +481,9 @@ public void onAnimationEnd(Animator animation) { drawable.addView(emojipackTab.imageView); } } - if (!isPremium && !free) { + if (currentType == SelectAnimatedEmojiDialog.TYPE_AVATAR_CONSTRUCTOR) { + emojipackTab.setLock(null); + } else if (!isPremium && !free) { emojipackTab.setLock(true); } else if (!this.isInstalled(pack)) { emojipackTab.setLock(false); @@ -558,9 +603,13 @@ public void select(int index) { public void select(int index, boolean animated) { animated = animated && !first; - if (!recentIsShown) { + if (toggleEmojiStickersTab != null) { + index++; + } + if (!recentIsShown || toggleEmojiStickersTab != null) { index = Math.max(1, index); } + selectedFullIndex = index; final int wasSelected = selected; for (int i = 0, j = 0; i < contentView.getChildCount(); ++i, ++j) { View child = contentView.getChildAt(i); @@ -603,7 +652,7 @@ public void select(int index, boolean animated) { } if (emojiTabs != null) { - emojiTabs.show(selected == 1, animated); + emojiTabs.show(selected == 1 || forceTabsShow, animated); } View child = contentView.getChildAt(selected); @@ -1001,6 +1050,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } public int maxWidth() { +// return AndroidUtilities.dp((30 + 2) * (clip() ? Math.min(5.7f, contentView.getChildCount()) : contentView.getChildCount())); return AndroidUtilities.dp((30 + 2) * Math.min(5.7f, contentView.getChildCount())); } @@ -1051,8 +1101,8 @@ public boolean onTouchEvent(MotionEvent ev) { return super.onTouchEvent(ev); } - private boolean shown = false; - private float showT = 0f; + private boolean shown = forceTabsShow; + private float showT = forceTabsShow ? 1f : 0f; private ValueAnimator showAnimator; public void show(boolean show, boolean animated) { if (show == shown) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java index cb5efca0fbf..f25b0179fb0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java @@ -8,6 +8,8 @@ package org.telegram.ui.Components; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; @@ -38,9 +40,12 @@ import android.os.Bundle; import android.os.SystemClock; import android.text.Editable; +import android.text.Spannable; import android.text.SpannableStringBuilder; +import android.text.Spanned; import android.text.TextUtils; import android.text.TextWatcher; +import android.util.Log; import android.util.LongSparseArray; import android.util.SparseArray; import android.util.SparseIntArray; @@ -102,6 +107,7 @@ import org.telegram.messenger.SharedConfig; import org.telegram.messenger.SvgHelper; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.browser.Browser; import org.telegram.tgnet.ConnectionsManager; @@ -132,6 +138,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -144,6 +151,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific private ArrayList allTabs = new ArrayList<>(); private ArrayList currentTabs = new ArrayList<>(); + private boolean ignorePagerScroll; private ViewPager pager; private FrameLayout bottomTabContainer; private FrameLayout bulletinContainer; @@ -290,6 +298,8 @@ public void allowEmojisForNonPremium(boolean allow) { private EmojiViewDelegate delegate; private long currentChatId; + boolean emojiBanned; + boolean stickersBanned; private TLRPC.StickerSetCovered[] primaryInstallingStickerSets = new TLRPC.StickerSetCovered[10]; private LongSparseArray installingStickerSets = new LongSparseArray<>(); @@ -468,13 +478,117 @@ public interface DragListener { } private ContentPreviewViewer.ContentPreviewViewerDelegate contentPreviewViewerDelegate = new ContentPreviewViewer.ContentPreviewViewerDelegate() { + @Override + public boolean can() { + return fragment != null; + } + @Override public void sendSticker(TLRPC.Document sticker, String query, Object parent, boolean notify, int scheduleDate) { delegate.onStickerSelected(null, sticker, query, parent, null, notify, scheduleDate); } @Override - public boolean needSend() { + public void resetTouch() { + if (emojiGridView != null) { + emojiGridView.clearAllTouches(); + } + } + + @Override + public void sendEmoji(TLRPC.Document emoji) { + if (fragment instanceof ChatActivity) { + ((ChatActivity) fragment).sendAnimatedEmoji(emoji, true, 0); + } + } + + @Override + public void setAsEmojiStatus(TLRPC.Document document, Integer until) { + TLRPC.EmojiStatus status; + if (document == null) { + status = new TLRPC.TL_emojiStatusEmpty(); + } else if (until != null) { + status = new TLRPC.TL_emojiStatusUntil(); + ((TLRPC.TL_emojiStatusUntil) status).document_id = document.id; + ((TLRPC.TL_emojiStatusUntil) status).until = until; + } else { + status = new TLRPC.TL_emojiStatus(); + ((TLRPC.TL_emojiStatus) status).document_id = document.id; + } + TLRPC.User user = UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser(); + final TLRPC.EmojiStatus previousEmojiStatus = user == null ? new TLRPC.TL_emojiStatusEmpty() : user.emoji_status; + MessagesController.getInstance(currentAccount).updateEmojiStatus(status); + + Runnable undoAction = () -> MessagesController.getInstance(currentAccount).updateEmojiStatus(previousEmojiStatus); + if (document == null) { + final Bulletin.SimpleLayout layout = new Bulletin.SimpleLayout(getContext(), resourcesProvider); + layout.textView.setText(LocaleController.getString("RemoveStatusInfo", R.string.RemoveStatusInfo)); + layout.imageView.setImageResource(R.drawable.msg_settings_premium); + layout.imageView.setScaleX(.8f); + layout.imageView.setScaleY(.8f); + layout.imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chats_verifiedBackground, resourcesProvider), PorterDuff.Mode.MULTIPLY)); + Bulletin.UndoButton undoButton = new Bulletin.UndoButton(getContext(), true, resourcesProvider); + undoButton.setUndoAction(undoAction); + layout.setButton(undoButton); + if (fragment != null) { + Bulletin.make(fragment, layout, Bulletin.DURATION_SHORT).show(); + } else { + Bulletin.make(bulletinContainer, layout, Bulletin.DURATION_SHORT).show(); + } + } else { + BulletinFactory factory = fragment != null ? BulletinFactory.of(fragment) : BulletinFactory.of(bulletinContainer, resourcesProvider); + factory.createEmojiBulletin(document, LocaleController.getString("SetAsEmojiStatusInfo", R.string.SetAsEmojiStatusInfo), LocaleController.getString("Undo", R.string.Undo), undoAction).show(); + } + } + + @Override + public void copyEmoji(TLRPC.Document document) { + Spannable spannable = SpannableStringBuilder.valueOf(MessageObject.findAnimatedEmojiEmoticon(document)); + spannable.setSpan(new AnimatedEmojiSpan(document, null), 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + if (AndroidUtilities.addToClipboard(spannable)) { + BulletinFactory factory = fragment != null ? BulletinFactory.of(fragment) : BulletinFactory.of(bulletinContainer, resourcesProvider); + factory.createCopyBulletin(LocaleController.getString("EmojiCopied", R.string.EmojiCopied)).show(); + } + } + + @Override + public boolean needCopy() { + return true; + } + + @Override + public boolean needRemoveFromRecent(TLRPC.Document document) { + return document != null && Emoji.recentEmoji.contains("animated_" + document.id); + } + + @Override + public void removeFromRecent(TLRPC.Document document) { + if (document != null) { + Emoji.removeRecentEmoji("animated_" + document.id); + if (emojiAdapter != null) { + emojiAdapter.notifyDataSetChanged(); + } + } + } + + @Override + public Boolean canSetAsStatus(TLRPC.Document document) { + if (!UserConfig.getInstance(UserConfig.selectedAccount).isPremium()) { + return null; + } + TLRPC.User user = UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser(); + if (user == null) { + return null; + } + Long emojiStatusId = UserObject.getEmojiStatusDocumentId(user); + return document != null && (emojiStatusId == null || emojiStatusId != document.id); + } + + @Override + public boolean needSend(int contentType) { + if (contentType == ContentPreviewViewer.CONTENT_TYPE_EMOJI) { + return fragment instanceof ChatActivity && ((ChatActivity) fragment).canSendMessage() && (UserConfig.getInstance(UserConfig.selectedAccount).isPremium() || ((ChatActivity) fragment).getCurrentUser() != null && UserObject.isUserSelf(((ChatActivity) fragment).getCurrentUser())); + } return true; } @@ -557,55 +671,81 @@ public void setEnabled(boolean enabled) { private class SearchField extends FrameLayout { - private View searchBackground; - private ImageView searchIconImageView; - private ImageView clearSearchImageView; - private CloseProgressDrawable2 progressDrawable; + private int type; + private ImageView searchImageView; + private SearchStateDrawable searchStateDrawable; private EditTextBoldCursor searchEditText; private View shadowView; private View backgroundView; + private ImageView clear; + private FrameLayout box; private AnimatorSet shadowAnimator; + private StickerCategoriesListView categoriesListView; + private FrameLayout inputBox; + private View inputBoxGradient; + private StickerCategoriesListView.EmojiCategory recent; + private StickerCategoriesListView.EmojiCategory trending; + + @SuppressLint("ClickableViewAccessibility") public SearchField(Context context, int type) { super(context); + this.type = type; shadowView = new View(context); shadowView.setAlpha(0.0f); shadowView.setTag(1); shadowView.setBackgroundColor(getThemedColor(Theme.key_chat_emojiPanelShadowLine)); - addView(shadowView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, AndroidUtilities.getShadowHeight(), Gravity.BOTTOM | Gravity.LEFT)); + addView(shadowView, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, AndroidUtilities.getShadowHeight(), Gravity.BOTTOM | Gravity.LEFT)); backgroundView = new View(context); backgroundView.setBackgroundColor(getThemedColor(Theme.key_chat_emojiPanelBackground)); - addView(backgroundView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, searchFieldHeight)); + addView(backgroundView, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, searchFieldHeight)); - searchBackground = new View(context); - searchBackground.setBackgroundDrawable(Theme.createRoundRectDrawable(AndroidUtilities.dp(18), getThemedColor(Theme.key_chat_emojiSearchBackground))); - addView(searchBackground, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.LEFT | Gravity.TOP, 14, 14, 14, 0)); - - searchIconImageView = new ImageView(context); - searchIconImageView.setScaleType(ImageView.ScaleType.CENTER); - searchIconImageView.setImageResource(R.drawable.smiles_inputsearch); - searchIconImageView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_emojiSearchIcon), PorterDuff.Mode.MULTIPLY)); - addView(searchIconImageView, LayoutHelper.createFrame(36, 36, Gravity.LEFT | Gravity.TOP, 16, 14, 0, 0)); - - clearSearchImageView = new ImageView(context); - clearSearchImageView.setScaleType(ImageView.ScaleType.CENTER); - clearSearchImageView.setImageDrawable(progressDrawable = new CloseProgressDrawable2() { - @Override - protected int getCurrentColor() { - return getThemedColor(Theme.key_chat_emojiSearchIcon); + box = new FrameLayout(context); + box.setBackground(Theme.createRoundRectDrawable(dp(18), getThemedColor(Theme.key_chat_emojiSearchBackground))); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + box.setClipToOutline(true); + box.setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), (int) dp(18)); + } + }); + } + if (type == 2) { + addView(box, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.FILL, 10, 8, 10, 8)); + } else { + addView(box, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.FILL, 10, 6, 10, 8)); + } + + inputBox = new FrameLayout(context); + box.addView(inputBox, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 40, Gravity.LEFT | Gravity.TOP, 38, 0, 0, 0)); + + searchImageView = new ImageView(context); + searchStateDrawable = new SearchStateDrawable(); + searchStateDrawable.setIconState(SearchStateDrawable.State.STATE_SEARCH, false); + searchStateDrawable.setColor(getThemedColor(Theme.key_chat_emojiSearchIcon)); + searchImageView.setScaleType(ImageView.ScaleType.CENTER); + searchImageView.setImageDrawable(searchStateDrawable); + searchImageView.setOnClickListener(e -> { + if (searchStateDrawable.getIconState() == SearchStateDrawable.State.STATE_BACK) { + searchEditText.setText(""); + search(null, false); + if (categoriesListView != null) { + categoriesListView.scrollToStart(); + categoriesListView.selectCategory(null); + categoriesListView.updateCategoriesShown(true, true); + } + toggleClear(false); + if (searchEditText != null) { + searchEditText.clearAnimation(); + searchEditText.animate().translationX(0).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + } + showInputBoxGradient(false); } }); - progressDrawable.setSide(AndroidUtilities.dp(7)); - clearSearchImageView.setScaleX(0.1f); - clearSearchImageView.setScaleY(0.1f); - clearSearchImageView.setAlpha(0.0f); - addView(clearSearchImageView, LayoutHelper.createFrame(36, 36, Gravity.RIGHT | Gravity.TOP, 14, 14, 14, 0)); - clearSearchImageView.setOnClickListener(v -> { - searchEditText.setText(""); - AndroidUtilities.showKeyboard(searchEditText); - }); + box.addView(searchImageView, LayoutHelper.createFrame(36, 36, Gravity.LEFT | Gravity.TOP)); searchEditText = new EditTextBoldCursor(context) { @Override @@ -633,49 +773,207 @@ public boolean onTouchEvent(MotionEvent event) { searchEditText.setLines(1); searchEditText.setSingleLine(true); searchEditText.setImeOptions(EditorInfo.IME_ACTION_SEARCH | EditorInfo.IME_FLAG_NO_EXTRACT_UI); - if (type == 0) { - searchEditText.setHint(LocaleController.getString("SearchStickersHint", R.string.SearchStickersHint)); - } else if (type == 1) { - searchEditText.setHint(LocaleController.getString("SearchEmojiHint", R.string.SearchEmojiHint)); - } else if (type == 2) { - searchEditText.setHint(LocaleController.getString("SearchGifsTitle", R.string.SearchGifsTitle)); - } + searchEditText.setHint(LocaleController.getString("Search", R.string.Search)); searchEditText.setCursorColor(getThemedColor(Theme.key_featuredStickers_addedIcon)); - searchEditText.setCursorSize(AndroidUtilities.dp(20)); + searchEditText.setCursorSize(dp(20)); searchEditText.setCursorWidth(1.5f); - addView(searchEditText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 40, Gravity.LEFT | Gravity.TOP, 16 + 38, 12, 16 + 30, 0)); + searchEditText.setTranslationY(dp(-2)); + inputBox.addView(searchEditText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 40, Gravity.LEFT | Gravity.TOP, 0, 0, 28, 0)); searchEditText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { - } @Override public void afterTextChanged(Editable s) { - boolean show = searchEditText.length() > 0; - boolean showed = clearSearchImageView.getAlpha() != 0; - if (show != showed) { - clearSearchImageView.animate() - .alpha(show ? 1.0f : 0.0f) - .setDuration(150) - .scaleX(show ? 1.0f : 0.1f) - .scaleY(show ? 1.0f : 0.1f) - .start(); - } - if (type == 0) { - stickersSearchGridAdapter.search(searchEditText.getText().toString()); - } else if (type == 1) { - emojiSearchAdapter.search(searchEditText.getText().toString()); - } else if (type == 2) { - gifSearchAdapter.search(searchEditText.getText().toString()); + updateButton(); + final String query = searchEditText.getText().toString(); + search(query, true); + if (categoriesListView != null) { + categoriesListView.selectCategory(null); + categoriesListView.updateCategoriesShown(TextUtils.isEmpty(query), true); + } + toggleClear(!TextUtils.isEmpty(query)); + if (searchEditText != null) { + searchEditText.clearAnimation(); + searchEditText.animate().translationX(0).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); } + showInputBoxGradient(false); + } + }); + + inputBoxGradient = new View(context); + Drawable gradientDrawable = context.getResources().getDrawable(R.drawable.gradient_right).mutate(); + gradientDrawable.setColorFilter(new PorterDuffColorFilter(Theme.blendOver(getThemedColor(Theme.key_chat_emojiPanelBackground), getThemedColor(Theme.key_chat_emojiSearchBackground)), PorterDuff.Mode.MULTIPLY)); + inputBoxGradient.setBackground(gradientDrawable); + inputBoxGradient.setAlpha(0f); + inputBox.addView(inputBoxGradient, LayoutHelper.createFrame(18, LayoutHelper.MATCH_PARENT, Gravity.LEFT)); + + clear = new ImageView(context); + clear.setScaleType(ImageView.ScaleType.CENTER); + clear.setImageDrawable(new CloseProgressDrawable2(1.25f) { + { setSide(AndroidUtilities.dp(7)); } + @Override + protected int getCurrentColor() { + return Theme.getColor(Theme.key_chat_emojiSearchIcon, resourcesProvider); } }); + clear.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), Theme.RIPPLE_MASK_CIRCLE_20DP, AndroidUtilities.dp(15))); + clear.setAlpha(0f); + clear.setOnClickListener(e -> { + searchEditText.setText(""); + search(null, false); + if (categoriesListView != null) { + categoriesListView.scrollToStart(); + categoriesListView.selectCategory(null); + categoriesListView.updateCategoriesShown(true, true); + } + toggleClear(false); + if (searchEditText != null) { + searchEditText.clearAnimation(); + searchEditText.animate().translationX(0).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + } + showInputBoxGradient(false); + }); + box.addView(clear, LayoutHelper.createFrame(36, 36, Gravity.RIGHT | Gravity.TOP)); + + if (type != 1 || allowAnimatedEmoji && UserConfig.getInstance(UserConfig.selectedAccount).isPremium()) { + categoriesListView = new StickerCategoriesListView(context, null, StickerCategoriesListView.CategoriesType.DEFAULT, resourcesProvider) { + @Override + public void selectCategory(int categoryIndex) { + super.selectCategory(categoryIndex); + showBottomTab(categoriesListView.getSelectedCategory() == null, true); + if (type == 1 && emojiTabs != null) { + emojiTabs.showSelected(categoriesListView.getSelectedCategory() == null); + } else if (type == 0 && stickersTab != null) { + stickersTab.showSelected(categoriesListView.getSelectedCategory() == null); + } + updateButton(); + } + + @Override + protected boolean isTabIconsAnimationEnabled(boolean loaded) { + return !SharedConfig.getLiteMode().enabled(); + } + }; + categoriesListView.setDontOccupyWidth((int) (searchEditText.getPaint().measureText(searchEditText.getHint() + "")) + dp(16)); + categoriesListView.setBackgroundColor(Theme.blendOver(getThemedColor(Theme.key_chat_emojiPanelBackground), getThemedColor(Theme.key_chat_emojiSearchBackground))); + categoriesListView.setOnScrollIntoOccupiedWidth(scrolled -> { + searchEditText.setTranslationX(-Math.max(0, scrolled)); + showInputBoxGradient(scrolled > 0); + updateButton(); + }); + categoriesListView.setOnTouchListener(new OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + ignorePagerScroll = true; + } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + ignorePagerScroll = false; + } + return false; + } + }); + categoriesListView.setOnCategoryClick(category -> { + if (category == recent) { + showInputBoxGradient(false); + categoriesListView.selectCategory(recent); + gifSearchField.searchEditText.setText(""); + gifLayoutManager.scrollToPositionWithOffset(0, 0); + return; + } else if (category == trending) { + showInputBoxGradient(false); + gifSearchField.searchEditText.setText(""); + gifLayoutManager.scrollToPositionWithOffset(gifAdapter.trendingSectionItem, -dp(4)); + categoriesListView.selectCategory(trending); + final ArrayList gifSearchEmojies = MessagesController.getInstance(currentAccount).gifSearchEmojies; + if (!gifSearchEmojies.isEmpty()) { + gifSearchPreloader.preload(gifSearchEmojies.get(0)); + } + return; + } + if (categoriesListView.getSelectedCategory() == category) { + search(null, false); + categoriesListView.selectCategory(null); + } else { + search(category.emojis, false); + categoriesListView.selectCategory(category); + } + }); + box.addView(categoriesListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.LEFT | Gravity.TOP, 36, 0, 0, 0)); + } + } + + public boolean isCategorySelected() { + return categoriesListView != null && categoriesListView.getSelectedCategory() != null; + } + + public void search(String text, boolean delay) { + if (type == 0) { + stickersSearchGridAdapter.search(text, delay); + } else if (type == 1) { + emojiSearchAdapter.search(text, delay); + } else if (type == 2) { + gifSearchAdapter.search(text, delay); + } + } + + private boolean inputBoxShown = false; + + private void showInputBoxGradient(boolean show) { + if (show == inputBoxShown || inputBoxGradient == null) { + return; + } + inputBoxShown = show; + inputBoxGradient.clearAnimation(); + inputBoxGradient.animate().alpha(show ? 1 : 0).setDuration(120).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + } + + public boolean isInProgress() { + return isprogress; + } + + private Runnable delayedToggle; + private void toggleClear(boolean enabled) { + if (enabled) { + if (delayedToggle == null) { + AndroidUtilities.runOnUIThread(delayedToggle = () -> { + AndroidUtilities.updateViewShow(clear, true); + }, 340); + } + } else { + if (delayedToggle != null) { + AndroidUtilities.cancelRunOnUIThread(delayedToggle); + delayedToggle = null; + } + AndroidUtilities.updateViewShow(clear, false); + } + } + + private boolean isprogress; + public void showProgress(boolean progress) { + isprogress = progress; + if (progress) { + searchStateDrawable.setIconState(SearchStateDrawable.State.STATE_PROGRESS); + } else { + updateButton(true); + } + } + + private void updateButton() { + updateButton(false); + } + + private void updateButton(boolean force) { + if (!isInProgress() || searchEditText.length() == 0 && (categoriesListView == null || categoriesListView.getSelectedCategory() == null) || force) { + boolean backButton = searchEditText.length() > 0 || categoriesListView != null && categoriesListView.isCategoriesShown() && (categoriesListView.isScrolledIntoOccupiedWidth() || categoriesListView.getSelectedCategory() != null); + searchStateDrawable.setIconState(backButton ? SearchStateDrawable.State.STATE_BACK : SearchStateDrawable.State.STATE_SEARCH); + isprogress = false; + } } public void hideKeyboard() { @@ -930,65 +1228,48 @@ public boolean onTouchEvent(MotionEvent ev) { } } - private boolean premiumBulletin = true; - private class ImageViewEmoji extends ImageView { - public int position; - - public ImageReceiver imageReceiver; - public AnimatedEmojiDrawable drawable; - public boolean ignoring; - private boolean isRecent; - private AnimatedEmojiSpan span; - private EmojiPack pack; - private ImageReceiver.BackgroundThreadDrawHolder[] backgroundThreadDrawHolder = new ImageReceiver.BackgroundThreadDrawHolder[DrawingInBackgroundThreadDrawable.THREAD_COUNT]; - float pressedProgress; - ValueAnimator backAnimator; - - public ImageViewEmoji(Context context) { - super(context); - setScaleType(ImageView.ScaleType.CENTER); - setBackground(Theme.createRadSelectorDrawable(getThemedColor(Theme.key_listSelector), AndroidUtilities.dp(2), AndroidUtilities.dp(2))); + private void sendEmoji(ImageViewEmoji imageViewEmoji, String override) { + if (imageViewEmoji == null) { + return; } - - private void sendEmoji(String override) { - if (getSpan() != null) { + if (imageViewEmoji.getSpan() != null) { // if (pack != null && pack.set != null && (pack.free || UserConfig.getInstance(currentAccount).isPremium())) { // openEmojiPackAlert(pack.set); // return; // } - if (delegate != null) { - long documentId = getSpan().documentId; - TLRPC.Document document = getSpan().document; - String emoticon = null; - if (document == null) { - for (int i = 0; i < emojipacksProcessed.size(); ++i) { - EmojiPack pack = emojipacksProcessed.get(i); - for (int j = 0; pack.documents != null && j < pack.documents.size(); ++j) { - if (pack.documents.get(j).id == documentId) { - document = pack.documents.get(j); - break; - } + if (delegate != null) { + long documentId = imageViewEmoji.getSpan().documentId; + TLRPC.Document document = imageViewEmoji.getSpan().document; + String emoticon = null; + if (document == null) { + for (int i = 0; i < emojipacksProcessed.size(); ++i) { + EmojiPack pack = emojipacksProcessed.get(i); + for (int j = 0; pack.documents != null && j < pack.documents.size(); ++j) { + if (pack.documents.get(j).id == documentId) { + document = pack.documents.get(j); + break; } } } - if (document == null) { - document = AnimatedEmojiDrawable.findDocument(currentAccount, documentId); - } - if (emoticon == null && document != null) { - emoticon = MessageObject.findAnimatedEmojiEmoticon(document); - } - if (!MessageObject.isFreeEmoji(document) && !UserConfig.getInstance(currentAccount).isPremium() && !(delegate != null && delegate.isUserSelf()) && !allowEmojisForNonPremium) { - showBottomTab(false, true); - BulletinFactory factory = fragment != null ? BulletinFactory.of(fragment) : BulletinFactory.of(bulletinContainer, resourcesProvider); - if (premiumBulletin || fragment == null) { - factory.createEmojiBulletin( + } + if (document == null) { + document = AnimatedEmojiDrawable.findDocument(currentAccount, documentId); + } + if (emoticon == null && document != null) { + emoticon = MessageObject.findAnimatedEmojiEmoticon(document); + } + if (!MessageObject.isFreeEmoji(document) && !UserConfig.getInstance(currentAccount).isPremium() && !(delegate != null && delegate.isUserSelf()) && !allowEmojisForNonPremium) { + showBottomTab(false, true); + BulletinFactory factory = fragment != null ? BulletinFactory.of(fragment) : BulletinFactory.of(bulletinContainer, resourcesProvider); + if (premiumBulletin || fragment == null) { + factory.createEmojiBulletin( document, AndroidUtilities.replaceTags(LocaleController.getString("UnlockPremiumEmojiHint", R.string.UnlockPremiumEmojiHint)), LocaleController.getString("PremiumMore", R.string.PremiumMore), EmojiView.this::openPremiumAnimatedEmojiFeature - ).show(); - } else { - factory.createSimpleBulletin( + ).show(); + } else { + factory.createSimpleBulletin( R.raw.saved_messages, AndroidUtilities.replaceTags(LocaleController.getString("UnlockPremiumEmojiHint2", R.string.UnlockPremiumEmojiHint2)), LocaleController.getString("Open", R.string.Open), @@ -1010,39 +1291,59 @@ public void onTransitionAnimationEnd(boolean isOpen, boolean backward) { } }); } - ).show(); - } - premiumBulletin = !premiumBulletin; - return; + ).show(); } - shownBottomTabAfterClick = SystemClock.elapsedRealtime(); - showBottomTab(true, true); - addEmojiToRecent("animated_" + documentId); - delegate.onCustomEmojiSelected(documentId, document, emoticon, isRecent); + premiumBulletin = !premiumBulletin; + return; } - return; + shownBottomTabAfterClick = SystemClock.elapsedRealtime(); + showBottomTab(true, true); + addEmojiToRecent("animated_" + documentId); + delegate.onCustomEmojiSelected(documentId, document, emoticon, imageViewEmoji.isRecent); } - shownBottomTabAfterClick = SystemClock.elapsedRealtime(); - showBottomTab(true, true); - String code = override != null ? override : (String) getTag(); - SpannableStringBuilder builder = new SpannableStringBuilder(); - builder.append(code); - if (override == null) { - if (!isRecent) { - String color = Emoji.emojiColor.get(code); - if (color != null) { - code = addColorToCode(code, color); - } - } - addEmojiToRecent(code); - if (delegate != null) { - delegate.onEmojiSelected(Emoji.fixEmoji(code)); - } - } else { - if (delegate != null) { - delegate.onEmojiSelected(Emoji.fixEmoji(override)); + return; + } + shownBottomTabAfterClick = SystemClock.elapsedRealtime(); + showBottomTab(true, true); + String code = override != null ? override : (String) imageViewEmoji.getTag(); + SpannableStringBuilder builder = new SpannableStringBuilder(); + builder.append(code); + if (override == null) { + if (!imageViewEmoji.isRecent) { + String color = Emoji.emojiColor.get(code); + if (color != null) { + code = addColorToCode(code, color); } } + addEmojiToRecent(code); + if (delegate != null) { + delegate.onEmojiSelected(Emoji.fixEmoji(code)); + } + } else { + if (delegate != null) { + delegate.onEmojiSelected(Emoji.fixEmoji(override)); + } + } + } + + private boolean premiumBulletin = true; + public static class ImageViewEmoji extends ImageView { + public int position; + + public ImageReceiver imageReceiver; + public AnimatedEmojiDrawable drawable; + public boolean ignoring; + private boolean isRecent; + private AnimatedEmojiSpan span; + private EmojiPack pack; + private ImageReceiver.BackgroundThreadDrawHolder[] backgroundThreadDrawHolder = new ImageReceiver.BackgroundThreadDrawHolder[DrawingInBackgroundThreadDrawable.THREAD_COUNT]; + float pressedProgress; + ValueAnimator backAnimator; + + public ImageViewEmoji(Context context) { + super(context); + setScaleType(ImageView.ScaleType.CENTER); + setBackground(Theme.createRadSelectorDrawable(Theme.getColor(Theme.key_listSelector), AndroidUtilities.dp(2), AndroidUtilities.dp(2))); } public void setImageDrawable(Drawable drawable, boolean recent) { @@ -1335,7 +1636,7 @@ public EmojiView(BaseFragment fragment, boolean needAnimatedEmoji, boolean needS int color = getThemedColor(Theme.key_chat_emojiBottomPanelIcon); color = Color.argb(30, Color.red(color), Color.green(color), Color.blue(color)); - searchFieldHeight = AndroidUtilities.dp(64); + searchFieldHeight = AndroidUtilities.dp(50); needEmojiSearch = needSearch; tabIcons = new Drawable[]{ @@ -1405,6 +1706,7 @@ public void getOutline(View view, Outline outline) { emojiItemAnimator.setChangeDuration(160); emojiItemAnimator.setMoveInterpolator(CubicBezierInterpolator.EASE_OUT); emojiGridView.setItemAnimator(emojiItemAnimator); + emojiGridView.setOnTouchListener((v, event) -> ContentPreviewViewer.getInstance().onTouch(event, emojiGridView, EmojiView.this.getMeasuredHeight(), null, contentPreviewViewerDelegate, resourcesProvider)); emojiGridView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { @Override public boolean onItemClick(View view, int position) { @@ -1547,6 +1849,7 @@ public int getSpanSize(int position) { needEmojiSearch && position == 0 || position == emojiAdapter.trendingRow || position == emojiAdapter.trendingHeaderRow || + position == emojiAdapter.recentlyUsedHeaderRow || emojiAdapter.positionToSection.indexOfKey(position) >= 0 || emojiAdapter.positionToUnlock.indexOfKey(position) >= 0 ) { @@ -1626,11 +1929,22 @@ public void setTranslationY(float translationY) { } } + @Override + protected boolean doIncludeFeatured() { + return !(featuredEmojiSets.size() > 0 && featuredEmojiSets.get(0).set != null && MessagesController.getEmojiSettings(currentAccount).getLong("emoji_featured_hidden", 0) != featuredEmojiSets.get(0).set.id && UserConfig.getInstance(UserConfig.selectedAccount).isPremium()); + } + @Override protected boolean onTabClick(int index) { if (emojiSmoothScrolling) { return false; } + if (emojiSearchAdapter != null) { + emojiSearchAdapter.search(null); + } + if (emojiSearchField != null && emojiSearchField.categoriesListView != null) { + emojiSearchField.categoriesListView.selectCategory(null); + } Integer position = null; int offset = 0; if (index == 0) { @@ -1735,7 +2049,7 @@ protected void onMeasure(int widthSpec, int heightSpec) { protected void onLayout(boolean changed, int l, int t, int r, int b) { if (firstGifAttach && gifAdapter.getItemCount() > 1) { ignoreLayout = true; - gifLayoutManager.scrollToPositionWithOffset(1, 0); + gifLayoutManager.scrollToPositionWithOffset(0, 0); gifSearchField.setVisibility(VISIBLE); gifTabs.onPageScrolled(0, 0); firstGifAttach = false; @@ -1765,17 +2079,17 @@ public void getItemOffsets(android.graphics.Rect outRect, View view, RecyclerVie return; } - if (position != 0) { + if (position != 0 || !gifAdapter.addSearch) { outRect.left = 0; outRect.bottom = 0; outRect.top = AndroidUtilities.dp(2); - outRect.right = gifLayoutManager.isLastInRow(position - 1) ? 0 : AndroidUtilities.dp(2); + outRect.right = gifLayoutManager.isLastInRow(position - (gifAdapter.addSearch ? 1 : 0)) ? 0 : AndroidUtilities.dp(2); } else { outRect.set(0, 0, 0, 0); } } }); - gifGridView.setPadding(0, AndroidUtilities.dp(36 + 4), 0, AndroidUtilities.dp(44)); + gifGridView.setPadding(0, searchFieldHeight, 0, AndroidUtilities.dp(44)); gifGridView.setOverScrollMode(RecyclerListView.OVER_SCROLL_NEVER); ((SimpleItemAnimator) gifGridView.getItemAnimator()).setSupportsChangeAnimations(false); gifGridView.setAdapter(gifAdapter = new GifAdapter(context, true)); @@ -1786,7 +2100,9 @@ public void getItemOffsets(android.graphics.Rect outRect, View view, RecyclerVie if (delegate == null) { return; } - position--; + if (gifAdapter.addSearch) { + position--; + } if (gifGridView.getAdapter() == gifAdapter) { if (position < 0) { return; @@ -1816,7 +2132,7 @@ public void getItemOffsets(android.graphics.Rect outRect, View view, RecyclerVie gifContainer.addView(gifGridView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); gifSearchField = new SearchField(context, 2); - gifSearchField.setVisibility(INVISIBLE); +// gifSearchField.setVisibility(INVISIBLE); gifContainer.addView(gifSearchField, new FrameLayout.LayoutParams(LayoutHelper.MATCH_PARENT, searchFieldHeight + AndroidUtilities.getShadowHeight())); gifTabs = new DraggableScrollSlidingTabStrip(context, resourcesProvider); @@ -1825,7 +2141,7 @@ public void getItemOffsets(android.graphics.Rect outRect, View view, RecyclerVie gifTabs.setIndicatorColor(getThemedColor(Theme.key_chat_emojiPanelStickerPackSelectorLine)); gifTabs.setUnderlineColor(getThemedColor(Theme.key_chat_emojiPanelShadowLine)); gifTabs.setBackgroundColor(getThemedColor(Theme.key_chat_emojiPanelBackground)); - gifContainer.addView(gifTabs, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, StickerTabView.SMALL_HEIGHT, Gravity.LEFT | Gravity.TOP)); +// gifContainer.addView(gifTabs, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, StickerTabView.SMALL_HEIGHT, Gravity.LEFT | Gravity.TOP)); updateGifTabs(); gifTabs.setDelegate(page -> { @@ -1907,7 +2223,7 @@ public void setVisibility(int visibility) { protected void onLayout(boolean changed, int l, int t, int r, int b) { if (firstStickersAttach && stickersGridAdapter.getItemCount() > 0) { ignoreLayout = true; - stickersLayoutManager.scrollToPositionWithOffset(1, 0); + stickersLayoutManager.scrollToPositionWithOffset(0, 0); firstStickersAttach = false; ignoreLayout = false; } @@ -1922,8 +2238,15 @@ public void requestLayout() { } super.requestLayout(); } - }; + @Override + public void onScrolled(int dx, int dy) { + super.onScrolled(dx, dy); + if (stickersTabContainer != null) { + stickersTab.setUnderlineHeight(stickersGridView.canScrollVertically(-1) ? AndroidUtilities.getShadowHeight() : 0); + } + } + }; stickersGridView.setLayoutManager(stickersLayoutManager = new GridLayoutManager(context, 5) { @Override public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { @@ -1975,7 +2298,7 @@ public int getSpanSize(int position) { } } }); - stickersGridView.setPadding(0, AndroidUtilities.dp(4 + 36), 0, AndroidUtilities.dp(44)); + stickersGridView.setPadding(0, AndroidUtilities.dp(36), 0, AndroidUtilities.dp(44)); stickersGridView.setClipToPadding(false); Tab stickersTabHolder = new Tab(); @@ -2079,7 +2402,7 @@ protected void invalidateOverlays() { stickersTab.setDragEnabled(true); stickersTab.setWillNotDraw(false); stickersTab.setType(ScrollSlidingTabStrip.Type.TAB); - stickersTab.setUnderlineHeight(AndroidUtilities.getShadowHeight()); + stickersTab.setUnderlineHeight(stickersGridView.canScrollVertically(-1) ? AndroidUtilities.getShadowHeight() : 0); stickersTab.setIndicatorColor(getThemedColor(Theme.key_chat_emojiPanelStickerPackSelectorLine)); stickersTab.setUnderlineColor(getThemedColor(Theme.key_chat_emojiPanelShadowLine)); @@ -2124,7 +2447,14 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto if (page == trendingTabNum) { openTrendingStickers(null); return; - } else if (page == recentTabNum) { + } + + if (stickersSearchField != null && stickersSearchField.isCategorySelected()) { + stickersSearchField.search(null, false); + stickersSearchField.categoriesListView.selectCategory(null); + } + + if (page == recentTabNum) { stickersGridView.stopScroll(); scrollStickersToPosition(stickersGridAdapter.getPositionForPack("recent"), 0); resetTabsY(Type.STICKERS); @@ -2178,6 +2508,9 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto pager = new ViewPager(context) { @Override public boolean onInterceptTouchEvent(MotionEvent ev) { + if (ignorePagerScroll) { + return false; + } if (getParent() != null) { getParent().requestDisallowInterceptTouchEvent(canScrollHorizontally(-1)); } @@ -2198,12 +2531,12 @@ public void setCurrentItem(int item, boolean smoothScroll) { animator.setDuration(150); animator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); animator.start(); - scrollEmojisToPosition(0, 0); + scrollEmojisToPosition(1, 0); if (emojiTabs != null) { emojiTabs.select(0); } } else if (item == 1) { - gifGridView.smoothScrollToPosition(1); + gifGridView.smoothScrollToPosition(0); } else { stickersGridView.smoothScrollToPosition(1); } @@ -2253,15 +2586,8 @@ public void onClick(View v) { addView(bulletinContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 100, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0, 0, 0)); } - bottomTabContainer = new FrameLayout(context) { - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - if (getParent() != null) { - getParent().requestDisallowInterceptTouchEvent(true); - } - return super.onInterceptTouchEvent(ev); - } - }; + bottomTabContainer = new FrameLayout(context); + bottomTabContainer.setClickable(true); shadowLine = new View(context); shadowLine.setBackgroundColor(getThemedColor(Theme.key_chat_emojiPanelShadowLine)); @@ -2299,9 +2625,10 @@ public void onClick(View v) { typeTabs = new PagerSlidingTabStrip(context, resourcesProvider); typeTabs.setViewPager(pager); typeTabs.setShouldExpand(false); - typeTabs.setIndicatorHeight(0); + typeTabs.setIndicatorHeight(AndroidUtilities.dp(3)); + typeTabs.setIndicatorColor(getThemedColor(Theme.key_chat_emojiPanelIconSelected)); typeTabs.setUnderlineHeight(0); - typeTabs.setTabPaddingLeftRight(AndroidUtilities.dp(10)); + typeTabs.setTabPaddingLeftRight(AndroidUtilities.dp(13)); bottomTabContainer.addView(typeTabs, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 40, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM)); typeTabs.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override @@ -2372,6 +2699,7 @@ public void onPageScrollStateChanged(int state) { searchButton.setScaleType(ImageView.ScaleType.CENTER); searchButton.setContentDescription(LocaleController.getString("Search", R.string.Search)); searchButton.setFocusable(true); + searchButton.setVisibility(View.GONE); if (Build.VERSION.SDK_INT >= 21) { searchButton.setBackground(Theme.createSelectorDrawable(color, Theme.RIPPLE_MASK_CIRCLE_20DP, AndroidUtilities.dp(18))); } @@ -2435,9 +2763,9 @@ public void getOutline(View view, Outline outline) { addView(pager, 0, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); mediaBanTooltip = new CorrectlyMeasuringTextView(context); - mediaBanTooltip.setBackgroundDrawable(Theme.createRoundRectDrawable(AndroidUtilities.dp(3), getThemedColor(Theme.key_chat_gifSaveHintBackground))); + mediaBanTooltip.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(6), getThemedColor(Theme.key_chat_gifSaveHintBackground))); mediaBanTooltip.setTextColor(getThemedColor(Theme.key_chat_gifSaveHintText)); - mediaBanTooltip.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(7), AndroidUtilities.dp(8), AndroidUtilities.dp(7)); + mediaBanTooltip.setPadding(AndroidUtilities.dp(12), AndroidUtilities.dp(7), AndroidUtilities.dp(12), AndroidUtilities.dp(7)); mediaBanTooltip.setGravity(Gravity.CENTER_VERTICAL); mediaBanTooltip.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); mediaBanTooltip.setVisibility(INVISIBLE); @@ -2475,6 +2803,12 @@ public EmojiGridView(Context context) { super(context); } + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + boolean result = ContentPreviewViewer.getInstance().onInterceptTouchEvent(event, this, 0, contentPreviewViewerDelegate, resourcesProvider); + return super.onInterceptTouchEvent(event) || result; + } + private boolean ignoreLayout; SparseArray> viewsGroupedByLines = new SparseArray<>(); @@ -2511,7 +2845,7 @@ protected void onMeasure(int widthSpec, int heightSpec) { protected void onLayout(boolean changed, int l, int t, int r, int b) { if (needEmojiSearch && firstEmojiAttach) { ignoreLayout = true; - emojiLayoutManager.scrollToPositionWithOffset(1, 0); + emojiLayoutManager.scrollToPositionWithOffset(0, 0); firstEmojiAttach = false; ignoreLayout = false; } @@ -2562,7 +2896,7 @@ public boolean onTouchEvent(MotionEvent event) { Emoji.emojiColor.remove(code); } emojiTouchedView.setImageDrawable(Emoji.getEmojiBigDrawable(code), emojiTouchedView.isRecent); - emojiTouchedView.sendEmoji(null); + sendEmoji(emojiTouchedView, null); try { performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); } catch (Exception ignore) {} @@ -2574,11 +2908,10 @@ public boolean onTouchEvent(MotionEvent event) { .replace("\uD83C\uDFFD", "") .replace("\uD83C\uDFFE", "") .replace("\uD83C\uDFFF", ""); - if (color != null) { - emojiTouchedView.sendEmoji(addColorToCode(code, color)); + sendEmoji(emojiTouchedView, addColorToCode(code, color)); } else { - emojiTouchedView.sendEmoji(code); + sendEmoji(emojiTouchedView, code); } } } @@ -2688,7 +3021,6 @@ protected void dispatchDraw(Canvas canvas) { } } } - } } @@ -2786,6 +3118,26 @@ public void clearTouchesFor(View view) { } } } + public void clearAllTouches() { + if (touches != null) { + for (Map.Entry e : touches.entrySet()) { + if (e != null) { + View view = e.getValue().view; + if (view != null) { + TouchDownInfo touch = touches.remove(e.getKey()); + if (touch != null) { + if (touch.view != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && touch.view.getBackground() instanceof RippleDrawable) { + touch.view.getBackground().setState(new int[]{}); + } + if (touch.view != null) { + touch.view.setPressed(false); + } + } + } + } + } + } + } public long animateExpandDuration() { return animateExpandAppearDuration() + animateExpandCrossfadeDuration() + 150; @@ -2980,15 +3332,16 @@ public boolean dispatchTouchEvent(MotionEvent ev) { (!pickerViewPopup.isShowing() || SystemClock.elapsedRealtime() - touch.time < ViewConfiguration.getLongPressTimeout()) ) { View view = touch.view; + int position = getChildAdapterPosition(touch.view); if (view instanceof ImageViewEmoji) { ImageViewEmoji viewEmoji = (ImageViewEmoji) view; - viewEmoji.sendEmoji(null); + sendEmoji(viewEmoji, null); try { performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); } catch (Exception ignore) {} } else if (view instanceof EmojiPackExpand) { EmojiPackExpand button = (EmojiPackExpand) view; - emojiAdapter.expand(getChildAdapterPosition(button), button); + emojiAdapter.expand(position, button); try { performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); } catch (Exception ignore) {} @@ -3162,7 +3515,7 @@ private void updateEmojiTabsPosition() { private void updateEmojiTabsPosition(int position) { if (!emojiSmoothScrolling && position != RecyclerView.NO_POSITION) { int tab = 0; - int count = getRecentEmoji().size() + (needEmojiSearch ? 1 : 0); + int count = getRecentEmoji().size() + (needEmojiSearch ? 1 : 0) + (emojiAdapter.trendingHeaderRow >= 0 ? 3 : 0); if (position >= count) { tab = -1; for (int a = 0; a < EmojiData.dataColored.length; a++) { @@ -3771,8 +4124,6 @@ public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull R // if (parent.getChildAdapterPosition(view) == emojiAdapter.firstTrendingRow) { // outRect.top = AndroidUtilities.dp(32); // } - } else { - outRect.bottom = AndroidUtilities.dp(6); } } else if (view instanceof BackupImageView) { outRect.bottom = AndroidUtilities.dp(12); @@ -3862,22 +4213,21 @@ public void setTranslationY(float translationY) { updateBottomTabContainerPosition(); } private void updateBottomTabContainerPosition() { - if (bottomTabContainer.getTag() == null && (delegate == null || !delegate.isSearchOpened()) && (pager == null || pager.getCurrentItem() != 0)) { - View parent = (View) getParent(); - if (parent != null) { - float y = getY() - parent.getHeight(); - if (getLayoutParams().height > 0) { - y += getLayoutParams().height; - } else { - y += getMeasuredHeight(); - } - if (bottomTabContainer.getTop() - y < 0) { - y = bottomTabContainer.getTop(); - } - bottomTabContainer.setTranslationY(-y); - if (needEmojiSearch) { - bulletinContainer.setTranslationY(-y); - } + View parent = (View) getParent(); + if (parent != null) { + float y = getY() - parent.getHeight(); + if (getLayoutParams().height > 0) { + y += getLayoutParams().height; + } else { + y += getMeasuredHeight(); + } + if (bottomTabContainer.getTop() - y < 0) { + y = 0; + } + bottomTabMainTranslation = -y; + bottomTabContainer.setTranslationY(bottomTabMainTranslation + bottomTabAdditionalTranslation); + if (needEmojiSearch) { + bulletinContainer.setTranslationY(bottomTabMainTranslation + bottomTabAdditionalTranslation); } } } @@ -4014,7 +4364,7 @@ public void showSearchField(boolean show) { } } else { if (position == 0) { - layoutManager.scrollToPositionWithOffset(1, 0); + layoutManager.scrollToPositionWithOffset(0, 0); } } } @@ -4075,7 +4425,7 @@ private void openSearch(SearchField searchField) { ObjectAnimator.ofFloat(currentField, View.TRANSLATION_Y, AndroidUtilities.dp(0))); } else { searchAnimation.playTogether( - ObjectAnimator.ofFloat(gridView, View.TRANSLATION_Y, -AndroidUtilities.dp(36)), + ObjectAnimator.ofFloat(gridView, View.TRANSLATION_Y, a == 2 ? 0 : -AndroidUtilities.dp(36)), ObjectAnimator.ofFloat(currentField, View.TRANSLATION_Y, AndroidUtilities.dp(0))); } searchAnimation.setDuration(220); @@ -4086,9 +4436,11 @@ public void onAnimationEnd(Animator animation) { if (animation.equals(searchAnimation)) { gridView.setTranslationY(0); if (gridView == stickersGridView) { - gridView.setPadding(0, AndroidUtilities.dp(4), 0, 0); - } else if (gridView == emojiGridView || gridView == gifGridView) { gridView.setPadding(0, 0, 0, 0); + } else if (gridView == emojiGridView) { + gridView.setPadding(AndroidUtilities.dp(5), 0, AndroidUtilities.dp(5), 0); + } else if (gridView == gifGridView) { + gridView.setPadding(0, searchFieldHeight, 0, 0); } searchAnimation = null; } @@ -4109,8 +4461,10 @@ public void onAnimationCancel(Animator animation) { } if (gridView == stickersGridView) { gridView.setPadding(0, AndroidUtilities.dp(4), 0, 0); - } else if (gridView == emojiGridView || gridView == gifGridView) { - gridView.setPadding(0, 0, 0, 0); + } else if (gridView == emojiGridView) { + gridView.setPadding(AndroidUtilities.dp(5), 0, AndroidUtilities.dp(5), 0); + } else if (gridView == gifGridView) { + gridView.setPadding(0, searchFieldHeight, 0, 0); } if (gridView == gifGridView) { if (gifSearchAdapter.showTrendingWhenSearchEmpty = gifAdapter.results.size() > 0) { @@ -4123,6 +4477,7 @@ public void onAnimationCancel(Animator animation) { layoutManager.scrollToPositionWithOffset(0, 0); } } + showBottomTab(false, true); } private void showEmojiShadow(boolean show, boolean animated) { @@ -4256,18 +4611,23 @@ public void closeSearch(boolean animated, long scrollToSet) { } currentField.searchEditText.setText(""); + if (currentField.categoriesListView != null) { + currentField.categoriesListView.selectCategory(null); + currentField.categoriesListView.scrollToStart(); + } if (a == currentItem && animated) { searchAnimation = new AnimatorSet(); - if (tabStrip != null && a != 2) { + if (tabStrip != null && a != 1) { searchAnimation.playTogether( - ObjectAnimator.ofFloat(tabStrip, View.TRANSLATION_Y, 0), - ObjectAnimator.ofFloat(gridView, View.TRANSLATION_Y, AndroidUtilities.dp(36) - searchFieldHeight), - ObjectAnimator.ofFloat(currentField, View.TRANSLATION_Y, AndroidUtilities.dp(36) - searchFieldHeight)); + ObjectAnimator.ofFloat(tabStrip, View.TRANSLATION_Y, 0), + ObjectAnimator.ofFloat(gridView, View.TRANSLATION_Y, AndroidUtilities.dp(36)), + ObjectAnimator.ofFloat(currentField, View.TRANSLATION_Y, AndroidUtilities.dp(36)) + ); } else { searchAnimation.playTogether( - ObjectAnimator.ofFloat(gridView, View.TRANSLATION_Y, AndroidUtilities.dp(36) - searchFieldHeight), - ObjectAnimator.ofFloat(currentField, View.TRANSLATION_Y, -searchFieldHeight)); + ObjectAnimator.ofFloat(gridView, View.TRANSLATION_Y, AndroidUtilities.dp(36) - searchFieldHeight) + ); } searchAnimation.setDuration(200); searchAnimation.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); @@ -4276,21 +4636,16 @@ public void closeSearch(boolean animated, long scrollToSet) { public void onAnimationEnd(Animator animation) { if (animation.equals(searchAnimation)) { int firstVisPos = layoutManager.findFirstVisibleItemPosition(); - int top = 0; - if (firstVisPos != RecyclerView.NO_POSITION) { - View firstVisView = layoutManager.findViewByPosition(firstVisPos); - top = (int) (firstVisView.getTop() + gridView.getTranslationY()); - } gridView.setTranslationY(0); if (gridView == stickersGridView) { - gridView.setPadding(0, AndroidUtilities.dp(36 + 4), 0, AndroidUtilities.dp(44)); + gridView.setPadding(0, AndroidUtilities.dp(36), 0, AndroidUtilities.dp(44)); } else if (gridView == gifGridView) { - gridView.setPadding(0, AndroidUtilities.dp(36 + 4), 0, AndroidUtilities.dp(44)); + gridView.setPadding(0, searchFieldHeight, 0, AndroidUtilities.dp(44)); } else if (gridView == emojiGridView) { - gridView.setPadding(0, AndroidUtilities.dp(36), 0, AndroidUtilities.dp(44)); + gridView.setPadding(AndroidUtilities.dp(5), AndroidUtilities.dp(36), AndroidUtilities.dp(5), AndroidUtilities.dp(44)); } if (firstVisPos != RecyclerView.NO_POSITION) { - layoutManager.scrollToPositionWithOffset(firstVisPos, top - gridView.getPaddingTop()); + layoutManager.scrollToPositionWithOffset(firstVisPos, 0); } searchAnimation = null; } @@ -4305,24 +4660,25 @@ public void onAnimationCancel(Animator animation) { }); searchAnimation.start(); } else { - currentField.setTranslationY(AndroidUtilities.dp(36) - searchFieldHeight); + if (currentField != gifSearchField) { + currentField.setTranslationY(AndroidUtilities.dp(36) - searchFieldHeight); + } if (tabStrip != null && a != 2) { tabStrip.setTranslationY(0); } if (gridView == stickersGridView) { - gridView.setPadding(0, AndroidUtilities.dp(36 + 4), 0, AndroidUtilities.dp(44)); + gridView.setPadding(0, AndroidUtilities.dp(36), 0, AndroidUtilities.dp(44)); } else if (gridView == gifGridView) { gridView.setPadding(0, AndroidUtilities.dp(36 + 4), 0, AndroidUtilities.dp(44)); } else if (gridView == emojiGridView) { - gridView.setPadding(0, AndroidUtilities.dp(36), 0, AndroidUtilities.dp(44)); + gridView.setPadding(AndroidUtilities.dp(5), AndroidUtilities.dp(36), AndroidUtilities.dp(5), AndroidUtilities.dp(44)); } - layoutManager.scrollToPositionWithOffset(1, 0); + layoutManager.scrollToPositionWithOffset(0, 0); } } if (!animated) { delegate.onSearchOpenClose(0); } - showBottomTab(true, animated); } private void checkStickersSearchFieldScroll(boolean isLayout) { @@ -4442,33 +4798,45 @@ public void onAnimationEnd(Animator animation) { } } + private ValueAnimator bottomTabContainerAnimator; + private float bottomTabMainTranslation, bottomTabAdditionalTranslation; private long shownBottomTabAfterClick; private void showBottomTab(boolean show, boolean animated) { lastBottomScrollDy = 0; - if (show && bottomTabContainer.getTag() == null || !show && bottomTabContainer.getTag() != null || delegate != null && delegate.isSearchOpened()) { + if (delegate != null && delegate.isSearchOpened()) { + show = false; + } + if (show && bottomTabContainer.getTag() == null || !show && bottomTabContainer.getTag() != null) { return; } - if (bottomTabContainerAnimation != null) { - bottomTabContainerAnimation.cancel(); - bottomTabContainerAnimation = null; + if (bottomTabContainerAnimator != null) { + bottomTabContainerAnimator.cancel(); + bottomTabContainerAnimator = null; } bottomTabContainer.setTag(show ? null : 1); if (animated) { - bottomTabContainerAnimation = new AnimatorSet(); - bottomTabContainerAnimation.playTogether( - ObjectAnimator.ofFloat(bottomTabContainer, View.TRANSLATION_Y, show ? 0 : AndroidUtilities.dp(needEmojiSearch ? 45 : 50)), - ObjectAnimator.ofFloat(bulletinContainer, View.TRANSLATION_Y, needEmojiSearch ? (show ? 0 : AndroidUtilities.dp(needEmojiSearch ? 45 : 50)) : bulletinContainer.getTranslationY()), - ObjectAnimator.ofFloat(shadowLine, View.TRANSLATION_Y, show ? 0 : AndroidUtilities.dp(45)) - ); - bottomTabContainerAnimation.setDuration(200); - bottomTabContainerAnimation.setInterpolator(CubicBezierInterpolator.EASE_OUT); - bottomTabContainerAnimation.start(); + bottomTabContainerAnimator = ValueAnimator.ofFloat(bottomTabAdditionalTranslation, show ? 0 : AndroidUtilities.dp(needEmojiSearch ? 45 : 50)); + bottomTabContainerAnimator.addUpdateListener(anm -> { + bottomTabAdditionalTranslation = (float) anm.getAnimatedValue(); + updateBottomTabContainerPosition(); + }); + bottomTabContainerAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (bottomTabContainerAnimator != animation) { + return; + } + bottomTabAdditionalTranslation = (float) bottomTabContainerAnimator.getAnimatedValue(); + updateBottomTabContainerPosition(); + bottomTabContainerAnimator = null; + } + }); + bottomTabContainerAnimator.setDuration(380); + bottomTabContainerAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + bottomTabContainerAnimator.start(); } else { - bottomTabContainer.setTranslationY(show ? 0 : AndroidUtilities.dp(needEmojiSearch ? 45 : 50)); - if (needEmojiSearch) { - bulletinContainer.setTranslationY(show ? 0 : AndroidUtilities.dp(needEmojiSearch ? 45 : 50)); - } - shadowLine.setTranslationY(show ? 0 : AndroidUtilities.dp(45)); + bottomTabAdditionalTranslation = show ? 0 : AndroidUtilities.dp(needEmojiSearch ? 45 : 50); + updateBottomTabContainerPosition(); } } @@ -4554,6 +4922,9 @@ private void animateSearchField(@Type int type) { } private void animateSearchField(@Type int type, boolean visible, int tabsMinusDy) { + if (type == Type.GIFS) { + return; + } if (getListViewForType(type).findViewHolderForAdapterPosition(0) == null) { return; } @@ -4710,17 +5081,17 @@ private void checkGifSearchFieldScroll(boolean isLayout) { if (gifSearchField == null || gifGridView == null) { return; } - RecyclerView.ViewHolder holder = gifGridView.findViewHolderForAdapterPosition(0); - if (holder != null) { - gifSearchField.setTranslationY(holder.itemView.getTop()); - } else { - gifSearchField.setTranslationY(-searchFieldHeight); - } - gifSearchField.showShadow(false, !isLayout); +// RecyclerView.ViewHolder holder = gifGridView.findViewHolderForAdapterPosition(0); +// if (holder != null) { +// gifSearchField.setTranslationY(holder.itemView.getTop()); +// } else { +// gifSearchField.setTranslationY(-searchFieldHeight); +// } + gifSearchField.showShadow(true, !isLayout); } private void scrollGifsToTop() { - gifLayoutManager.scrollToPositionWithOffset(delegate != null && delegate.isExpanded() ? 0 : 1, 0); + gifLayoutManager.scrollToPositionWithOffset(0, 0); resetTabsY(Type.GIFS); } @@ -4919,13 +5290,13 @@ private void updateStickerTabs(boolean updateStickerSets) { stickerSets.add(pack); } - if (!premiumStickers.isEmpty()) { - premiumTabNum = stickersTabOffset; - stickersTabOffset++; - StickerTabView stickerTabView = stickersTab.addStickerIconTab(4, PremiumGradient.getInstance().premiumStarMenuDrawable2); - stickerTabView.textView.setText(LocaleController.getString("PremiumStickersShort", R.string.PremiumStickersShort)); - stickerTabView.setContentDescription(LocaleController.getString("PremiumStickers", R.string.PremiumStickers)); - } +// if (!premiumStickers.isEmpty()) { +// premiumTabNum = stickersTabOffset; +// stickersTabOffset++; +// StickerTabView stickerTabView = stickersTab.addStickerIconTab(4, PremiumGradient.getInstance().premiumStarMenuDrawable2); +// stickerTabView.textView.setText(LocaleController.getString("PremiumStickersShort", R.string.PremiumStickersShort)); +// stickerTabView.setContentDescription(LocaleController.getString("PremiumStickers", R.string.PremiumStickers)); +// } if (info != null) { long hiddenStickerSetId = MessagesController.getEmojiSettings(currentAccount).getLong("group_hide_stickers_" + info.id, -1); @@ -4974,9 +5345,21 @@ private void updateStickerTabs(boolean updateStickerSets) { } } else { TLRPC.TL_messages_stickerSet stickerSet = stickerSets.get(a); - TLRPC.Document document = stickerSet.documents.get(0); + TLRPC.Document document = null; + if (stickerSet.set != null && stickerSet.set.thumb_document_id != 0) { + for (int i = 0; i < stickerSet.documents.size(); ++i) { + TLRPC.Document d = stickerSet.documents.get(i); + if (d != null && stickerSet.set.thumb_document_id == d.id) { + document = d; + break; + } + } + } + if (document == null) { + document = stickerSet.documents.get(0); + } TLObject thumb = FileLoader.getClosestPhotoSizeWithSize(stickerSet.set.thumbs, 90); - if (thumb == null || stickerSet.set.gifs) { + if (thumb == null || stickerSet.set.gifs) { thumb = document; } stickersTab.addStickerTab(thumb, document, stickerSet).setContentDescription(stickerSet.set.title + ", " + LocaleController.getString("AccDescrStickerSet", R.string.AccDescrStickerSet)); @@ -5051,6 +5434,9 @@ private void updateGifTabs() { if (wasRecentTabSelected && !hasRecent) { gifTabs.selectTab(gifTrendingTabNum); + if (gifSearchField != null && gifSearchField.categoriesListView != null) { + gifSearchField.categoriesListView.selectCategory(gifSearchField.trending); + } } else if (ViewCompat.isLaidOut(gifTabs)) { if (hasRecent && !hadRecent) { gifTabs.onPageScrolled(lastPosition + 1, 0); @@ -5128,10 +5514,9 @@ public void updateColors() { } searchField.backgroundView.setBackgroundColor(getThemedColor(Theme.key_chat_emojiPanelBackground)); searchField.shadowView.setBackgroundColor(getThemedColor(Theme.key_chat_emojiPanelShadowLine)); - searchField.clearSearchImageView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_emojiSearchIcon), PorterDuff.Mode.MULTIPLY)); - searchField.searchIconImageView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_emojiSearchIcon), PorterDuff.Mode.MULTIPLY)); - Theme.setDrawableColorByKey(searchField.searchBackground.getBackground(), Theme.key_chat_emojiSearchBackground); - searchField.searchBackground.invalidate(); + searchField.searchStateDrawable.setColor(getThemedColor(Theme.key_chat_emojiSearchIcon)); + Theme.setDrawableColorByKey(searchField.box.getBackground(), Theme.key_chat_emojiSearchBackground); + searchField.box.invalidate(); searchField.searchEditText.setHintTextColor(getThemedColor(Theme.key_chat_emojiSearchIcon)); searchField.searchEditText.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); } @@ -5255,31 +5640,8 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto lastNotifyWidth = right - left; reloadStickersAdapter(); } - View parent = (View) getParent(); - if (parent != null) { - int newHeight = bottom - top; - int newHeight2 = parent.getHeight(); - if (lastNotifyHeight != newHeight || lastNotifyHeight2 != newHeight2) { - if (delegate != null && delegate.isSearchOpened()) { - bottomTabContainer.setTranslationY(AndroidUtilities.dp(49)); - if (needEmojiSearch) { - bulletinContainer.setTranslationY(AndroidUtilities.dp(49)); - } - } else { - if (bottomTabContainer.getTag() == null) { - if (newHeight <= lastNotifyHeight) { - bottomTabContainer.setTranslationY(0); - if (needEmojiSearch) { - bulletinContainer.setTranslationY(0); - } - } - } - } - lastNotifyHeight = newHeight; - lastNotifyHeight2 = newHeight2; - } - } super.onLayout(changed, left, top, right, bottom); + updateBottomTabContainerPosition(); updateStickerTabsPosition(); } @@ -5318,9 +5680,12 @@ public void setForseMultiwindowLayout(boolean value) { } public void onOpen(boolean forceEmoji) { - if (currentPage != 0 && currentChatId != 0) { + if (currentPage != 0 && stickersBanned) { currentPage = 0; } + if (currentPage == 0 && emojiBanned) { + currentPage = 1; + } if (currentPage == 0 || forceEmoji || currentTabs.size() == 1) { showBackspaceButton(true, false); showStickerSettingsButton(false, false); @@ -5343,7 +5708,7 @@ public void onOpen(boolean forceEmoji) { stickersTab.selectTab(stickersTabOffset); } firstTabUpdate = false; - stickersLayoutManager.scrollToPositionWithOffset(1, 0); + stickersLayoutManager.scrollToPositionWithOffset(0, 0); } } else if (currentPage == 2) { showBackspaceButton(false, false); @@ -5354,7 +5719,11 @@ public void onOpen(boolean forceEmoji) { if (gifTabs != null) { gifTabs.selectTab(0); } + if (gifSearchField != null && gifSearchField.categoriesListView != null) { + gifSearchField.categoriesListView.selectCategory(gifSearchField.recent); + } } + showBottomTab(true, true); } @Override @@ -5488,91 +5857,97 @@ private void updateRecentGifs() { } } - public void setStickersBanned(boolean value, long chatId) { + public void setStickersBanned(boolean emojiBanned, boolean stickersBanned, long chatId) { if (typeTabs == null) { return; } - if (value) { + this.emojiBanned = emojiBanned; + this.stickersBanned = stickersBanned; + if (stickersBanned || emojiBanned) { currentChatId = chatId; } else { currentChatId = 0; } - View view = typeTabs.getTab(2); + View view = typeTabs.getTab(stickersBanned ? 2 : 0); if (view != null) { - view.setAlpha(currentChatId != 0 ? 0.5f : 1.0f); - if (currentChatId != 0 && pager.getCurrentItem() != 0) { - showBackspaceButton(true, true); - showStickerSettingsButton(false, true); - pager.setCurrentItem(0, false); + view.setAlpha(currentChatId != 0 ? 0.15f : 1.0f); + if (stickersBanned) { + if (currentChatId != 0 && pager.getCurrentItem() != 0) { + showBackspaceButton(true, true); + showStickerSettingsButton(false, true); + pager.setCurrentItem(0, false); + } + } else { + if (currentChatId != 0 && pager.getCurrentItem() != 1) { + showBackspaceButton(false, true); + showStickerSettingsButton(false, true); + pager.setCurrentItem(1, false); + } } } } - public void showStickerBanHint(boolean gif) { - if (mediaBanTooltip.getVisibility() == VISIBLE) { - return; - } + private AnimatorSet showStickersBanAnimator; + private Runnable hideStickersBan; + public void showStickerBanHint(boolean show, boolean emoji, boolean gif) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(currentChatId); if (chat == null) { return; } - String text; - if (!ChatObject.hasAdminRights(chat) && chat.default_banned_rights != null && chat.default_banned_rights.send_stickers) { - if (gif) { - mediaBanTooltip.setText(LocaleController.getString("GlobalAttachGifRestricted", R.string.GlobalAttachGifRestricted)); - } else { - mediaBanTooltip.setText(LocaleController.getString("GlobalAttachStickersRestricted", R.string.GlobalAttachStickersRestricted)); - } - } else { - if (chat.banned_rights == null) { - return; - } - if (AndroidUtilities.isBannedForever(chat.banned_rights)) { - if (gif) { - mediaBanTooltip.setText(LocaleController.getString("AttachGifRestrictedForever", R.string.AttachGifRestrictedForever)); + if (show) { + if (!ChatObject.hasAdminRights(chat) && chat.default_banned_rights != null && (chat.default_banned_rights.send_stickers || (emoji && chat.default_banned_rights.send_plain))) { + if (emoji) { + mediaBanTooltip.setText(LocaleController.getString("GlobalAttachEmojiRestricted", R.string.GlobalAttachEmojiRestricted)); + } else if (gif) { + mediaBanTooltip.setText(LocaleController.getString("GlobalAttachGifRestricted", R.string.GlobalAttachGifRestricted)); } else { - mediaBanTooltip.setText(LocaleController.getString("AttachStickersRestrictedForever", R.string.AttachStickersRestrictedForever)); + mediaBanTooltip.setText(LocaleController.getString("GlobalAttachStickersRestricted", R.string.GlobalAttachStickersRestricted)); } } else { - if (gif) { - mediaBanTooltip.setText(LocaleController.formatString("AttachGifRestricted", R.string.AttachGifRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date))); + if (chat.banned_rights == null) { + return; + } + if (AndroidUtilities.isBannedForever(chat.banned_rights)) { + if (emoji) { + mediaBanTooltip.setText(LocaleController.getString("AttachPlainRestrictedForever", R.string.AttachPlainRestrictedForever)); + } else if (gif) { + mediaBanTooltip.setText(LocaleController.getString("AttachGifRestrictedForever", R.string.AttachGifRestrictedForever)); + } else { + mediaBanTooltip.setText(LocaleController.getString("AttachStickersRestrictedForever", R.string.AttachStickersRestrictedForever)); + } } else { - mediaBanTooltip.setText(LocaleController.formatString("AttachStickersRestricted", R.string.AttachStickersRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date))); + if (emoji) { + mediaBanTooltip.setText(LocaleController.formatString("AttachPlainRestricted", R.string.AttachPlainRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date))); + } if (gif) { + mediaBanTooltip.setText(LocaleController.formatString("AttachGifRestricted", R.string.AttachGifRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date))); + } else { + mediaBanTooltip.setText(LocaleController.formatString("AttachStickersRestricted", R.string.AttachStickersRestricted, LocaleController.formatDateForBan(chat.banned_rights.until_date))); + } } } + mediaBanTooltip.setVisibility(View.VISIBLE); + } + + if (showStickersBanAnimator != null) { + showStickersBanAnimator.cancel(); + showStickersBanAnimator = null; } - mediaBanTooltip.setVisibility(View.VISIBLE); - AnimatorSet AnimatorSet = new AnimatorSet(); - AnimatorSet.playTogether( - ObjectAnimator.ofFloat(mediaBanTooltip, View.ALPHA, 0.0f, 1.0f) + + showStickersBanAnimator = new AnimatorSet(); + showStickersBanAnimator.playTogether( + ObjectAnimator.ofFloat(mediaBanTooltip, View.ALPHA, show ? mediaBanTooltip.getAlpha() : 1f, show ? 1f : 0f), + ObjectAnimator.ofFloat(mediaBanTooltip, View.TRANSLATION_Y, show ? AndroidUtilities.dp(12) : mediaBanTooltip.getTranslationY(), show ? 0 : AndroidUtilities.dp(12)) ); - AnimatorSet.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - AndroidUtilities.runOnUIThread(() -> { - if (mediaBanTooltip == null) { - return; - } - AnimatorSet AnimatorSet1 = new AnimatorSet(); - AnimatorSet1.playTogether( - ObjectAnimator.ofFloat(mediaBanTooltip, View.ALPHA, 0.0f) - ); - AnimatorSet1.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation1) { - if (mediaBanTooltip != null) { - mediaBanTooltip.setVisibility(View.INVISIBLE); - } - } - }); - AnimatorSet1.setDuration(300); - AnimatorSet1.start(); - }, 5000); - } - }); - AnimatorSet.setDuration(300); - AnimatorSet.start(); + if (hideStickersBan != null) { + AndroidUtilities.cancelRunOnUIThread(hideStickersBan); + } + if (show) { + AndroidUtilities.runOnUIThread(hideStickersBan = () -> showStickerBanHint(false, emoji, gif), 3500); + } + showStickersBanAnimator.setDuration(320); + showStickersBanAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + showStickersBanAnimator.start(); } private void updateVisibleTrendingSets() { @@ -5709,7 +6084,7 @@ public void didReceivedNotification(int id, int account, Object... args) { gifTabs.invalidateTabs(); } } else if (id == NotificationCenter.newEmojiSuggestionsAvailable) { - if (emojiGridView != null && needEmojiSearch && (emojiSearchField.progressDrawable.isAnimating() || emojiGridView.getAdapter() == emojiSearchAdapter) && !TextUtils.isEmpty(emojiSearchAdapter.lastSearchEmojiString)) { + if (emojiGridView != null && needEmojiSearch && (emojiSearchField.searchStateDrawable.getIconState() == SearchStateDrawable.State.STATE_PROGRESS || emojiGridView.getAdapter() == emojiSearchAdapter) && !TextUtils.isEmpty(emojiSearchAdapter.lastSearchEmojiString)) { emojiSearchAdapter.search(emojiSearchAdapter.lastSearchEmojiString); } } else if (id == NotificationCenter.currentUserPremiumStatusChanged) { @@ -5744,18 +6119,20 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); - TLRPC.StickerSetCovered set = (TLRPC.StickerSetCovered) getTag(); - if (MediaDataController.getInstance(currentAccount).isStickerPackUnread(emoji, set.set.id) && dotPaint != null) { - int x = canvas.getWidth() - AndroidUtilities.dp(8); - int y = AndroidUtilities.dp(14); - canvas.drawCircle(x, y, AndroidUtilities.dp(3), dotPaint); + if (!emoji) { + TLRPC.StickerSetCovered set = (TLRPC.StickerSetCovered) getTag(); + if (MediaDataController.getInstance(currentAccount).isStickerPackUnread(emoji, set.set.id) && dotPaint != null) { + int x = canvas.getWidth() - AndroidUtilities.dp(8); + int y = AndroidUtilities.dp(14); + canvas.drawCircle(x, y, AndroidUtilities.dp(3), dotPaint); + } } } }; - imageView.setSize(AndroidUtilities.dp(emoji ? 36 : 30), AndroidUtilities.dp(emoji ? 36 : 30)); + imageView.setSize(AndroidUtilities.dp(emoji ? 24 : 30), AndroidUtilities.dp(emoji ? 24 : 30)); imageView.setLayerNum(1); imageView.setAspectFit(true); - imageView.setLayoutParams(new RecyclerView.LayoutParams(AndroidUtilities.dp(42), AndroidUtilities.dp(42))); + imageView.setLayoutParams(new RecyclerView.LayoutParams(AndroidUtilities.dp(emoji ? 34 : 42), AndroidUtilities.dp(emoji ? 34 : 42))); return new RecyclerListView.Holder(imageView); } @@ -5765,10 +6142,44 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { TLRPC.StickerSetCovered set = (emoji ? featuredEmojiSets : featuredStickerSets).get(position); imageView.setTag(set); - TLRPC.Document document = set.cover; - if (!set.covers.isEmpty()) { - document = set.covers.get(0); + ArrayList setDocuments; + if (set instanceof TLRPC.TL_stickerSetFullCovered) { + setDocuments = ((TLRPC.TL_stickerSetFullCovered) set).documents; + } else if (set instanceof TLRPC.TL_stickerSetNoCovered) { + TLRPC.TL_messages_stickerSet fullSet = MediaDataController.getInstance(currentAccount).getStickerSet(MediaDataController.getInputStickerSet(set.set), false); + if (fullSet == null) { + setDocuments = null; + } else { + setDocuments = fullSet.documents; + } + } else { + setDocuments = set.covers; + } + + TLRPC.Document document = null; + if (set.cover != null) { + document = set.cover; + } else if (setDocuments != null && !setDocuments.isEmpty()) { + if (set.set != null) { + for (int i = 0; i < setDocuments.size(); ++i) { + if (setDocuments.get(i).id == set.set.thumb_document_id) { + document = setDocuments.get(i); + break; + } + } + } + if (document == null) { + document = setDocuments.get(0); + } } + if (document == null) { + return; + } + + if (this.emoji) { + imageView.setColorFilter(MessageObject.isTextColorEmoji(document) ? Theme.chat_animatedEmojiTextColorFilter : null); + } + TLObject object = FileLoader.getClosestPhotoSizeWithSize(set.set.thumbs, 90); SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(set.set.thumbs, Theme.key_emptyListPlaceholder, 0.2f); if (svgThumb != null) { @@ -5789,6 +6200,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else { return; } + if (imageLocation == null) { return; } @@ -6132,7 +6544,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } case 5: { StickerSetNameCell cell = (StickerSetNameCell) holder.itemView; - cell.setText(MediaDataController.getInstance(currentAccount).loadFeaturedPremium ? LocaleController.getString("FeaturedStickersPremium", R.string.FeaturedStickersPremium) : LocaleController.getString("FeaturedStickers", R.string.FeaturedStickers), R.drawable.msg_close); + cell.setText(MediaDataController.getInstance(currentAccount).loadFeaturedPremium ? LocaleController.getString("FeaturedStickersPremium", R.string.FeaturedStickersPremium) : LocaleController.getString("FeaturedStickers", R.string.FeaturedStickers), R.drawable.msg_close, LocaleController.getString("AccDescrCloseTrendingStickers", R.string.AccDescrCloseTrendingStickers)); break; } } @@ -6178,8 +6590,9 @@ private void updateItems() { documents = recentStickers; packStartPosition.put(key = "recent", totalItems); } else if (a == -1) { - documents = premiumStickers; - packStartPosition.put(key = "premium", totalItems); + continue; +// documents = premiumStickers; +// packStartPosition.put(key = "premium", totalItems); } else { key = null; pack = packs.get(a); @@ -6306,6 +6719,7 @@ private class EmojiGridAdapter extends RecyclerListView.SelectionAdapter { private int trendingHeaderRow = -1; private int trendingRow = -1; private int firstTrendingRow = -1; + private int recentlyUsedHeaderRow = -1; private ArrayList frozenEmojiPacks; private ArrayList rowHashCodes = new ArrayList<>(); @@ -6317,10 +6731,6 @@ private class EmojiGridAdapter extends RecyclerListView.SelectionAdapter { private int itemCount; public int plainEmojisCount; - void EmojiGridAdapter() { - MediaDataController mediaDataController = MediaDataController.getInstance(currentAccount); - } - @Override public int getItemCount() { return itemCount; @@ -6346,37 +6756,64 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType break; case VIEW_TYPE_HEADER: view = new StickerSetNameCell(getContext(), true, resourcesProvider); + ((StickerSetNameCell) view).setOnIconClickListener(e -> { + if (featuredEmojiSets == null || featuredEmojiSets.isEmpty() || featuredEmojiSets.get(0).set == null) { + return; + } + long lastSetId = featuredEmojiSets.get(0).set.id; + MessagesController.getEmojiSettings(currentAccount).edit().putLong("emoji_featured_hidden", lastSetId).commit(); + if (emojiAdapter != null) { + emojiAdapter.notifyItemRangeRemoved(1, 3); + } + if (emojiTabs != null) { + emojiTabs.updateEmojiPacks(getEmojipacks()); + } + updateRows(); + }); break; case VIEW_TYPE_PACK_HEADER: view = new EmojiPackHeader(getContext()); break; case VIEW_TYPE_TRENDING: TrendingListView listView = new TrendingListView(getContext(), trendingEmojiAdapter = new TrendingAdapter(true)); - listView.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 0); + listView.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(4), AndroidUtilities.dp(8), 0); listView.setClipToPadding(false); listView.addItemDecoration(new RecyclerView.ItemDecoration() { @Override public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { - outRect.right = AndroidUtilities.dp(8); + outRect.right = AndroidUtilities.dp(2); } }); listView.setOnItemClickListener((item, position) -> { - ArrayList inputStickerSets = new ArrayList<>(); - List featuredStickerSets = MediaDataController.getInstance(currentAccount).getFeaturedEmojiSets(); - for (int i = 0; featuredStickerSets != null && i < featuredStickerSets.size(); ++i) { - TLRPC.StickerSetCovered set = featuredStickerSets.get(i); - if (set != null && set.set != null) { - TLRPC.TL_inputStickerSetID inputStickerSet = new TLRPC.TL_inputStickerSetID(); - inputStickerSet.id = set.set.id; - inputStickerSet.access_hash = set.set.access_hash; - inputStickerSets.add(inputStickerSet); + if (item.getTag() instanceof TLRPC.StickerSetCovered) { + TLRPC.StickerSetCovered highlightSet = (TLRPC.StickerSetCovered) item.getTag(); + ArrayList inputStickerSets = new ArrayList<>(); + ArrayList sets = MediaDataController.getInstance(currentAccount).getFeaturedEmojiSets(); + int highlight = -1; + for (int i = 0; i < sets.size(); ++i) { + TLRPC.StickerSetCovered set = sets.get(i); + if (set != null && set.set != null) { + TLRPC.TL_inputStickerSetID inputStickerSet = new TLRPC.TL_inputStickerSetID(); + inputStickerSet.id = set.set.id; + inputStickerSet.access_hash = set.set.access_hash; + inputStickerSets.add(inputStickerSet); + + if (highlightSet != null && highlightSet.set != null && highlightSet.set.id == set.set.id) { + highlight = i; + } + } + } + + MediaDataController.getInstance(currentAccount).markFeaturedStickersAsRead(true, true); + EmojiPacksAlert alert = new EmojiPacksAlert(fragment, getContext(), fragment == null ? null : fragment.getResourceProvider(), inputStickerSets); + if (highlight >= 0) { + alert.highlight(highlight); + } + if (fragment != null) { + fragment.showDialog(alert); + } else { + alert.show(); } - } - MediaDataController.getInstance(currentAccount).markFeaturedStickersAsRead(true, true); - if (fragment != null) { - fragment.showDialog(new EmojiPacksAlert(fragment, getContext(), fragment.getResourceProvider(), inputStickerSets)); - } else { - new EmojiPacksAlert(null, getContext(), resourcesProvider, inputStickerSets).show(); } }); view = listView; @@ -6413,6 +6850,9 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, @SuppressLint("Recy if (needEmojiSearch) { position--; } + if (recentlyUsedHeaderRow >= 0) { + position--; + } if (trendingRow >= 0) { position -= 2; } @@ -6486,19 +6926,19 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, @SuppressLint("Recy StickerSetNameCell cell = (StickerSetNameCell) holder.itemView; cell.position = position; index = positionToSection.get(position); - String text; if (position == trendingHeaderRow) { - text = LocaleController.getString("FeaturedEmojiPacks", R.string.FeaturedEmojiPacks); + cell.setText(LocaleController.getString("FeaturedEmojiPacks", R.string.FeaturedEmojiPacks), R.drawable.msg_close, LocaleController.getString("AccDescrCloseTrendingEmoji", R.string.AccDescrCloseTrendingEmoji)); + } else if (position == recentlyUsedHeaderRow) { + cell.setText(LocaleController.getString("RecentlyUsed", R.string.RecentlyUsed), 0); } else if (index >= emojiTitles.length) { try { - text = emojipacksProcessed.get(index - emojiTitles.length).set.title; + cell.setText(emojipacksProcessed.get(index - emojiTitles.length).set.title, 0); } catch (Exception ignore) { - text = ""; + cell.setText("", 0); } } else { - text = emojiTitles[index]; + cell.setText(emojiTitles[index], 0); } - cell.setText(text, 0); break; } case VIEW_TYPE_EXPAND: @@ -6563,7 +7003,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, @SuppressLint("Recy public int getItemViewType(int position) { if (position == trendingRow) { return VIEW_TYPE_TRENDING; - } else if (position == trendingHeaderRow) { + } else if (position == trendingHeaderRow || position == recentlyUsedHeaderRow) { return VIEW_TYPE_HEADER; } else if (positionToSection.indexOfKey(position) >= 0) { return positionToSection.get(position) >= EmojiData.dataColored.length ? VIEW_TYPE_PACK_HEADER : VIEW_TYPE_HEADER; @@ -6758,17 +7198,20 @@ public void updateRows() { packStartPosition.clear(); rowHashCodes.clear(); itemCount = 0; + boolean isPremium = UserConfig.getInstance(currentAccount).isPremium() || allowEmojisForNonPremium; if (needEmojiSearch) { itemCount++; rowHashCodes.add(-1); } -// if (featuredEmojiSets.size() > 0) { -// trendingHeaderRow = itemCount++; -// trendingRow = itemCount++; -// } else { -// trendingHeaderRow = -1; -// trendingRow = -1; -// } + if (isPremium && allowAnimatedEmoji && featuredEmojiSets.size() > 0 && featuredEmojiSets.get(0).set != null && MessagesController.getEmojiSettings(currentAccount).getLong("emoji_featured_hidden", 0) != featuredEmojiSets.get(0).set.id) { + trendingHeaderRow = itemCount++; + trendingRow = itemCount++; + recentlyUsedHeaderRow = itemCount++; + } else { + trendingHeaderRow = -1; + trendingRow = -1; + recentlyUsedHeaderRow = -1; + } ArrayList recent = getRecentEmoji(); if (emojiTabs != null) { emojiTabs.showRecent(!recent.isEmpty()); @@ -6788,7 +7231,6 @@ public void updateRows() { } } - boolean isPremium = UserConfig.getInstance(currentAccount).isPremium() || allowEmojisForNonPremium; int maxlen = emojiLayoutManager.getSpanCount() * 3; plainEmojisCount = itemCount; firstTrendingRow = -1; @@ -7038,6 +7480,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { case 0: { ImageViewEmoji imageView = (ImageViewEmoji) holder.itemView; + imageView.position = position; imageView.pack = null; String code; @@ -7093,6 +7536,10 @@ public int getItemViewType(int position) { } public void search(String text) { + search(text, true); + } + + public void search(String text, boolean delay) { if (TextUtils.isEmpty(text)) { lastSearchEmojiString = null; if (emojiGridView.getAdapter() != emojiAdapter) { @@ -7107,11 +7554,11 @@ public void search(String text) { AndroidUtilities.cancelRunOnUIThread(searchRunnable); } if (!TextUtils.isEmpty(lastSearchEmojiString)) { - AndroidUtilities.runOnUIThread(searchRunnable = new Runnable() { - @Override - public void run() { - emojiSearchField.progressDrawable.startAnimation(); - String query = lastSearchEmojiString; + emojiSearchField.showProgress(true); + AndroidUtilities.runOnUIThread(searchRunnable = () -> { + final LinkedHashSet documentIds = new LinkedHashSet<>(); + final String query = lastSearchEmojiString; + final Runnable fullSearch = () -> { String[] newLanguage = AndroidUtilities.getCurrentKeyboardLanguage(); if (!Arrays.equals(lastSearchKeyboardLanguage, newLanguage)) { MediaDataController.getInstance(currentAccount).fetchNewEmojiKeywords(newLanguage); @@ -7122,18 +7569,92 @@ public void run() { public void run(ArrayList param, String alias) { if (query.equals(lastSearchEmojiString)) { lastSearchAlias = alias; - emojiSearchField.progressDrawable.stopAnimation(); + emojiSearchField.showProgress(false); searchWas = true; if (emojiGridView.getAdapter() != emojiSearchAdapter) { emojiGridView.setAdapter(emojiSearchAdapter); } - result = param; + result.clear(); + searchByPackname(query, documentIds); + for (long documentId : documentIds) { + MediaDataController.KeywordResult r = new MediaDataController.KeywordResult(); + r.keyword = ""; + r.emoji = "animated_" + documentId; + result.add(r); + } + for (int i = 0; i < param.size(); ++i) { + MediaDataController.KeywordResult r = param.get(i); + if (r != null && r.emoji != null && (!r.emoji.startsWith("animated_") || !documentIds.contains(Long.parseLong(r.emoji.substring(9))))) { + result.add(r); + } + } notifyDataSetChanged(); } } - }, true); + }, null, true, false, true, 25); + }; + if (Emoji.fullyConsistsOfEmojis(query)) { + StickerCategoriesListView.search.fetch(UserConfig.selectedAccount, query, list -> { + if (list != null) { + documentIds.addAll(list.document_id); + } + fullSearch.run(); + }); + } else { + fullSearch.run(); + } + }, delay ? 300 : 0); + } + } + + private ArrayList addedSets = new ArrayList<>(); + + private void searchByPackname(String query, LinkedHashSet documentIds) { + if (query == null || query.length() <= 3 || !UserConfig.getInstance(currentAccount).isPremium()) { + return; + } + String translitQuery = LocaleController.getInstance().getTranslitString(query).toLowerCase(); + + ArrayList sets = MediaDataController.getInstance(currentAccount).getStickerSets(MediaDataController.TYPE_EMOJIPACKS); + ArrayList featuredSets = MediaDataController.getInstance(currentAccount).getFeaturedEmojiSets(); + addedSets.clear(); + + for (int i = 0; i < sets.size(); ++i) { + TLRPC.TL_messages_stickerSet fullSet = sets.get(i); + if (fullSet == null || fullSet.set == null) { + continue; + } + checkAddPackToResults(fullSet.set, fullSet.documents, translitQuery, documentIds); + } + for (int i = 0; i < featuredSets.size(); ++i) { + TLRPC.StickerSetCovered coveredSet = featuredSets.get(i); + if (coveredSet == null || coveredSet.set == null) { + continue; + } + if (coveredSet instanceof TLRPC.TL_stickerSetFullCovered) { + checkAddPackToResults(coveredSet.set, ((TLRPC.TL_stickerSetFullCovered) coveredSet).documents, translitQuery, documentIds); + } else if (coveredSet instanceof TLRPC.TL_stickerSetNoCovered) { + TLRPC.TL_inputStickerSetID inputStickerSetID = new TLRPC.TL_inputStickerSetID(); + inputStickerSetID.id = coveredSet.set.id; + TLRPC.TL_messages_stickerSet fullSet = MediaDataController.getInstance(currentAccount).getStickerSet(inputStickerSetID, true); + if (fullSet != null) { + checkAddPackToResults(fullSet.set, fullSet.documents, translitQuery, documentIds); } - }, 300); + } else { + checkAddPackToResults(coveredSet.set, coveredSet.covers, translitQuery, documentIds); + } + } + } + + private void checkAddPackToResults(TLRPC.StickerSet set, ArrayList documents, String translitQuery, LinkedHashSet documentIds) { + if (set.title != null && !addedSets.contains(set.id) && LocaleController.getInstance().getTranslitString(set.title.toLowerCase()).contains(translitQuery)) { + for (TLRPC.Document document : documents) { + if (document == null) { + continue; + } + documentIds.add(document.id); + } + addedSets.add(set.id); } } } @@ -7146,8 +7667,12 @@ public void destroyItem(ViewGroup viewGroup, int position, Object object) { @Override public boolean canScrollToTab(int position) { - if ((position == 1 || position == 2) && currentChatId != 0) { - showStickerBanHint(position == 1); + if ((position == 1 || position == 2) && stickersBanned) { + showStickerBanHint(true, false, position == 1); + return false; + } + if (position == 0 && emojiBanned) { + showStickerBanHint(true, true, false); return false; } return true; @@ -7158,7 +7683,8 @@ public int getCount() { } public Drawable getPageIconDrawable(int position) { - return tabIcons[position]; + return null; +// return tabIcons[position]; } public CharSequence getPageTitle(int position) { @@ -7174,14 +7700,26 @@ public CharSequence getPageTitle(int position) { } @Override - public void customOnDraw(Canvas canvas, int position) { - if (position == 2 && !MediaDataController.getInstance(currentAccount).getUnreadStickerSets().isEmpty() && dotPaint != null) { - int x = canvas.getWidth() / 2 + AndroidUtilities.dp(4 + 5); - int y = canvas.getHeight() / 2 - AndroidUtilities.dp(13 - 5); - canvas.drawCircle(x, y, AndroidUtilities.dp(5), dotPaint); + public int getTabPadding(int position) { + switch (position) { + case 0: + return AndroidUtilities.dp(18); + case 1: + case 2: + default: + return AndroidUtilities.dp(12); } } + @Override + public void customOnDraw(Canvas canvas, View view, int position) { +// if (position == 2 && !MediaDataController.getInstance(currentAccount).getUnreadStickerSets().isEmpty() && dotPaint != null) { +// int x = canvas.getWidth() - view.getPaddingRight(); +// int y = canvas.getHeight() / 2 - AndroidUtilities.dp(13 - 5); +// canvas.drawCircle(x, y, AndroidUtilities.dp(5), dotPaint); +// } + } + public Object instantiateItem(ViewGroup viewGroup, int position) { View view = currentTabs.get(position).view; viewGroup.addView(view); @@ -7219,6 +7757,8 @@ private class GifAdapter extends RecyclerListView.SelectionAdapter { private int trendingSectionItem = -1; private int firstResultItem = -1; + private boolean addSearch; + private boolean showTrendingWhenSearchEmpty; public GifAdapter(Context context) { @@ -7248,7 +7788,7 @@ public int getItemCount() { @Override public int getItemViewType(int position) { - if (position == 0) { + if (position == 0 && addSearch) { return 1; // search field } else if (withRecent && position == trendingSectionItem) { return 2; // trending section @@ -7297,7 +7837,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (firstResultItem >= 0 && position >= firstResultItem) { cell.setLink(results.get(position - firstResultItem), bot, true, false, false, true); } else { - cell.setGif(recentGifs.get(position - 1), false); + cell.setGif(recentGifs.get(position - (addSearch ? 1 : 0)), false); } break; } @@ -7315,7 +7855,10 @@ private void updateItems() { trendingSectionItem = -1; firstResultItem = -1; - itemsCount = 1; // search field + itemsCount = 0; + if (addSearch) { + itemsCount++;// search field + } if (withRecent) { itemsCount += recentItemsCount; @@ -7402,6 +7945,10 @@ private void searchBotUser() { } public void search(String text) { + search(text, true); + } + + public void search(String text, boolean delay) { if (withRecent) { return; } @@ -7439,13 +7986,13 @@ public void search(String text) { if (!TextUtils.isEmpty(lastSearchImageString)) { AndroidUtilities.runOnUIThread(searchRunnable = () -> { search(text, "", true); - }, 300); + }, delay ? 300 : 0); } } public void searchEmoji(String emoji) { if (lastSearchIsEmoji && TextUtils.equals(lastSearchImageString, emoji)) { - gifLayoutManager.scrollToPositionWithOffset(1, 0); + gifLayoutManager.scrollToPositionWithOffset(0, 0); return; } search(emoji, "", true, true, true); @@ -7475,13 +8022,13 @@ protected void search(final String query, final String offset, boolean searchUse if (searchUser) { searchBotUser(); if (!withRecent) { - gifSearchField.progressDrawable.startAnimation(); + gifSearchField.showProgress(true); } } return; } if (!withRecent && TextUtils.isEmpty(offset)) { - gifSearchField.progressDrawable.startAnimation(); + gifSearchField.showProgress(true); } bot = (TLRPC.User) object; @@ -7516,7 +8063,7 @@ protected void search(final String query, final String offset, boolean searchUse req.bot = MessagesController.getInstance(currentAccount).getInputUser(bot); req.offset = offset; req.peer = new TLRPC.TL_inputPeerEmpty(); - reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, requestDelegate, ConnectionsManager.RequestFlagFailOnServerErrors); + reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, requestDelegate); } } @@ -7535,7 +8082,7 @@ private void processResponse(final String query, final String offset, boolean se if (TextUtils.isEmpty(offset)) { results.clear(); resultsMap.clear(); - gifSearchField.progressDrawable.stopAnimation(); + gifSearchField.showProgress(false); } } @@ -7566,16 +8113,16 @@ private void processResponse(final String query, final String offset, boolean se updateItems(); if (withRecent) { if (oldCount != 0) { - notifyItemChanged(recentItemsCount + 1 + oldCount); - notifyItemRangeInserted(recentItemsCount + 1 + oldCount + 1, addedCount); + notifyItemChanged(recentItemsCount + (gifAdapter.addSearch ? 1 : 0) + oldCount); + notifyItemRangeInserted(recentItemsCount + (gifAdapter.addSearch ? 1 : 0) + oldCount + 1, addedCount); } else { - notifyItemRangeInserted(recentItemsCount + 1, addedCount + 1); + notifyItemRangeInserted(recentItemsCount + (gifAdapter.addSearch ? 1 : 0), addedCount + 1); } } else { if (oldCount != 0) { notifyItemChanged(oldCount); } - notifyItemRangeInserted(oldCount + 1, addedCount); + notifyItemRangeInserted(oldCount + (gifAdapter.addSearch ? 1 : 0), addedCount); } } else { notifyDataSetChanged(); @@ -7662,10 +8209,10 @@ public GifLayoutManager(Context context) { setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { - if (position == 0 || gifGridView.getAdapter() == gifSearchAdapter && gifSearchAdapter.results.isEmpty()) { + if (position == 0 && gifAdapter.addSearch || gifGridView.getAdapter() == gifSearchAdapter && gifSearchAdapter.results.isEmpty()) { return getSpanCount(); } - return getSpanSizeForItem(position - 1); + return getSpanSizeForItem(position - (gifAdapter.addSearch ? 1 : 0)); } }); } @@ -7762,13 +8309,13 @@ public GifProgressEmptyView(@NonNull Context context) { imageView.setScaleType(ImageView.ScaleType.CENTER); imageView.setImageResource(R.drawable.gif_empty); imageView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_emojiPanelEmptyText), PorterDuff.Mode.MULTIPLY)); - addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, 59)); + addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 8, 0, 0)); textView = new TextView(getContext()); textView.setText(LocaleController.getString("NoGIFsFound", R.string.NoGIFsFound)); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); textView.setTextColor(getThemedColor(Theme.key_chat_emojiPanelEmptyText)); - addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, 9)); + addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 42, 0, 0)); progressView = new RadialProgressView(context, resourcesProvider); progressView.setVisibility(GONE); @@ -7828,34 +8375,43 @@ private class StickersSearchGridAdapter extends RecyclerListView.SelectionAdapte boolean cleared; private String searchQuery; private Runnable searchRunnable = new Runnable() { + String query; + int lastId; + + final ArrayList serverPacks = new ArrayList<>(); + final ArrayList localPacks = new ArrayList<>(); + final HashMap localPacksByShortName = new HashMap<>(); + final HashMap localPacksByName = new HashMap<>(); + final HashMap, String> emojiStickers = new HashMap<>(); + final ArrayList> emojiArrays = new ArrayList<>(); - private void clear() { - if (cleared) { + final ArrayList emojiStickersArray = new ArrayList<>(0); + final LongSparseArray emojiStickersMap = new LongSparseArray<>(0); + + private void searchFinish() { + if (emojiSearchId != lastId) { return; } - cleared = true; - emojiStickers.clear(); - emojiArrays.clear(); - localPacks.clear(); - serverPacks.clear(); - localPacksByShortName.clear(); - localPacksByName.clear(); - } - @Override - public void run() { - if (TextUtils.isEmpty(searchQuery)) { - return; + StickersSearchGridAdapter.this.localPacks = localPacks; + StickersSearchGridAdapter.this.serverPacks = serverPacks; + StickersSearchGridAdapter.this.localPacksByShortName = localPacksByShortName; + StickersSearchGridAdapter.this.localPacksByName = localPacksByName; + StickersSearchGridAdapter.this.emojiStickers = emojiStickers; + StickersSearchGridAdapter.this.emojiArrays = emojiArrays; + stickersSearchField.showProgress(false); + + if (stickersGridView.getAdapter() != stickersSearchGridAdapter) { + stickersGridView.setAdapter(stickersSearchGridAdapter); } - stickersSearchField.progressDrawable.startAnimation(); - cleared = false; - int lastId = ++emojiSearchId; + notifyDataSetChanged(); + } + + private void addFromAllStickers(Runnable finished) { + final HashMap> allStickers = MediaDataController.getInstance(currentAccount).getAllStickers(); - final ArrayList emojiStickersArray = new ArrayList<>(0); - final LongSparseArray emojiStickersMap = new LongSparseArray<>(0); - HashMap> allStickers = MediaDataController.getInstance(currentAccount).getAllStickers(); - if (searchQuery.length() <= 14) { - CharSequence emoji = searchQuery; + if (query.length() <= 14) { + CharSequence emoji = query; int length = emoji.length(); for (int a = 0; a < length; a++) { if (a < length - 1 && (emoji.charAt(a) == 0xD83C && emoji.charAt(a + 1) >= 0xDFFB && emoji.charAt(a + 1) <= 0xDFFF || emoji.charAt(a) == 0x200D && (emoji.charAt(a + 1) == 0x2640 || emoji.charAt(a + 1) == 0x2642))) { @@ -7870,7 +8426,6 @@ public void run() { } ArrayList newStickers = allStickers != null ? allStickers.get(emoji.toString()) : null; if (newStickers != null && !newStickers.isEmpty()) { - clear(); emojiStickersArray.addAll(newStickers); for (int a = 0, size = newStickers.size(); a < size; a++) { TLRPC.Document document = newStickers.get(a); @@ -7880,37 +8435,41 @@ public void run() { emojiArrays.add(emojiStickersArray); } } - if (allStickers != null && !allStickers.isEmpty() && searchQuery.length() > 1) { + finished.run(); + } + + private void addFromSuggestions(Runnable finished) { + final HashMap> allStickers = MediaDataController.getInstance(currentAccount).getAllStickers(); + + if (allStickers != null && !allStickers.isEmpty() && query.length() > 1) { String[] newLanguage = AndroidUtilities.getCurrentKeyboardLanguage(); if (!Arrays.equals(lastSearchKeyboardLanguage, newLanguage)) { MediaDataController.getInstance(currentAccount).fetchNewEmojiKeywords(newLanguage); } lastSearchKeyboardLanguage = newLanguage; - MediaDataController.getInstance(currentAccount).getEmojiSuggestions(lastSearchKeyboardLanguage, searchQuery, false, new MediaDataController.KeywordResultCallback() { - @Override - public void run(ArrayList param, String alias) { - if (lastId != emojiSearchId) { - return; - } - boolean added = false; - for (int a = 0, size = param.size(); a < size; a++) { - String emoji = param.get(a).emoji; - ArrayList newStickers = allStickers != null ? allStickers.get(emoji) : null; - if (newStickers != null && !newStickers.isEmpty()) { - clear(); - if (!emojiStickers.containsKey(newStickers)) { - emojiStickers.put(newStickers, emoji); - emojiArrays.add(newStickers); - added = true; - } + MediaDataController.getInstance(currentAccount).getEmojiSuggestions(lastSearchKeyboardLanguage, searchQuery, false, (param, alias) -> { + if (emojiSearchId != lastId) { + return; + } + + for (int a = 0, size = param.size(); a < size; a++) { + String emoji = param.get(a).emoji; + ArrayList newStickers = allStickers.get(emoji); + if (newStickers != null && !newStickers.isEmpty()) { + if (!emojiStickers.containsKey(newStickers)) { + emojiStickers.put(newStickers, emoji); + emojiArrays.add(newStickers); } } - if (added) { - notifyDataSetChanged(); - } } + finished.run(); }, false); + } else { + finished.run(); } + } + + private void addLocalPacks(Runnable finished) { ArrayList local = MediaDataController.getInstance(currentAccount).getStickerSets(MediaDataController.TYPE_IMAGE); MessagesController.getInstance(currentAccount).filterPremiumStickers(local); int index; @@ -7918,13 +8477,11 @@ public void run(ArrayList param, String alias TLRPC.TL_messages_stickerSet set = local.get(a); if ((index = AndroidUtilities.indexOfIgnoreCase(set.set.title, searchQuery)) >= 0) { if (index == 0 || set.set.title.charAt(index - 1) == ' ') { - clear(); localPacks.add(set); localPacksByName.put(set, index); } } else if (set.set.short_name != null && (index = AndroidUtilities.indexOfIgnoreCase(set.set.short_name, searchQuery)) >= 0) { if (index == 0 || set.set.short_name.charAt(index - 1) == ' ') { - clear(); localPacks.add(set); localPacksByShortName.put(set, true); } @@ -7936,48 +8493,50 @@ public void run(ArrayList param, String alias TLRPC.TL_messages_stickerSet set = local.get(a); if ((index = AndroidUtilities.indexOfIgnoreCase(set.set.title, searchQuery)) >= 0) { if (index == 0 || set.set.title.charAt(index - 1) == ' ') { - clear(); localPacks.add(set); localPacksByName.put(set, index); } } else if (set.set.short_name != null && (index = AndroidUtilities.indexOfIgnoreCase(set.set.short_name, searchQuery)) >= 0) { if (index == 0 || set.set.short_name.charAt(index - 1) == ' ') { - clear(); localPacks.add(set); localPacksByShortName.put(set, true); } } } - if ((!localPacks.isEmpty() || !emojiStickers.isEmpty()) && stickersGridView.getAdapter() != stickersSearchGridAdapter) { - stickersGridView.setAdapter(stickersSearchGridAdapter); - } + finished.run(); + } + + private void searchStickerSets(Runnable finished) { final TLRPC.TL_messages_searchStickerSets req = new TLRPC.TL_messages_searchStickerSets(); - req.q = searchQuery; - reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + req.q = query; + reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (emojiSearchId != lastId) { + return; + } + if (response instanceof TLRPC.TL_messages_foundStickerSets) { - AndroidUtilities.runOnUIThread(() -> { - if (req.q.equals(searchQuery)) { - clear(); - stickersSearchField.progressDrawable.stopAnimation(); - reqId = 0; - if (stickersGridView.getAdapter() != stickersSearchGridAdapter) { - stickersGridView.setAdapter(stickersSearchGridAdapter); - } - TLRPC.TL_messages_foundStickerSets res = (TLRPC.TL_messages_foundStickerSets) response; - serverPacks.addAll(res.sets); - notifyDataSetChanged(); - } - }); + reqId = 0; + TLRPC.TL_messages_foundStickerSets res = (TLRPC.TL_messages_foundStickerSets) response; + serverPacks.addAll(res.sets); } - }); - if (Emoji.isValidEmoji(searchQuery)) { + finished.run(); + })); + } + + private void searchStickers(Runnable finished) { + if (Emoji.fullyConsistsOfEmojis(searchQuery)) { final TLRPC.TL_messages_getStickers req2 = new TLRPC.TL_messages_getStickers(); - req2.emoticon = searchQuery; + req2.emoticon = query; req2.hash = 0; reqId2 = ConnectionsManager.getInstance(currentAccount).sendRequest(req2, (response, error) -> AndroidUtilities.runOnUIThread(() -> { - if (req2.emoticon.equals(searchQuery)) { - reqId2 = 0; + if (emojiSearchId != lastId) { + return; + } + + reqId2 = 0; + if (req2.emoticon.equals(query)) { if (!(response instanceof TLRPC.TL_messages_stickers)) { + finished.run(); return; } TLRPC.TL_messages_stickers res = (TLRPC.TL_messages_stickers) response; @@ -7995,12 +8554,48 @@ public void run(ArrayList param, String alias if (oldCount == 0) { emojiArrays.add(emojiStickersArray); } - notifyDataSetChanged(); } } + finished.run(); })); + } else { + finished.run(); } - notifyDataSetChanged(); + } + + @Override + public void run() { + if (TextUtils.isEmpty(searchQuery)) { + if (stickersGridView.getAdapter() != stickersGridAdapter) { + stickersGridView.setAdapter(stickersGridAdapter); + } + notifyDataSetChanged(); + return; + } + lastId = ++emojiSearchId; + query = searchQuery; + + serverPacks.clear(); + localPacks.clear(); + localPacksByShortName.clear(); + localPacksByName.clear(); + emojiStickers.clear(); + emojiArrays.clear(); + + emojiStickersArray.clear(); + emojiStickersMap.clear(); + + stickersSearchField.showProgress(true); + + Utilities.raceCallbacks( + this::searchFinish, + + this::addFromAllStickers, + this::addFromSuggestions, + this::addLocalPacks, + this::searchStickerSets, + this::searchStickers + ); } }; @@ -8027,6 +8622,10 @@ public Object getItem(int i) { } public void search(String text) { + search(text, true); + } + + public void search(String text, boolean delay) { if (reqId != 0) { ConnectionsManager.getInstance(currentAccount).cancelRequest(reqId, true); reqId = 0; @@ -8044,8 +8643,10 @@ public void search(String text) { stickersGridView.setAdapter(stickersGridAdapter); } notifyDataSetChanged(); + stickersSearchField.showProgress(false); } else { searchQuery = text.toLowerCase(); + stickersSearchField.showProgress(true); } AndroidUtilities.cancelRunOnUIThread(searchRunnable); AndroidUtilities.runOnUIThread(searchRunnable, 300); @@ -8123,13 +8724,14 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { imageView.setScaleType(ImageView.ScaleType.CENTER); imageView.setImageResource(R.drawable.stickers_empty); imageView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_chat_emojiPanelEmptyText), PorterDuff.Mode.MULTIPLY)); - frameLayout.addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, 59)); + imageView.setTranslationY(-AndroidUtilities.dp(24)); + frameLayout.addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 42, 0, 28)); TextView textView = new TextView(context); textView.setText(LocaleController.getString("NoStickersFound", R.string.NoStickersFound)); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); textView.setTextColor(getThemedColor(Theme.key_chat_emojiPanelEmptyText)); - frameLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, 9)); + frameLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 42, 0, 9)); view = frameLayout; view.setLayoutParams(new RecyclerView.LayoutParams(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ForwardingPreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ForwardingPreviewView.java index c94c0c9c4f2..5bd4e387e9a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ForwardingPreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ForwardingPreviewView.java @@ -166,7 +166,7 @@ public boolean drawChild(Canvas canvas, View child, long drawingTime) { cell.drawCheckBox(canvas); canvas.save(); canvas.translate(cell.getX(), cell.getY()); - cell.drawMessageText(canvas, cell.getMessageObject().textLayoutBlocks, true, 1f, false); + cell.drawMessageText(canvas, cell.getMessageObject().textLayoutBlocks, cell.getMessageObject().textXOffset, true, 1f, false); if (cell.getCurrentMessagesGroup() != null || cell.getTransitionParams().animateBackgroundBoundsInner) { cell.drawNamesLayout(canvas, 1f); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java index 0c795fa1903..116f276e843 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java @@ -1960,7 +1960,9 @@ public void onAnimationEnd(Animator animation) { } else { timeLayout = null; joinButton.setVisibility(VISIBLE); - if (call.call.rtmp_stream) { + if (!TextUtils.isEmpty(call.call.title)) { + titleTextView.setText(call.call.title, false); + } else if (call.call.rtmp_stream) { titleTextView.setText(LocaleController.getString(R.string.VoipChannelVoiceChat), false); } else if (ChatObject.isChannelOrGiga(chat)) { titleTextView.setText(LocaleController.getString("VoipChannelVoiceChat", R.string.VoipChannelVoiceChat), false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/GestureDetector2.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/GestureDetector2.java index 13690d4bab7..52bba9adb77 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/GestureDetector2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/GestureDetector2.java @@ -285,7 +285,7 @@ public boolean onTouchEvent(MotionEvent ev) { if (mIsLongpressEnabled) { mHandler.removeMessages(LONG_PRESS); - mHandler.sendMessageAtTime(mHandler.obtainMessage(LONG_PRESS, 0, 0), mCurrentDownEvent.getDownTime() + ViewConfiguration.getLongPressTimeout()); + mHandler.sendMessageDelayed(mHandler.obtainMessage(LONG_PRESS, 0, 0), ViewConfiguration.getLongPressTimeout()); } mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT); handled |= mListener.onDown(ev); @@ -316,7 +316,7 @@ public boolean onTouchEvent(MotionEvent ev) { if (distance > slopSquare) { mHandler.removeMessages(LONG_PRESS); final long longPressTimeout = ViewConfiguration.getLongPressTimeout(); - mHandler.sendMessageAtTime(mHandler.obtainMessage(LONG_PRESS, 0, 0), ev.getDownTime() + (long) (longPressTimeout * multiplier)); + mHandler.sendMessageDelayed(mHandler.obtainMessage(LONG_PRESS, 0, 0), (long) (longPressTimeout * multiplier)); } slopSquare *= multiplier * multiplier; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/GradientTools.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/GradientTools.java new file mode 100644 index 00000000000..e3ed8cbfdc3 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/GradientTools.java @@ -0,0 +1,106 @@ +package org.telegram.ui.Components; + +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.LinearGradient; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.RectF; +import android.graphics.Shader; + +import androidx.core.graphics.ColorUtils; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Utilities; + +public class GradientTools { + + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + int color1; + int color2; + int color3; + int color4; + + private final static int INTERNAL_WIDTH = 60; + private final static int INTERNAL_HEIGHT = 80; + + RectF bounds = new RectF(); + Shader shader; + Matrix matrix = new Matrix(); + + Bitmap gradientBitmap = null; + + int[] colors = new int[4]; + + public void setColors(int color1, int color2) { + setColors(color1, color2, 0, 0); + } + + public void setColors(int color1, int color2, int color3) { + setColors(color1, color2, color3, 0); + } + + public void setColors(int color1, int color2, int color3, int color4) { + if (shader != null && this.color1 == color1 && this.color2 == color2 && this.color3 == color3 && this.color4 == color4) { + return; + } + colors[0] = this.color1 = color1; + colors[1] = this.color2 = color2; + colors[2] = this.color3 = color3; + colors[3] = this.color4 = color4; + if (color2 == 0) { + paint.setShader(shader = null); + paint.setColor(color1); + } else if (color3 == 0) { + paint.setShader(shader = new LinearGradient(0, 0, 0, INTERNAL_HEIGHT, new int[]{color1, color2}, null, Shader.TileMode.CLAMP)); + } else { + if (gradientBitmap == null) { + gradientBitmap = Bitmap.createBitmap(INTERNAL_WIDTH, INTERNAL_HEIGHT, Bitmap.Config.ARGB_8888); + } + Utilities.generateGradient(gradientBitmap, true, 0, 0, gradientBitmap.getWidth(), gradientBitmap.getHeight(), gradientBitmap.getRowBytes(), colors); + paint.setShader(shader = new BitmapShader(gradientBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); + } + updateBounds(); + } + + public void setBounds(RectF bounds) { + if (this.bounds.top == bounds.top && this.bounds.bottom == bounds.bottom && this.bounds.left == bounds.left && this.bounds.right == bounds.right) { + return; + } + this.bounds.set(bounds); + updateBounds(); + } + + private void updateBounds() { + if (shader == null) { + return; + } + float sx = bounds.width() / (float) INTERNAL_WIDTH; + float sy = bounds.height() / (float) INTERNAL_HEIGHT; + + matrix.reset(); + matrix.postTranslate(bounds.left, bounds.top); + matrix.preScale(sx, sy); + + shader.setLocalMatrix(matrix); + } + + public void setBounds(float left, float top, float right, float bottom) { + AndroidUtilities.rectTmp.set(left, top, right, bottom); + setBounds(AndroidUtilities.rectTmp); + } + + public int getAverageColor() { + int color = color1; + if (color2 != 0) { + color = ColorUtils.blendARGB(color, color2, 0.5f); + } + if (color3 != 0) { + color = ColorUtils.blendARGB(color, color3, 0.5f); + } + if (color4 != 0) { + color = ColorUtils.blendARGB(color, color4, 0.5f); + } + return color; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ImageUpdater.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ImageUpdater.java index 211bb858e34..d0f1876174d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ImageUpdater.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ImageUpdater.java @@ -37,6 +37,7 @@ import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SendMessagesHelper; @@ -68,6 +69,10 @@ public class ImageUpdater implements NotificationCenter.NotificationCenterDelega ID_REMOVE_PHOTO = 3, ID_RECORD_VIDEO = 4; + public final static int FOR_TYPE_USER = 0; + public final static int FOR_TYPE_CHANNEL = 1; + public final static int FOR_TYPE_GROUP = 2; + public BaseFragment parentFragment; private ImageUpdaterDelegate delegate; private ChatAttachAlert chatAttachAlert; @@ -87,19 +92,23 @@ public class ImageUpdater implements NotificationCenter.NotificationCenterDelega private boolean clearAfterUpdate; private boolean useAttachMenu = true; private boolean openWithFrontfaceCamera; + private boolean supportEmojiMarkup; private boolean searchAvailable = true; private boolean uploadAfterSelect = true; private TLRPC.User user; + private boolean isUser; private TLRPC.InputFile uploadedPhoto; private TLRPC.InputFile uploadedVideo; + private TLRPC.VideoSize vectorMarkup; private double videoTimestamp; private boolean canSelectVideo; private boolean forceDarkTheme; private boolean showingFromDialog; private boolean canceled; + private boolean forUser; private final static int attach_photo = 0; @@ -108,6 +117,7 @@ public class ImageUpdater implements NotificationCenter.NotificationCenterDelega public final static int TYPE_SUGGEST_PHOTO_FOR_USER = 2; private int type; + public final int setForType; public void processEntry(MediaController.PhotoEntry photoEntry) { String path = null; @@ -128,6 +138,7 @@ public void processEntry(MediaController.PhotoEntry photoEntry) { avatarObject = new MessageObject(UserConfig.selectedAccount, message, false, false); avatarObject.messageOwner.attachPath = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), SharedConfig.getLastLocalId() + "_avatar.mp4").getAbsolutePath(); avatarObject.videoEditedInfo = photoEntry.editedInfo; + avatarObject.emojiMarkup = photoEntry.emojiMarkup; bitmap = ImageLoader.loadBitmap(photoEntry.thumbPath, null, 800, 800, true); } else { bitmap = ImageLoader.loadBitmap(path, null, 800, 800, true); @@ -153,7 +164,7 @@ public boolean isCanceled() { } public interface ImageUpdaterDelegate { - void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double videoStartTimestamp, String videoPath, TLRPC.PhotoSize bigSize, TLRPC.PhotoSize smallSize, boolean isVideo); + void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double videoStartTimestamp, String videoPath, TLRPC.PhotoSize bigSize, TLRPC.PhotoSize smallSize, boolean isVideo, TLRPC.VideoSize emojiMarkup); default String getInitialSearchString() { return null; @@ -198,9 +209,11 @@ public void setOpenWithFrontfaceCamera(boolean value) { openWithFrontfaceCamera = value; } - public ImageUpdater(boolean allowVideo) { + public ImageUpdater(boolean allowVideo, int setForType, boolean supportEmojiMarkup) { imageReceiver = new ImageReceiver(null); canSelectVideo = allowVideo; + this.supportEmojiMarkup = supportEmojiMarkup; + this.setForType = setForType; } public void setCanSelectVideo(boolean canSelectVideo) { @@ -417,6 +430,7 @@ private void openAttachMenu(DialogInterface.OnDismissListener onDismissListener) if (type != 0) { chatAttachAlert.avatarFor(new AvatarFor(user, type)); } + chatAttachAlert.forUser = forUser; parentFragment.showDialog(chatAttachAlert); } @@ -457,6 +471,7 @@ public void didPressedButton(int button, boolean arg, boolean notify, int schedu info.entities = photoEntry.entities; info.masks = photoEntry.stickers; info.ttl = photoEntry.ttl; + info.emojiMarkup = photoEntry.emojiMarkup; } else if (object instanceof MediaController.SearchImage) { MediaController.SearchImage searchImage = (MediaController.SearchImage) object; if (searchImage.imagePath != null) { @@ -526,6 +541,7 @@ public void openAvatarsSearch() { openSearch(); } }); + chatAttachAlert.setImageUpdater(this); } if (type == TYPE_SET_PHOTO_FOR_USER) { chatAttachAlert.getSelectedTextView().setText(LocaleController.formatString("SetPhotoFor", R.string.SetPhotoFor, user.first_name)); @@ -549,6 +565,7 @@ private void didSelectPhotos(ArrayList phot avatarObject = new MessageObject(UserConfig.selectedAccount, message, false, false); avatarObject.messageOwner.attachPath = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), SharedConfig.getLastLocalId() + "_avatar.mp4").getAbsolutePath(); avatarObject.videoEditedInfo = info.videoEditedInfo; + avatarObject.emojiMarkup = info.emojiMarkup; bitmap = ImageLoader.loadBitmap(info.thumbPath, null, 800, 800, true); } else if (info.path != null) { bitmap = ImageLoader.loadBitmap(info.path, null, 800, 800, true); @@ -795,6 +812,7 @@ private void processBitmap(Bitmap bitmap, MessageObject avatarObject) { uploadedPhoto = null; convertingVideo = null; videoPath = null; + vectorMarkup = avatarObject == null ? null : avatarObject.emojiMarkup; bigPhoto = ImageLoader.scaleAndSaveImage(bitmap, 800, 800, 80, false, 320, 320); smallPhoto = ImageLoader.scaleAndSaveImage(bitmap, 150, 150, 80, false, 150, 150); if (smallPhoto != null) { @@ -812,6 +830,18 @@ private void processBitmap(Bitmap bitmap, MessageObject avatarObject) { uploadingImage = FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + bigPhoto.location.volume_id + "_" + bigPhoto.location.local_id + ".jpg"; if (uploadAfterSelect) { if (avatarObject != null && avatarObject.videoEditedInfo != null) { + if (supportEmojiMarkup && !MessagesController.getInstance(currentAccount).uploadMarkupVideo) { + if (delegate != null) { + delegate.didStartUpload(true); + } + if (delegate != null) { + //skip upload step + delegate.didUploadPhoto(null, null, 0, null, bigPhoto, smallPhoto, isVideo, null); + delegate.didUploadPhoto(null, null, videoTimestamp, videoPath, bigPhoto, smallPhoto, isVideo, vectorMarkup); + cleanup(); + } + return; + } convertingVideo = avatarObject; long startTime = avatarObject.videoEditedInfo.startTime < 0 ? 0 : avatarObject.videoEditedInfo.startTime; videoTimestamp = (avatarObject.videoEditedInfo.avatarStartTime - startTime) / 1000000.0; @@ -839,7 +869,7 @@ private void processBitmap(Bitmap bitmap, MessageObject avatarObject) { } } if (delegate != null) { - delegate.didUploadPhoto(null, null, 0, null, bigPhoto, smallPhoto, isVideo); + delegate.didUploadPhoto(null, null, 0, null, bigPhoto, smallPhoto, isVideo, null); } } } @@ -887,7 +917,7 @@ public void didReceivedNotification(int id, int account, Object... args) { NotificationCenter.getInstance(currentAccount).removeObserver(ImageUpdater.this, NotificationCenter.fileUploadFailed); if (id == NotificationCenter.fileUploaded) { if (delegate != null) { - delegate.didUploadPhoto(uploadedPhoto, uploadedVideo, videoTimestamp, videoPath, bigPhoto, smallPhoto, isVideo); + delegate.didUploadPhoto(uploadedPhoto, uploadedVideo, videoTimestamp, videoPath, bigPhoto, smallPhoto, isVideo, vectorMarkup); } } cleanup(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java index de688ad1740..66597f49f03 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java @@ -582,14 +582,14 @@ public boolean onTouchEvent(MotionEvent event) { } else if (pressedLink.getSpan() != null) { pressedLink.getSpan().onClick(this); } + pressedLink = null; + return true; } pressedLink = null; - return true; } if (event.getAction() == MotionEvent.ACTION_CANCEL) { links.clear(); pressedLink = null; - return true; } } return pressedLink != null || super.onTouchEvent(event); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/LoadingDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/LoadingDrawable.java index fcf811331bb..0b72cd7e45d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/LoadingDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/LoadingDrawable.java @@ -256,7 +256,6 @@ public void draw(@NonNull Canvas canvas) { rectF.inset(-strokePaint.getStrokeWidth(), -strokePaint.getStrokeWidth()); canvas.saveLayerAlpha(rectF, 255, Canvas.ALL_SAVE_FLAG); } - } if (appearByGradient) { int appearGradientWidthNow = Math.max(AndroidUtilities.dp(200), bounds.width() / 3); @@ -327,7 +326,9 @@ public void draw(@NonNull Canvas canvas) { canvas.restore(); } - invalidateSelf(); + if (!isDisappeared()) { + invalidateSelf(); + } } public void updateBounds() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MotionBackgroundDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MotionBackgroundDrawable.java index f2bbb287f63..b12cd469451 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MotionBackgroundDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MotionBackgroundDrawable.java @@ -53,6 +53,7 @@ public class MotionBackgroundDrawable extends Drawable { private long lastUpdateTime; private WeakReference parentView; + private boolean ignoreInterpolator; private final CubicBezierInterpolator interpolator = new CubicBezierInterpolator(0.33, 0.0, 0.0, 1.0); private int translationY; @@ -268,7 +269,7 @@ public void switchToNextPosition(boolean fast) { generateNextGradient(); } - private void generateNextGradient() { + public void generateNextGradient() { if (useLegacyBitmap && intensity < 0) { try { if (legacyBitmap != null) { @@ -294,9 +295,9 @@ private void generateNextGradient() { Utilities.generateGradient(currentBitmap, true, phase, 1f, currentBitmap.getWidth(), currentBitmap.getHeight(), currentBitmap.getRowBytes(), colors); invalidateLegacy = true; } - for (int i = 0; i < ANIMATION_CACHE_BITMAPS_COUNT; i++) { + for (int i = -1; i < ANIMATION_CACHE_BITMAPS_COUNT; i++) { float p = (i + 1) / (float) ANIMATION_CACHE_BITMAPS_COUNT; - Utilities.generateGradient(gradientToBitmap[i], true, phase, p, currentBitmap.getWidth(), currentBitmap.getHeight(), currentBitmap.getRowBytes(), colors); + Utilities.generateGradient(i < 0 ? gradientFromBitmap : gradientToBitmap[i], true, phase, p, currentBitmap.getWidth(), currentBitmap.getHeight(), currentBitmap.getRowBytes(), colors); } } @@ -892,11 +893,14 @@ public void updateAnimation(boolean invalidate) { if (posAnimationProgress > 1.0f) { posAnimationProgress = 1.0f; } - if (animationProgressProvider == null) { + if (animationProgressProvider == null && !ignoreInterpolator) { progress = interpolator.getInterpolation(posAnimationProgress); } else { progress = posAnimationProgress; } + if (ignoreInterpolator && (progress == 0 || progress == 1)) { + ignoreInterpolator = false; + } if (stageBefore == 0 && progress > 0.25f || stageBefore == 1 && progress > 0.5f || stageBefore == 2 && progress > 0.75f) { @@ -941,11 +945,14 @@ public void updateAnimation(boolean invalidate) { if (posAnimationProgress > 1.0f) { posAnimationProgress = 1.0f; } - if (animationProgressProvider == null) { + if (animationProgressProvider == null && !ignoreInterpolator) { progress = interpolator.getInterpolation(posAnimationProgress); } else { progress = posAnimationProgress; } + if (ignoreInterpolator && (progress == 0 || progress == 1)) { + ignoreInterpolator = false; + } if (rotationBack) { progress = 1.0f - progress; if (posAnimationProgress >= 1.0f) { @@ -1022,6 +1029,12 @@ public boolean isIndeterminateAnimation() { } public void setIndeterminateAnimation(boolean isIndeterminateAnimation) { + if (!isIndeterminateAnimation && this.isIndeterminateAnimation) { + float progressPerPhase = 1f / 8f; + int phase = (int) (posAnimationProgress / progressPerPhase); + posAnimationProgress = 1f - (posAnimationProgress - phase * progressPerPhase) / progressPerPhase; + ignoreInterpolator = true; + } this.isIndeterminateAnimation = isIndeterminateAnimation; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/OverlayActionBarLayoutDialog.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/OverlayActionBarLayoutDialog.java index 7b09d5c4f03..cd624464812 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/OverlayActionBarLayoutDialog.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/OverlayActionBarLayoutDialog.java @@ -2,6 +2,7 @@ import android.app.Dialog; import android.content.Context; +import android.content.ContextWrapper; import android.graphics.Color; import android.os.Build; import android.os.Bundle; @@ -20,6 +21,7 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.INavigationLayout; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.LaunchActivity; import java.util.ArrayList; @@ -27,6 +29,7 @@ public class OverlayActionBarLayoutDialog extends Dialog implements INavigationL private Theme.ResourcesProvider resourcesProvider; private INavigationLayout actionBarLayout; private FrameLayout frameLayout; + private PasscodeView passcodeView; public OverlayActionBarLayoutDialog(@NonNull Context context, Theme.ResourcesProvider resourcesProvider) { super(context, R.style.TransparentDialog); @@ -46,9 +49,38 @@ public OverlayActionBarLayoutDialog(@NonNull Context context, Theme.ResourcesPro actionBarLayout.setRemoveActionBarExtraHeight(true); VerticalPositionAutoAnimator.attach(actionBarLayout.getView()); } + passcodeView = new PasscodeView(context); + frameLayout.addView(passcodeView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + setContentView(frameLayout); } + @Override + protected void onStart() { + super.onStart(); + + Context context = getContext(); + if (context instanceof ContextWrapper && !(context instanceof LaunchActivity)) { + context = ((ContextWrapper) context).getBaseContext(); + } + if (context instanceof LaunchActivity) { + ((LaunchActivity) context).addOverlayPasscodeView(passcodeView); + } + } + + @Override + protected void onStop() { + super.onStop(); + + Context context = getContext(); + if (context instanceof ContextWrapper && !(context instanceof LaunchActivity)) { + context = ((ContextWrapper) context).getBaseContext(); + } + if (context instanceof LaunchActivity) { + ((LaunchActivity) context).removeOverlayPasscodeView(passcodeView); + } + } + @Override public void onMeasureOverride(int[] measureSpec) { if (AndroidUtilities.isTablet() && !AndroidUtilities.isInMultiwindow && !AndroidUtilities.isSmallTablet()) { @@ -105,6 +137,13 @@ public void addFragment(BaseFragment fragment) { @Override public void onBackPressed() { + if (passcodeView.getVisibility() == View.VISIBLE) { + if (getOwnerActivity() != null) { + getOwnerActivity().finish(); + } + return; + } + actionBarLayout.onBackPressed(); if (actionBarLayout.getFragmentStack().size() <= 1) { dismiss(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PagerSlidingTabStrip.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PagerSlidingTabStrip.java index e1d7ed532ec..8aa3f7e45f6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PagerSlidingTabStrip.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PagerSlidingTabStrip.java @@ -16,6 +16,8 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.RippleDrawable; import android.os.Build; +import android.util.TypedValue; +import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver.OnGlobalLayoutListener; @@ -23,6 +25,7 @@ import android.widget.HorizontalScrollView; import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.TextView; import androidx.viewpager.widget.ViewPager; import androidx.viewpager.widget.ViewPager.OnPageChangeListener; @@ -34,8 +37,9 @@ public class PagerSlidingTabStrip extends HorizontalScrollView { public interface IconTabProvider { Drawable getPageIconDrawable(int position); - void customOnDraw(Canvas canvas, int position); + void customOnDraw(Canvas canvas, View view, int position); boolean canScrollToTab(int position); + int getTabPadding(int position); } private LinearLayout.LayoutParams defaultTabLayoutParams; @@ -104,7 +108,14 @@ public void notifyDataSetChanged() { tabCount = pager.getAdapter().getCount(); for (int i = 0; i < tabCount; i++) { if (pager.getAdapter() instanceof IconTabProvider) { - addIconTab(i, ((IconTabProvider) pager.getAdapter()).getPageIconDrawable(i), pager.getAdapter().getPageTitle(i)); + Drawable drawable = ((IconTabProvider) pager.getAdapter()).getPageIconDrawable(i); + if (drawable != null) { + addIconTab(i, drawable, pager.getAdapter().getPageTitle(i)); + } else { + addTab(i, pager.getAdapter().getPageTitle(i)); + } + } else { + addTab(i, pager.getAdapter().getPageTitle(i)); } } updateTabStyles(); @@ -131,7 +142,7 @@ private void addIconTab(final int position, Drawable drawable, CharSequence cont protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (pager.getAdapter() instanceof IconTabProvider) { - ((IconTabProvider) pager.getAdapter()).customOnDraw(canvas, position); + ((IconTabProvider) pager.getAdapter()).customOnDraw(canvas, this, position); } } @@ -166,6 +177,58 @@ public void setSelected(boolean selected) { tab.setContentDescription(contentDescription); } + private void addTab(final int position, CharSequence text) { + TextView tab = new TextView(getContext()) { + + @Override + public void setAlpha(float alpha) { + super.setAlpha(alpha); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (pager.getAdapter() instanceof IconTabProvider) { + ((IconTabProvider) pager.getAdapter()).customOnDraw(canvas, this, position); + } + } + + @Override + public void setSelected(boolean selected) { + super.setSelected(selected); + Drawable background = getBackground(); + if (Build.VERSION.SDK_INT >= 21 && background != null) { + int color = getThemedColor(selected ? Theme.key_chat_emojiPanelIconSelected : Theme.key_chat_emojiBottomPanelIcon); + Theme.setSelectorDrawableColor(background, Color.argb(30, Color.red(color), Color.green(color), Color.blue(color)), true); + } + setTextColor(getThemedColor(selected ? Theme.key_chat_emojiPanelIconSelected : Theme.key_chat_emojiPanelBackspace)); + } + }; + tab.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + tab.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + tab.setTextColor(getThemedColor(Theme.key_chat_emojiPanelBackspace)); + tab.setFocusable(true); + tab.setGravity(Gravity.CENTER); + if (Build.VERSION.SDK_INT >= 21) { + RippleDrawable rippleDrawable = (RippleDrawable) Theme.createSelectorDrawable(getThemedColor(Theme.key_chat_emojiBottomPanelIcon), Theme.RIPPLE_MASK_CIRCLE_TO_BOUND_EDGE); + Theme.setRippleDrawableForceSoftware(rippleDrawable); + tab.setBackground(rippleDrawable); + } + tab.setText(text); + tab.setOnClickListener(v -> { + if (pager.getAdapter() instanceof IconTabProvider) { + if (!((IconTabProvider) pager.getAdapter()).canScrollToTab(position)) { + return; + } + } + pager.setCurrentItem(position, false); + }); + tab.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0); + tabsContainer.addView(tab, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 10, 0, 10, 0)); + tab.setSelected(position == currentPosition); + } + + private void updateTabStyles() { for (int i = 0; i < tabCount; i++) { View v = tabsContainer.getChildAt(i); @@ -173,6 +236,9 @@ private void updateTabStyles() { if (shouldExpand) { v.setPadding(0, 0, 0, 0); v.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1.0F)); + } else if (pager.getAdapter() instanceof IconTabProvider) { + int padding = ((IconTabProvider) pager.getAdapter()).getTabPadding(i); + v.setPadding(padding, 0, padding, 0); } else { v.setPadding(tabPadding, 0, tabPadding, 0); } @@ -207,6 +273,9 @@ private void scrollToChild(int position, int offset) { } } + private AnimatedFloat lineLeftAnimated = new AnimatedFloat(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private AnimatedFloat lineRightAnimated = new AnimatedFloat(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); @@ -219,26 +288,34 @@ protected void onDraw(Canvas canvas) { if (underlineHeight != 0) { rectPaint.setColor(underlineColor); - canvas.drawRect(0, height - underlineHeight, tabsContainer.getWidth(), height, rectPaint); + AndroidUtilities.rectTmp.set(0, height - underlineHeight, tabsContainer.getWidth(), height); + canvas.drawRoundRect(AndroidUtilities.rectTmp, underlineHeight / 2f, underlineHeight / 2f, rectPaint); } View currentTab = tabsContainer.getChildAt(currentPosition); if (currentTab != null) { - float lineLeft = currentTab.getLeft(); - float lineRight = currentTab.getRight(); + float lineLeft = currentTab.getLeft() + currentTab.getPaddingLeft(); + float lineRight = currentTab.getRight() - currentTab.getPaddingRight(); if (currentPositionOffset > 0f && currentPosition < tabCount - 1) { View nextTab = tabsContainer.getChildAt(currentPosition + 1); - final float nextTabLeft = nextTab.getLeft(); - final float nextTabRight = nextTab.getRight(); + final float nextTabLeft = nextTab.getLeft() + nextTab.getPaddingLeft(); + final float nextTabRight = nextTab.getRight() - nextTab.getPaddingRight(); lineLeft = (currentPositionOffset * nextTabLeft + (1f - currentPositionOffset) * lineLeft); lineRight = (currentPositionOffset * nextTabRight + (1f - currentPositionOffset) * lineRight); + + lineLeftAnimated.set(lineLeft, true); + lineRightAnimated.set(lineRight, true); + } else { + lineLeft = lineLeftAnimated.set(lineLeft); + lineRight = lineRightAnimated.set(lineRight); } if (indicatorHeight != 0) { rectPaint.setColor(indicatorColor); - canvas.drawRect(lineLeft, height - indicatorHeight, lineRight, height, rectPaint); + AndroidUtilities.rectTmp.set(lineLeft, height - indicatorHeight, lineRight, height); + canvas.drawRoundRect(AndroidUtilities.rectTmp, indicatorHeight / 2f, indicatorHeight / 2f, rectPaint); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java index 56626b0ff10..e66e5f2431f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/LPhotoPaintView.java @@ -789,12 +789,12 @@ public void draw(Canvas c) { cancelButton = new PaintCancelView(context); cancelButton.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); - cancelButton.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider))); + cancelButton.setBackground(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); bottomLayout.addView(cancelButton, LayoutHelper.createFrame(32, 32, Gravity.BOTTOM | Gravity.LEFT, 12, 0, 0, 4)); doneButton = new PaintDoneView(context); doneButton.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8)); - doneButton.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider))); + doneButton.setBackground(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); doneButton.setOnClickListener(v -> { if (isColorListShown) { new ColorPickerBottomSheet(context, this.resourcesProvider).setColor(colorSwatch.color).setPipetteDelegate(new ColorPickerBottomSheet.PipetteDelegate() { @@ -1170,6 +1170,7 @@ protected void onDraw(Canvas canvas) { drawTab.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); drawTab.setGravity(Gravity.CENTER_HORIZONTAL); drawTab.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + drawTab.setSingleLine(); drawTab.setOnClickListener(v -> { if (editingText) { selectEntity(null); @@ -1189,6 +1190,7 @@ protected void onDraw(Canvas canvas) { stickerTab.setGravity(Gravity.CENTER_HORIZONTAL); stickerTab.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); stickerTab.setAlpha(0.6f); + stickerTab.setSingleLine(); tabsLayout.addView(stickerTab, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f)); textTab = new TextView(context); @@ -1200,6 +1202,7 @@ protected void onDraw(Canvas canvas) { textTab.setGravity(Gravity.CENTER_HORIZONTAL); textTab.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); textTab.setAlpha(0.6f); + textTab.setSingleLine(); textTab.setOnClickListener(v -> { switchTab(2); if (!(currentEntityView instanceof TextPaintView)) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PasscodeView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PasscodeView.java index 9a3eb170a21..9f8a8ed1796 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PasscodeView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PasscodeView.java @@ -65,6 +65,7 @@ import org.telegram.messenger.support.fingerprint.FingerprintManagerCompat; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.LaunchActivity; import java.util.ArrayList; import java.util.Collections; @@ -82,11 +83,19 @@ public void didReceivedNotification(int id, int account, Object... args) { if ((boolean) args[0] && SharedConfig.appLocked) { checkFingerprint(); } + } else if (id == NotificationCenter.passcodeDismissed) { + if (args[0] != this) { + setVisibility(GONE); + + if (fingerprintDialog != null) { + fingerprintDialog.dismiss(); + } + } } } public interface PasscodeViewDelegate { - void didAcceptedPassword(); + void didAcceptedPassword(PasscodeView view); } private static class AnimatingTextView extends FrameLayout { @@ -608,7 +617,9 @@ public void beforeTextChanged(CharSequence s, int start, int count, int after) { backgroundSpringQueue.remove(callback); } for (int i : removeIndex) { - backgroundSpringNextQueue.remove(i); + if (i < backgroundSpringNextQueue.size()) { + backgroundSpringNextQueue.remove(i); + } } } } @@ -967,7 +978,7 @@ private void processDone(boolean fingerprint) { NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.didSetPasscode); setOnTouchListener(null); if (delegate != null) { - delegate.didAcceptedPassword(); + delegate.didAcceptedPassword(this); } AndroidUtilities.runOnUIThread(() -> { @@ -1105,6 +1116,7 @@ protected void onAttachedToWindow() { super.onAttachedToWindow(); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.didGenerateFingerprintKeyPair); + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.passcodeDismissed); } @Override @@ -1112,6 +1124,7 @@ protected void onDetachedFromWindow() { super.onDetachedFromWindow(); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didGenerateFingerprintKeyPair); + NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.passcodeDismissed); } private void checkFingerprint() { @@ -1119,7 +1132,7 @@ private void checkFingerprint() { return; } Activity parentActivity = (Activity) getContext(); - if (parentActivity != null && fingerprintView.getVisibility() == VISIBLE && !ApplicationLoader.mainInterfacePaused) { + if (parentActivity != null && fingerprintView.getVisibility() == VISIBLE && !ApplicationLoader.mainInterfacePaused && (!(parentActivity instanceof LaunchActivity) || ((LaunchActivity) parentActivity).allowShowFingerprintDialog(this))) { try { if (fingerprintDialog != null && fingerprintDialog.isShowing()) { return; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubledLimitsBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubledLimitsBottomSheet.java index be397511b60..90b978ea443 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubledLimitsBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/DoubledLimitsBottomSheet.java @@ -255,7 +255,7 @@ public static class Adapter extends RecyclerListView.SelectionAdapter { final ArrayList limits = new ArrayList<>(); - PremiumGradient.GradientTools gradientTools; + PremiumGradient.PremiumGradientTools gradientTools; private int totalGradientHeight; ViewGroup containerView; @@ -263,7 +263,7 @@ public static class Adapter extends RecyclerListView.SelectionAdapter { public Adapter(int currentAccount, boolean drawHeader) { this.drawHeader = drawHeader; - gradientTools = new PremiumGradient.GradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, Theme.key_premiumGradient3, Theme.key_premiumGradient4); + gradientTools = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, Theme.key_premiumGradient3, Theme.key_premiumGradient4); gradientTools.x1 = 0; gradientTools.y1 = 0; gradientTools.x2 = 0; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GiftPremiumBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GiftPremiumBottomSheet.java index 62620833269..dfec32b74dd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GiftPremiumBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/GiftPremiumBottomSheet.java @@ -54,8 +54,8 @@ import java.util.concurrent.atomic.AtomicReference; public class GiftPremiumBottomSheet extends BottomSheetWithRecyclerListView { - private PremiumGradient.GradientTools gradientTools; - private PremiumGradient.GradientTools outlineGradient; + private PremiumGradient.PremiumGradientTools gradientTools; + private PremiumGradient.PremiumGradientTools outlineGradient; private PremiumButtonView premiumButtonView; private PremiumGiftTierCell dummyCell; @@ -78,7 +78,7 @@ public GiftPremiumBottomSheet(BaseFragment fragment, TLRPC.User user) { super(fragment, false, true); this.user = user; - gradientTools = new PremiumGradient.GradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, null, null); + gradientTools = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, null, null); gradientTools.exactly = true; gradientTools.x1 = 0; gradientTools.y1 = 0f; @@ -87,7 +87,7 @@ public GiftPremiumBottomSheet(BaseFragment fragment, TLRPC.User user) { gradientTools.cx = 0; gradientTools.cy = 0; - outlineGradient = new PremiumGradient.GradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, Theme.key_premiumGradient3, Theme.key_premiumGradient4); + outlineGradient = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, Theme.key_premiumGradient3, Theme.key_premiumGradient4); outlineGradient.paint.setStyle(Paint.Style.STROKE); outlineGradient.paint.setStrokeWidth(AndroidUtilities.dp(1.5f)); @@ -216,8 +216,11 @@ public GiftPremiumBottomSheet(BaseFragment fragment, TLRPC.User user) { } private void updateButtonText(boolean animated) { + if (LocaleController.isRTL) { + animated = false; + } if (!BuildVars.useInvoiceBilling() && (!BillingController.getInstance().isReady() || giftTiers.get(selectedTierIndex).googlePlayProductDetails == null)) { - premiumButtonView.setButton(LocaleController.getString(R.string.Loading), v -> {}, true); + premiumButtonView.setButton(LocaleController.getString(R.string.Loading), v -> {}, !LocaleController.isRTL); premiumButtonView.setFlickerDisabled(true); return; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/HelloParticles.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/HelloParticles.java new file mode 100644 index 00000000000..10d42703076 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/HelloParticles.java @@ -0,0 +1,221 @@ +package org.telegram.ui.Components.Premium; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.Utilities; + +import java.util.ArrayList; +import java.util.HashMap; + +public class HelloParticles { + + private static String[] hellos = new String[] { + "Hello", "Привіт", "Привет", "Bonjour", "Hola", "Ciao", "Olá", "여보세요", "你好", "Salve", + "Sveiki", "Halo", "გამარჯობა", "Hallå", "Salam", "Tere", "Dia dhuit", "こんにちは", "Сайн уу", + "Bongu", "Ahoj", "γεια", "Zdravo", "नमस्ते", "Habari", "Hallo", "ជំរាបសួរ", "مرحبًا", "ನಮಸ್ಕಾರ", + "Салам", "Silav li wir", "سڵاو", "Kif inti", "Talofa", "Thobela", "हॅलो", "ሰላም", "Здраво", + "ഹലോ", "ہیلو", "ꯍꯦꯜꯂꯣ", "Alô", "வணக்கம்", "Mhoro", "Moni", "Alo", "สวัสดี", "Salom", "" + }; + + public static class Drawable { + + private TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + + private float bitmapScale = 1; + private HashMap bitmaps = new HashMap<>(); + + public RectF rect = new RectF(); + public RectF screenRect = new RectF(); + public boolean paused; + private Paint paint = new Paint(); + + ArrayList particles = new ArrayList<>(); + public float speedScale = 1f; + + public final int count; + public boolean useGradient; + public int size1 = 14, size2 = 12, size3 = 10; + public long minLifeTime = 2000; + private int lastColor; + private final float dt = 1000 / AndroidUtilities.screenRefreshRate; + + public Drawable(int count) { + this.count = count; + textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textPaint.setColor(Color.WHITE); + switch (SharedConfig.getDevicePerformanceClass()) { + case SharedConfig.PERFORMANCE_CLASS_LOW: + bitmapScale = .25f; + break; + case SharedConfig.PERFORMANCE_CLASS_AVERAGE: + bitmapScale = .5f; + break; + case SharedConfig.PERFORMANCE_CLASS_HIGH: + default: + bitmapScale = .75f; + break; + } + textPaint.setTextSize(AndroidUtilities.dp(24 * bitmapScale)); + paint.setColor(Color.WHITE); + } + + public void init() { + if (particles.isEmpty()) { + for (int i = 0; i < count; i++) { + particles.add(new Drawable.Particle()); + } + } + } + + public void resetPositions() { + long time = System.currentTimeMillis(); + for (int i = 0; i < particles.size(); i++) { + particles.get(i).genPosition(time, i, true); + } + } + + public void onDraw(Canvas canvas) { + long time = System.currentTimeMillis(); + for (int i = 0; i < particles.size(); i++) { + Drawable.Particle particle = particles.get(i); + if (paused) { + particle.draw(canvas, i, pausedTime); + } else { + particle.draw(canvas, i, time); + } + if (particle.inProgress >= 1) { + particle.genPosition(time, i, false); + } + } + } + + public void recycle() { + for (Bitmap bitmap : bitmaps.values()) { + bitmap.recycle(); + } + bitmaps.clear(); + } + + long pausedTime; + + private class Particle { + private boolean set; + private float x, y; + private float vecX, vecY; + private int alpha; + private StaticLayout staticLayout; + private Bitmap bitmap; + private int l, w, h; + private long duration; + private float scale; + float inProgress; + + public void draw(Canvas canvas, int index, long time) { + + if (!paused) { + float speed = AndroidUtilities.dp(4) * (dt / 660f) * speedScale; +// x += vecX * speed; +// y += vecY * speed; + + if (inProgress != 1f) { + inProgress += dt / duration; + if (inProgress > 1f) { + inProgress = 1f; + } + } + } + + + if (bitmap != null) { + canvas.save(); + float t = 1f - 4f * (float) Math.pow(inProgress - .5f, 2f); + float s = scale / bitmapScale * (.7f + .4f * t); + canvas.translate(x - w / 2f, y - h / 2f); + canvas.scale(s, s, w / 2f, h / 2f); + paint.setAlpha((int) (alpha * t)); + canvas.drawBitmap(bitmap, 0, 0, paint); + canvas.restore(); + } + } + + public void genPosition(long time, int index, boolean reset) { + duration = 2250 + Math.abs(Utilities.fastRandom.nextLong() % 2250); + scale = .6f + .45f * Math.abs(Utilities.fastRandom.nextFloat()); + + String string = hellos[Math.abs(Utilities.fastRandom.nextInt() % hellos.length)]; + if (string.length() > 7) { + scale *= .6f; + } else if (string.length() > 5) { + scale *= .75f; + } + staticLayout = new StaticLayout(string, textPaint, AndroidUtilities.displaySize.x, Layout.Alignment.ALIGN_NORMAL, 1f, 0, false); + if (staticLayout.getLineCount() <= 0) { + l = w = h = 0; + } else { + l = (int) staticLayout.getLineLeft(0); + w = (int) staticLayout.getLineWidth(0); + h = staticLayout.getHeight(); + } + bitmap = bitmaps.get(string); + if (bitmap == null) { + bitmap = Bitmap.createBitmap(Math.max(1, w - Math.max(0, l)), Math.max(1, h), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + canvas.translate(-l, 0); + staticLayout.draw(canvas); + bitmaps.put(string, bitmap); + } + + float bestDistance = 0; + float minX = rect.left + w / 4f, maxX = rect.right - w / 4f; + if (index % 2 == 0) { + maxX = rect.centerX() - w / 2f; + } else { + minX = rect.centerX() + w / 2f; + } + float bestX = minX + Math.abs(Utilities.fastRandom.nextInt() % (maxX - minX)); + float bestY = rect.top + Math.abs(Utilities.fastRandom.nextInt() % rect.height()); + for (int k = 0; k < 10; k++) { + float randX = minX + Math.abs(Utilities.fastRandom.nextInt() % (maxX - minX)); + float randY = rect.top + Math.abs(Utilities.fastRandom.nextInt() % rect.height()); + float minDistance = Integer.MAX_VALUE; + for (int j = 0; j < particles.size(); j++) { + Particle p = particles.get(j); + if (!p.set) { + continue; + } + float rx = Math.min(Math.abs(p.x + p.w * (scale / bitmapScale) * 1.1f - randX), Math.abs(p.x - randX)); + float ry = p.y - randY; + float distance = rx * rx + ry * ry; + if (distance < minDistance) { + minDistance = distance; + } + } + if (minDistance > bestDistance) { + bestDistance = minDistance; + bestX = randX; + bestY = randY; + } + } + x = bestX; + y = bestY; + + double a = Math.atan2(x - rect.centerX(), y - rect.centerY()); + vecX = (float) Math.sin(a); + vecY = (float) Math.cos(a); + alpha = (int) (255 * ((50 + Utilities.fastRandom.nextInt(50)) / 100f)); + + inProgress = reset ? Math.abs((Utilities.fastRandom.nextFloat() % 1f) * .9f) : 0; + set = true; + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java index 95178df8130..959474c7d07 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitPreviewView.java @@ -54,7 +54,7 @@ public class LimitPreviewView extends LinearLayout { TextView defaultCount; private float position; private View parentVideForGradient; - PremiumGradient.GradientTools staticGradient; + PremiumGradient.PremiumGradientTools staticGradient; int gradientYOffset; boolean wasHaptic; boolean animationCanPlay = true; @@ -283,7 +283,7 @@ public void setParentViewForGradien(ViewGroup containerView) { parentVideForGradient = containerView; } - public void setStaticGradinet(PremiumGradient.GradientTools gradientTools) { + public void setStaticGradinet(PremiumGradient.PremiumGradientTools gradientTools) { staticGradient = gradientTools; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java index bfc5c17ae89..7e4ca9198ae 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java @@ -138,7 +138,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setApplyBottomPadding(false); useBackgroundTopPadding = false; - PremiumGradient.GradientTools gradientTools = new PremiumGradient.GradientTools(Theme.key_premiumGradientBottomSheet1, Theme.key_premiumGradientBottomSheet2, Theme.key_premiumGradientBottomSheet3, null); + PremiumGradient.PremiumGradientTools gradientTools = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradientBottomSheet1, Theme.key_premiumGradientBottomSheet2, Theme.key_premiumGradientBottomSheet3, null); gradientTools.x1 = 0; gradientTools.y1 = 1.1f; gradientTools.x2 = 1.5f; @@ -234,7 +234,7 @@ public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { viewPager.setCurrentItem(selectedPosition); frameLayout.addView(viewPager, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 100, 0, 0, 18, 0, 0)); - frameLayout.addView(closeLayout, LayoutHelper.createFrame(52, 52, Gravity.RIGHT | Gravity.TOP, 0, 16, 0, 0)); + frameLayout.addView(closeLayout, LayoutHelper.createFrame(52, 52, Gravity.RIGHT | Gravity.TOP, 0, 24, 0, 0)); BottomPagesView bottomPages = new BottomPagesView(getContext(), viewPager, premiumFeatures.size()); viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @@ -621,6 +621,9 @@ void setFeatureDate(PremiumPreviewFragment.PremiumFeatureData featureData) { } else if (startType == PremiumPreviewFragment.PREMIUM_FEATURE_VOICE_TO_TEXT) { title.setText(LocaleController.getString(R.string.PremiumPreviewVoiceToText)); description.setText(LocaleController.getString(R.string.PremiumPreviewVoiceToTextDescription2)); + } else if (startType == PremiumPreviewFragment.PREMIUM_FEATURE_TRANSLATIONS) { + title.setText(LocaleController.getString(R.string.PremiumPreviewTranslations)); + description.setText(LocaleController.getString(R.string.PremiumPreviewTranslationsDescription)); } topViewOnFullHeight = false; } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumGradient.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumGradient.java index 4b24fc2fe28..87825cb9ebd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumGradient.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumGradient.java @@ -23,7 +23,7 @@ public class PremiumGradient { - private final GradientTools mainGradient = new GradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, Theme.key_premiumGradient3, Theme.key_premiumGradient4); + private final PremiumGradientTools mainGradient = new PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, Theme.key_premiumGradient3, Theme.key_premiumGradient4); // private final GradientTools grayGradient = new GradientTools(Theme.key_windowBackgroundWhiteGrayText7, Theme.key_windowBackgroundWhiteGrayText7, Theme.key_windowBackgroundWhiteGrayText7); private final Paint mainGradientPaint = mainGradient.paint; Paint lockedPremiumPaint; @@ -62,7 +62,7 @@ public InternalDrawable createGradientDrawable(Drawable drawable) { return createGradientDrawable(drawable, mainGradient); } - public InternalDrawable createGradientDrawable(Drawable drawable, PremiumGradient.GradientTools gradient) { + public InternalDrawable createGradientDrawable(Drawable drawable, PremiumGradientTools gradient) { if (drawable == null) { return null; } @@ -135,7 +135,9 @@ public Paint getMainGradientPaint() { return mainGradientPaint; } } - public static class GradientTools { + + //help with update colors and position + public static class PremiumGradientTools { public float cx = 0.5f; public float cy = 0.5f; @@ -149,15 +151,15 @@ public static class GradientTools { public float x1 = 0f, y1 = 1f, x2 = 1.5f, y2 = 0f; - public GradientTools(String colorKey1, String colorKey2, String colorKey3) { + public PremiumGradientTools(String colorKey1, String colorKey2, String colorKey3) { this(colorKey1, colorKey2, colorKey3, null, null); } - public GradientTools(String colorKey1, String colorKey2, String colorKey3, String colorKey4) { + public PremiumGradientTools(String colorKey1, String colorKey2, String colorKey3, String colorKey4) { this(colorKey1, colorKey2, colorKey3, colorKey4, null); } - public GradientTools(String colorKey1, String colorKey2, String colorKey3, String colorKey4, String colorKey5) { + public PremiumGradientTools(String colorKey1, String colorKey2, String colorKey3, String colorKey4, String colorKey5) { this.colorKey1 = colorKey1; this.colorKey2 = colorKey2; this.colorKey3 = colorKey3; @@ -165,7 +167,6 @@ public GradientTools(String colorKey1, String colorKey2, String colorKey3, Strin this.colorKey5 = colorKey5; } - public void gradientMatrix(int x, int y, int x1, int y1, float xOffset, float yOffset) { chekColors(); if (exactly) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumPreviewBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumPreviewBottomSheet.java index 2f8d73c46e5..1d101ea106d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumPreviewBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumPreviewBottomSheet.java @@ -80,7 +80,7 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i int buttonRow; FireworksOverlay fireworksOverlay; - PremiumGradient.GradientTools gradientTools; + PremiumGradient.PremiumGradientTools gradientTools; StarParticlesView starParticlesView; GLIconTextureView iconTextureView; ViewGroup iconContainer; @@ -124,7 +124,7 @@ public PremiumPreviewBottomSheet(BaseFragment fragment, int currentAccount, TLRP buttonContainer.setVisibility(View.GONE); } - gradientTools = new PremiumGradient.GradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, Theme.key_premiumGradient3, Theme.key_premiumGradient4); + gradientTools = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, Theme.key_premiumGradient3, Theme.key_premiumGradient4); gradientTools.exactly = true; gradientTools.x1 = 0; gradientTools.y1 = 1f; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumTierCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumTierCell.java index b4ce51be50c..97c6265e0a3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumTierCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumTierCell.java @@ -107,6 +107,15 @@ public PremiumTierCell(@NonNull Context context) { setWillNotDraw(false); } + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + + titleView.setAlpha(enabled ? 1 : 0.6f); + pricePerMonthView.setAlpha(enabled ? 1 : 0.6f); + checkBox.setAlpha(enabled ? 1 : 0.6f); + } + @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); @@ -142,7 +151,7 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { checkRtlAndLayout(checkBox); int y = (int) ((getMeasuredHeight() - pricePerMonthView.getMeasuredHeight()) / 2f); - if (AndroidUtilities.dp(leftPaddingToCheckboxDp + leftPaddingToTextDp + 24) + checkBox.getMeasuredWidth() + pricePerYearStrikeView.getMeasuredWidth() + pricePerYearView.getMeasuredWidth() + getPaddingLeft() > getMeasuredWidth() - pricePerMonthView.getMeasuredWidth() && discountView.getVisibility() == VISIBLE) { + if (AndroidUtilities.dp(leftPaddingToCheckboxDp + leftPaddingToTextDp + 24) + checkBox.getMeasuredWidth() + (pricePerYearStrikeView.getVisibility() == VISIBLE ? pricePerYearStrikeView.getMeasuredWidth() : 0) + pricePerYearView.getMeasuredWidth() + getPaddingLeft() > getMeasuredWidth() - pricePerMonthView.getMeasuredWidth() && discountView.getVisibility() == VISIBLE) { y = getPaddingTop() + AndroidUtilities.dp(2); } AndroidUtilities.rectTmp2.set(getMeasuredWidth() - pricePerMonthView.getMeasuredWidth() - AndroidUtilities.dp(16) - getPaddingRight(), y, 0, 0); @@ -159,7 +168,7 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { AndroidUtilities.rectTmp2.set(AndroidUtilities.dp(leftPaddingToCheckboxDp + leftPaddingToTextDp) + checkBox.getMeasuredWidth() + getPaddingLeft(), getMeasuredHeight() - pricePerYearStrikeView.getMeasuredHeight() - getPaddingBottom(), 0, 0); checkRtlAndLayout(pricePerYearStrikeView); - AndroidUtilities.rectTmp2.set(AndroidUtilities.dp(leftPaddingToCheckboxDp + leftPaddingToTextDp + 6) + checkBox.getMeasuredWidth() + pricePerYearStrikeView.getMeasuredWidth() + getPaddingLeft(), getMeasuredHeight() - pricePerYearView.getMeasuredHeight() - getPaddingBottom(), 0, 0); + AndroidUtilities.rectTmp2.set(AndroidUtilities.dp(leftPaddingToCheckboxDp + leftPaddingToTextDp) + checkBox.getMeasuredWidth() + (pricePerYearStrikeView.getVisibility() == VISIBLE ? pricePerYearStrikeView.getMeasuredWidth() + AndroidUtilities.dp(6) : 0) + getPaddingLeft(), getMeasuredHeight() - pricePerYearView.getMeasuredHeight() - getPaddingBottom(), 0, 0); checkRtlAndLayout(pricePerYearView); } @@ -197,8 +206,8 @@ private void checkRtlAndLayout(View v) { rect.bottom = rect.top + v.getMeasuredHeight(); if (LocaleController.isRTL) { int right = rect.right; - rect.right = rect.left; - rect.left = right; + rect.right = getWidth() - rect.left; + rect.left = getWidth() - right; } v.layout(AndroidUtilities.rectTmp2.left, AndroidUtilities.rectTmp2.top, AndroidUtilities.rectTmp2.right, AndroidUtilities.rectTmp2.bottom); } @@ -217,7 +226,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { discountView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY)); } pricePerYearStrikeView.measure(MeasureSpec.makeMeasureSpec(width - checkBox.getMeasuredWidth(), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); - pricePerYearView.measure(MeasureSpec.makeMeasureSpec(width - checkBox.getMeasuredWidth() - pricePerYearStrikeView.getMeasuredWidth() - AndroidUtilities.dp(6), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); + pricePerYearView.measure(MeasureSpec.makeMeasureSpec(width - checkBox.getMeasuredWidth() - (pricePerYearStrikeView.getVisibility() == VISIBLE ? pricePerYearStrikeView.getMeasuredWidth() : 0) - AndroidUtilities.dp(6), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); if (pricePerYearView.getVisibility() != VISIBLE) { height -= AndroidUtilities.dp(8); @@ -269,6 +278,11 @@ public void bind(PremiumPreviewFragment.SubscriptionTier tier, boolean hasDivide pricePerYearStrikeView.setText(tier.getFormattedPricePerYearRegular()); pricePerYearView.setText(LocaleController.formatString(R.string.PricePerYear, tier.getFormattedPricePerYear())); pricePerMonthView.setText(LocaleController.formatString(R.string.PricePerMonthMe, tier.getFormattedPricePerMonth())); + + if (tier.subscriptionOption.current) { + pricePerYearView.setVisibility(VISIBLE); + pricePerYearView.setText(LocaleController.getString(R.string.YourCurrentPlan)); + } } else { discountView.setText(LocaleController.formatString(R.string.GiftPremiumOptionDiscount, 10)); discountView.setVisibility(VISIBLE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/VideoScreenPreview.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/VideoScreenPreview.java index f59fac62f33..3e94dfdc8c0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/VideoScreenPreview.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/VideoScreenPreview.java @@ -67,12 +67,16 @@ private void checkVideo() { return; } - MediaMetadataRetriever retriever = new MediaMetadataRetriever(); - retriever.setDataSource(ApplicationLoader.applicationContext, Uri.fromFile(file)); - int width = Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)); - int height = Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)); - retriever.release(); - aspectRatio = width / (float) height; + try { + MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + retriever.setDataSource(ApplicationLoader.applicationContext, Uri.fromFile(file)); + int width = Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)); + int height = Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)); + retriever.release(); + aspectRatio = width / (float) height; + } catch (Exception e) { + aspectRatio = 0.671f; + } } else { aspectRatio = 0.671f; } @@ -102,6 +106,7 @@ private void checkVideo() { private float roundRadius; StarParticlesView.Drawable starDrawable; SpeedLineParticles.Drawable speedLinesDrawable; + HelloParticles.Drawable helloParticlesDrawable; private final static float[] speedScaleVideoTimestamps = new float[]{0.02f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 0.02f}; private MatrixParticlesDrawable matrixParticlesDrawable; @@ -147,6 +152,9 @@ public VideoScreenPreview(Context context, SvgHelper.SvgDrawable svgDrawable, in } else if (type == PremiumPreviewFragment.PREMIUM_FEATURE_DOWNLOAD_SPEED) { speedLinesDrawable = new SpeedLineParticles.Drawable(200); speedLinesDrawable.init(); + } else if (type == PremiumPreviewFragment.PREMIUM_FEATURE_TRANSLATIONS) { + helloParticlesDrawable = new HelloParticles.Drawable(25); + helloParticlesDrawable.init(); } else { int particlesCount = 100; if (SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_HIGH) { @@ -188,7 +196,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { AndroidUtilities.rectTmp.set(0, 0, getMeasuredWidth(), (int) (getMeasuredHeight() + roundRadius)); } float rad = roundRadius - AndroidUtilities.dp(3); - clipPath.addRoundRect(AndroidUtilities.rectTmp, new float[]{rad, rad, rad, rad, rad, rad, rad, rad}, Path.Direction.CW); + clipPath.addRoundRect(AndroidUtilities.rectTmp, rad, rad, Path.Direction.CW); } @Override @@ -339,13 +347,19 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto speedLinesDrawable.rect.offset(0, getMeasuredHeight() * 0.1f); speedLinesDrawable.resetPositions(); } + if (helloParticlesDrawable != null) { + helloParticlesDrawable.rect.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); + helloParticlesDrawable.screenRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); + helloParticlesDrawable.rect.inset(AndroidUtilities.dp(0), getMeasuredHeight() * 0.1f); + helloParticlesDrawable.resetPositions(); + } } } @Override protected void dispatchDraw(Canvas canvas) { - if ((starDrawable != null || speedLinesDrawable != null || matrixParticlesDrawable != null) && progress < 0.5f) { + if ((starDrawable != null || speedLinesDrawable != null || helloParticlesDrawable != null || matrixParticlesDrawable != null) && progress < 0.5f) { float s = (float) Math.pow(1f - progress, 2f); canvas.save(); canvas.scale(s, s, getMeasuredWidth() / 2f, getMeasuredHeight() / 2f); @@ -372,6 +386,8 @@ protected void dispatchDraw(Canvas canvas) { float progressSpeedScale = 0.1f + 0.9f * (1f - Utilities.clamp(progress / 0.1f, 1f, 0)); speedLinesDrawable.speedScale = 150 * progressSpeedScale * videoSpeedScale; speedLinesDrawable.onDraw(canvas); + } else if (helloParticlesDrawable != null) { + helloParticlesDrawable.onDraw(canvas); } canvas.restore(); invalidate(); @@ -486,6 +502,10 @@ protected void onDetachedFromWindow() { attached = false; updateAttachState(); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.fileLoaded); + if (helloParticlesDrawable != null) { + helloParticlesDrawable.recycle(); + helloParticlesDrawable = null; + } } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ProfileGalleryView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ProfileGalleryView.java index 959b8b56118..8b513a2d1a7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ProfileGalleryView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ProfileGalleryView.java @@ -25,6 +25,7 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.DialogObject; import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.MessagesController; @@ -54,7 +55,7 @@ public class ProfileGalleryView extends CircularViewPager implements Notificatio private TLRPC.ChatFull chatInfo; private final Callback callback; - private boolean scrolledByUser; + public boolean scrolledByUser; private boolean isDownReleased; private final boolean isProfileFragment; private ImageLocation uploadingImageLocation; @@ -72,6 +73,7 @@ public class ProfileGalleryView extends CircularViewPager implements Notificatio private ArrayList videoLocations = new ArrayList<>(); private ArrayList imagesLocations = new ArrayList<>(); private ArrayList thumbsLocations = new ArrayList<>(); + private ArrayList vectorAvatars = new ArrayList<>(); private ArrayList imagesLocationsSizes = new ArrayList<>(); private ArrayList imagesUploadProgress = new ArrayList<>(); @@ -470,7 +472,11 @@ public boolean onTouchEvent(MotionEvent ev) { } if (isSwipingViewPager) { - result |= super.onTouchEvent(ev); + try { + result |= super.onTouchEvent(ev); + } catch (Exception e) { + FileLog.e(e); + } } if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { @@ -486,7 +492,7 @@ public void setChatInfo(TLRPC.ChatFull chatFull) { if (!photos.isEmpty() && photos.get(0) == null && chatInfo != null && FileLoader.isSamePhoto(imagesLocations.get(0).location, chatInfo.chat_photo)) { photos.set(0, chatInfo.chat_photo); if (!chatInfo.chat_photo.video_sizes.isEmpty()) { - final TLRPC.VideoSize videoSize = chatInfo.chat_photo.video_sizes.get(0); + final TLRPC.VideoSize videoSize = FileLoader.getClosestVideoSizeWithSize(chatInfo.chat_photo.video_sizes, 1000); videoLocations.set(0, ImageLocation.getForPhoto(videoSize, chatInfo.chat_photo)); videoFileNames.set(0, FileLoader.getAttachFileName(videoSize)); callback.onPhotosLoaded(); @@ -499,7 +505,7 @@ public void setChatInfo(TLRPC.ChatFull chatFull) { } } - public boolean initIfEmpty(ImageLocation imageLocation, ImageLocation thumbLocation, boolean reload) { + public boolean initIfEmpty(VectorAvatarThumbDrawable vectorAvatar, ImageLocation imageLocation, ImageLocation thumbLocation, boolean reload) { if (imageLocation == null || thumbLocation == null || settingMainPhoto != 0) { return false; } @@ -524,6 +530,7 @@ public boolean initIfEmpty(ImageLocation imageLocation, ImageLocation thumbLocat videoFileNames.add(null); imagesLocations.add(imageLocation); thumbsLocations.add(thumbLocation); + vectorAvatars.add(vectorAvatar); videoLocations.add(null); photos.add(null); imagesLocationsSizes.add(-1); @@ -542,6 +549,7 @@ public void addUploadingImage(ImageLocation imageLocation, ImageLocation thumbLo videoFileNames.add(0, null); imagesLocations.add(0, imageLocation); thumbsLocations.add(0, thumbLocation); + vectorAvatars.add(0, null); videoLocations.add(0, null); photos.add(0, null); imagesLocationsSizes.add(0, -1); @@ -722,6 +730,10 @@ public void startMovePhotoToBegin(int index) { thumbsLocations.remove(index); thumbsLocations.add(0, location); + VectorAvatarThumbDrawable vectorAvatar = vectorAvatars.get(index); + vectorAvatars.remove(index); + vectorAvatars.add(0, vectorAvatar); + Integer size = imagesLocationsSizes.get(index); imagesLocationsSizes.remove(index); imagesLocationsSizes.add(0, size); @@ -748,6 +760,7 @@ public boolean removePhotoAtIndex(int index) { videoLocations.remove(index); imagesLocations.remove(index); thumbsLocations.remove(index); + vectorAvatars.remove(index); imagesLocationsSizes.remove(index); radialProgresses.delete(index); imagesUploadProgress.remove(index); @@ -808,6 +821,7 @@ public void didReceivedNotification(int id, int account, Object... args) { imagesLocations.clear(); videoLocations.clear(); thumbsLocations.clear(); + vectorAvatars.clear(); photos.clear(); imagesLocationsSizes.clear(); imagesUploadProgress.clear(); @@ -818,11 +832,12 @@ public void didReceivedNotification(int id, int account, Object... args) { if (currentImageLocation != null) { imagesLocations.add(currentImageLocation); thumbsLocations.add(ImageLocation.getForUserOrChat(chat, ImageLocation.TYPE_SMALL)); + vectorAvatars.add(null); thumbsFileNames.add(null); if (chatInfo != null && FileLoader.isSamePhoto(currentImageLocation.location, chatInfo.chat_photo)) { photos.add(chatInfo.chat_photo); if (!chatInfo.chat_photo.video_sizes.isEmpty()) { - final TLRPC.VideoSize videoSize = chatInfo.chat_photo.video_sizes.get(0); + final TLRPC.VideoSize videoSize = FileLoader.getClosestVideoSizeWithSize(chatInfo.chat_photo.video_sizes, 1000); videoLocations.add(ImageLocation.getForPhoto(videoSize, chatInfo.chat_photo)); videoFileNames.add(FileLoader.getAttachFileName(videoSize)); } else { @@ -858,7 +873,7 @@ public void didReceivedNotification(int id, int account, Object... args) { if (size.location != null && size.location.local_id == currentImageLocation.location.local_id && size.location.volume_id == currentImageLocation.location.volume_id) { photos.set(0, photo); if (!photo.video_sizes.isEmpty()) { - videoLocations.set(0, ImageLocation.getForPhoto(photo.video_sizes.get(0), photo)); + videoLocations.set(0, ImageLocation.getForPhoto(FileLoader.getClosestVideoSizeWithSize(photo.video_sizes, 1000), photo)); } cont = true; break; @@ -879,13 +894,23 @@ public void didReceivedNotification(int id, int account, Object... args) { imagesLocations.add(location); thumbsFileNames.add(FileLoader.getAttachFileName(sizeThumb instanceof TLRPC.TL_photoStrippedSize ? sizeFull : sizeThumb)); thumbsLocations.add(ImageLocation.getForPhoto(sizeThumb, photo)); + if (!photo.video_sizes.isEmpty()) { - final TLRPC.VideoSize videoSize = photo.video_sizes.get(0); - videoLocations.add(ImageLocation.getForPhoto(videoSize, photo)); - videoFileNames.add(FileLoader.getAttachFileName(videoSize)); + final TLRPC.VideoSize videoSize = FileLoader.getClosestVideoSizeWithSize(photo.video_sizes, 1000); + final TLRPC.VideoSize vectorMarkupVideoSize = FileLoader.getVectorMarkupVideoSize(photo); + if (vectorMarkupVideoSize != null) { + vectorAvatars.add(new VectorAvatarThumbDrawable(vectorMarkupVideoSize, user != null && user.premium, VectorAvatarThumbDrawable.TYPE_PROFILE)); + videoLocations.add(null); + videoFileNames.add(null); + } else { + vectorAvatars.add(null); + videoLocations.add(ImageLocation.getForPhoto(videoSize, photo)); + videoFileNames.add(FileLoader.getAttachFileName(videoSize)); + } } else { videoLocations.add(null); videoFileNames.add(null); + vectorAvatars.add(null); } photos.add(photo); imagesLocationsSizes.add(sizeFull.size); @@ -1043,7 +1068,7 @@ public Item instantiateItem(ViewGroup container, int position) { } else { ImageLocation videoLocation = videoLocations.get(imageLocationPosition); item.imageView.isVideo = videoLocation != null; - needProgress = true; + needProgress = vectorAvatars.get(imageLocationPosition) == null; String filter; if (isProfileFragment && videoLocation != null && videoLocation.imageType == FileLoader.IMAGE_TYPE_ANIMATION) { filter = "avatar"; @@ -1053,23 +1078,23 @@ public Item instantiateItem(ViewGroup container, int position) { ImageLocation location = thumbsLocations.get(imageLocationPosition); Bitmap thumb = (parentAvatarImageView == null || !createThumbFromParent) ? null : parentAvatarImageView.getImageReceiver().getBitmap(); String parent = "avatar_" + dialogId; - if (thumb != null) { + if (thumb != null && vectorAvatars.get(imageLocationPosition) == null) { item.imageView.setImageMedia(videoLocations.get(imageLocationPosition), filter, imagesLocations.get(imageLocationPosition), null, thumb, imagesLocationsSizes.get(imageLocationPosition), 1, parent); } else if (uploadingImageLocation != null) { - item.imageView.setImageMedia(videoLocations.get(imageLocationPosition), filter, imagesLocations.get(imageLocationPosition), null, uploadingImageLocation, null, null, imagesLocationsSizes.get(imageLocationPosition), 1, parent); + item.imageView.setImageMedia(vectorAvatars.get(imageLocationPosition), videoLocations.get(imageLocationPosition), filter, imagesLocations.get(imageLocationPosition), null, uploadingImageLocation, null, null, imagesLocationsSizes.get(imageLocationPosition), 1, parent); } else { String thumbFilter = location.photoSize instanceof TLRPC.TL_photoStrippedSize ? "b" : null; - item.imageView.setImageMedia(videoLocation, null, imagesLocations.get(imageLocationPosition), null, thumbsLocations.get(imageLocationPosition), thumbFilter, null, imagesLocationsSizes.get(imageLocationPosition), 1, parent); + item.imageView.setImageMedia(vectorAvatars.get(imageLocationPosition), videoLocation, null, imagesLocations.get(imageLocationPosition), null, thumbsLocations.get(imageLocationPosition), thumbFilter, null, imagesLocationsSizes.get(imageLocationPosition), 1, parent); } } } else { final ImageLocation videoLocation = videoLocations.get(imageLocationPosition); item.imageView.isVideo = videoLocation != null; - needProgress = true; + needProgress = vectorAvatars.get(imageLocationPosition) == null; ImageLocation location = thumbsLocations.get(imageLocationPosition); String filter = location.photoSize instanceof TLRPC.TL_photoStrippedSize ? "b" : null; String parent = "avatar_" + dialogId; - item.imageView.setImageMedia(videoLocation, null, imagesLocations.get(imageLocationPosition), null, thumbsLocations.get(imageLocationPosition), filter, null, imagesLocationsSizes.get(imageLocationPosition), 1, parent); + item.imageView.setImageMedia(vectorAvatars.get(imageLocationPosition), videoLocation, null, imagesLocations.get(imageLocationPosition), null, thumbsLocations.get(imageLocationPosition), filter, null, imagesLocationsSizes.get(imageLocationPosition), 1, parent); } if (imagesUploadProgress.get(imageLocationPosition) != null) { needProgress = true; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java index 068696d5f1b..62945b8a5a1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java @@ -24,6 +24,8 @@ import android.view.HapticFeedbackConstants; import android.view.View; +import com.google.gson.Gson; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.DispatchQueue; @@ -37,6 +39,7 @@ import java.io.File; import java.io.FileInputStream; +import java.io.FileReader; import java.io.InputStream; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -72,6 +75,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma private HashMap vibrationPattern; private boolean resetVibrationAfterRestart = false; private boolean allowVibration = true; + public static Gson gson; private WeakReference frameReadyCallback; protected WeakReference onFinishCallback; @@ -107,6 +111,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma private boolean applyingLayerColors; protected int currentFrame; private boolean shouldLimitFps; + private boolean createdForFirstFrame; private float scaleX = 1.0f; private float scaleY = 1.0f; @@ -231,12 +236,19 @@ protected void decodeFrameFinishedInternal() { if (destroyWhenDone) { checkRunningTasks(); if (loadFrameTask == null && cacheGenerateTask == null && nativePtr != 0) { - destroy(nativePtr); + long nativePtrFinal = nativePtr; + long secondNativePtrFinal = secondNativePtr; nativePtr = 0; - if (secondNativePtr != 0) { - destroy(secondNativePtr); - secondNativePtr = 0; - } + secondNativePtr = 0; + DispatchQueuePoolBackground.execute(() -> { + if (nativePtrFinal != 0) { + destroy(nativePtrFinal); + } + if (secondNativePtrFinal != 0) { + destroy(secondNativePtrFinal); + } + }); + } } if ((nativePtr == 0 || fallbackCache) && secondNativePtr == 0 && bitmapsCache == null) { @@ -447,6 +459,7 @@ public RLottieDrawable(File file, int w, int h, BitmapsCache.CacheOptions cacheO shouldLimitFps = limitFps; this.precache = cacheOptions != null; this.fallbackCache = cacheOptions != null && cacheOptions.fallback; + this.createdForFirstFrame = cacheOptions != null && cacheOptions.firstFrame; getPaint().setFlags(Paint.FILTER_BITMAP_FLAG); this.file = file; @@ -454,21 +467,16 @@ public RLottieDrawable(File file, int w, int h, BitmapsCache.CacheOptions cacheO createCacheGenQueue(); } if (precache) { - bitmapsCache = new BitmapsCache(file, this, cacheOptions, w, h, !limitFps); args = new NativePtrArgs(); args.file = file.getAbsoluteFile(); args.json = null; args.colorReplacement = colorReplacement; args.fitzModifier = fitzModifier; - nativePtr = create(file.getAbsolutePath(), null, w, h, metaData, precache, colorReplacement, shouldLimitFps, fitzModifier); - if (fallbackCache) { - if (nativePtr == 0) { - file.delete(); - } - } else { - destroy(nativePtr); - nativePtr = 0; + if (createdForFirstFrame) { + return; } + bitmapsCache = new BitmapsCache(file, this, cacheOptions, w, h, !limitFps); + parseLottieMetadata(file, null, metaData); } else { nativePtr = create(file.getAbsolutePath(), null, w, h, metaData, precache, colorReplacement, shouldLimitFps, fitzModifier); if (nativePtr == 0) { @@ -487,28 +495,22 @@ public RLottieDrawable(File file, String json, int w, int h, BitmapsCache.CacheO height = h; shouldLimitFps = limitFps; this.precache = options != null; + this.createdForFirstFrame = options != null && options.firstFrame; getPaint().setFlags(Paint.FILTER_BITMAP_FLAG); if (precache && lottieCacheGenerateQueue == null) { createCacheGenQueue(); } if (precache) { - bitmapsCache = new BitmapsCache(file, this, options, w, h, !limitFps); args = new NativePtrArgs(); args.file = file.getAbsoluteFile(); args.json = json; args.colorReplacement = colorReplacement; args.fitzModifier = fitzModifier; - nativePtr = create(file.getAbsolutePath(), json, w, h, metaData, precache, colorReplacement, shouldLimitFps, fitzModifier); - if (fallbackCache) { - if (nativePtr == 0) { - file.delete(); - } - } else { - if (nativePtr != 0) { - destroy(nativePtr); - } - nativePtr = 0; + if (createdForFirstFrame) { + return; } + bitmapsCache = new BitmapsCache(file, this, options, w, h, !limitFps); + parseLottieMetadata(file, json, metaData); } else { nativePtr = create(file.getAbsolutePath(), json, w, h, metaData, precache, colorReplacement, shouldLimitFps, fitzModifier); if (nativePtr == 0) { @@ -522,6 +524,28 @@ public RLottieDrawable(File file, String json, int w, int h, BitmapsCache.CacheO timeBetweenFrames = Math.max(shouldLimitFps ? 33 : 16, (int) (1000.0f / metaData[1])); } + private void parseLottieMetadata(File file, String json, int[] metaData) { + if (gson == null) { + gson = new Gson(); + } + try { + LottieMetadata lottieMetadata; + if (file != null) { + lottieMetadata = gson.fromJson(new FileReader(file.getAbsolutePath()), LottieMetadata.class); + } else { + lottieMetadata = gson.fromJson(json, LottieMetadata.class); + } + metaData[0] = (int) lottieMetadata.op; + metaData[1] = (int) lottieMetadata.fr; + } catch (Exception e) { + FileLog.e(e); + long nativePtr = create(file.getAbsolutePath(), json, width, height, metaData, false, args.colorReplacement, shouldLimitFps, args.fitzModifier); + if (nativePtr != 0) { + destroy(nativePtr); + } + } + } + public RLottieDrawable(int rawRes, String name, int w, int h) { this(rawRes, name, w, h, true, null); } @@ -739,8 +763,6 @@ public void removeParentView(ImageReceiver parent) { checkCacheCancel(); } - private Runnable cancelCache; - public void checkCacheCancel() { if (bitmapsCache == null || lottieCacheGenerateQueue == null || cacheGenerateTask == null) { return; @@ -856,7 +878,11 @@ public void start() { } public boolean restart() { - if ((autoRepeat < 2 || autoRepeatPlayCount == 0) && autoRepeatCount < 0) { + return restart(false); + } + + public boolean restart(boolean force) { + if (!force && (autoRepeat < 2 || autoRepeatPlayCount == 0) && autoRepeatCount < 0) { return false; } autoRepeatPlayCount = 0; @@ -1256,12 +1282,16 @@ public boolean isLastFrame() { @Override public void prepareForGenerateCache() { - generateCacheNativePtr = create(args.file.toString(), args.json, width, height, new int[3], false, args.colorReplacement, false, args.fitzModifier); + generateCacheNativePtr = create(args.file.toString(), args.json, width, height, createdForFirstFrame ? metaData : new int[3], false, args.colorReplacement, false, args.fitzModifier); if (generateCacheNativePtr == 0 && file != null) { file.delete(); } } + public void setGeneratingFrame(int i) { + generateCacheFramePointer = i; + } + @Override public int getNextFrame(Bitmap bitmap) { if (generateCacheNativePtr == 0) { @@ -1366,4 +1396,11 @@ public void checkCache(Runnable onReady) { }); } } + + private class LottieMetadata { + float fr; + int w; + int h; + float op; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieImageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieImageView.java index ee890df898a..e456605f9e7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieImageView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieImageView.java @@ -31,6 +31,9 @@ public class RLottieImageView extends ImageView { private boolean attachedToWindow; private boolean playing; private boolean startOnAttach; + private Integer layerNum; + private boolean onlyLastFrame; + public boolean cached; public RLottieImageView(Context context) { super(context); @@ -40,6 +43,13 @@ public void clearLayerColors() { layerColors.clear(); } + public void setLayerNum(Integer layerNum) { + this.layerNum = layerNum; + if (this.imageReceiver != null) { + this.imageReceiver.setLayerNum(layerNum); + } + } + public void setLayerColor(String layer, int color) { if (layerColors == null) { layerColors = new HashMap<>(); @@ -95,6 +105,10 @@ public void setAnimation(RLottieDrawable lottieDrawable) { } + public void setOnlyLastFrame(boolean onlyLastFrame) { + this.onlyLastFrame = onlyLastFrame; + } + public void setAnimation(TLRPC.Document document, int w, int h) { if (imageReceiver != null) { imageReceiver.onDetachedFromWindow(); @@ -103,36 +117,50 @@ public void setAnimation(TLRPC.Document document, int w, int h) { if (document == null) { return; } - imageReceiver = new ImageReceiver(); - if ("video/webm".equals(document.mime_type)) { + imageReceiver = new ImageReceiver() { + @Override + protected boolean setImageBitmapByKey(Drawable drawable, String key, int type, boolean memCache, int guid) { + if (drawable != null) { + onLoaded(); + } + return super.setImageBitmapByKey(drawable, key, type, memCache, guid); + } + }; + if (onlyLastFrame) { + imageReceiver.setImage(ImageLocation.getForDocument(document), w + "_" + h + "_lastframe", null, null, null, null, null, 0, null, document, 1); + } else if ("video/webm".equals(document.mime_type)) { TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 90); - imageReceiver.setImage(ImageLocation.getForDocument(document), w + "_" + h + "_pcache_" + ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForDocument(thumb, document), null, null, document.size, null, document, 1); + imageReceiver.setImage(ImageLocation.getForDocument(document), w + "_" + h + (cached ? "_pcache" : "") + "_" + ImageLoader.AUTOPLAY_FILTER, ImageLocation.getForDocument(thumb, document), null, null, document.size, null, document, 1); } else { - Drawable thumbDrawable = null; - String probableCacheKey = document.id + "@" + w + "_" + h; - if (!ImageLoader.getInstance().hasLottieMemCache(probableCacheKey)) { - SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(document.thumbs, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f); - if (svgThumb != null) { - svgThumb.overrideWidthAndHeight(512, 512); - } - thumbDrawable = svgThumb; + SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(document.thumbs, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f); + if (svgThumb != null) { + svgThumb.overrideWidthAndHeight(512, 512); } TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 90); - imageReceiver.setImage(ImageLocation.getForDocument(document), w + "_" + h, ImageLocation.getForDocument(thumb, document), null, null, null, thumbDrawable, 0, null, document, 1); + imageReceiver.setImage(ImageLocation.getForDocument(document), w + "_" + h + (cached ? "_pcache" : ""), ImageLocation.getForDocument(thumb, document), null, null, null, svgThumb, 0, null, document, 1); } imageReceiver.setAspectFit(true); imageReceiver.setParentView(this); - imageReceiver.setAutoRepeat(1); - imageReceiver.setAllowStartLottieAnimation(true); - imageReceiver.setAllowStartAnimation(true); + if (autoRepeat) { + imageReceiver.setAutoRepeat(1); + imageReceiver.setAllowStartLottieAnimation(true); + imageReceiver.setAllowStartAnimation(true); + } else { + imageReceiver.setAutoRepeat(0); + } + imageReceiver.setLayerNum(layerNum != null ? layerNum : 7); imageReceiver.clip = false; setImageDrawable(new Drawable() { @Override public void draw(@NonNull Canvas canvas) { - AndroidUtilities.rectTmp2.set(getBounds()); - AndroidUtilities.rectTmp2.inset(AndroidUtilities.dp(11), AndroidUtilities.dp(11)); + AndroidUtilities.rectTmp2.set( + getBounds().centerX() - AndroidUtilities.dp(w) / 2, + getBounds().centerY() - AndroidUtilities.dp(h) / 2, + getBounds().centerX() + AndroidUtilities.dp(w) / 2, + getBounds().centerY() + AndroidUtilities.dp(h) / 2 + ); imageReceiver.setImageCoords(AndroidUtilities.rectTmp2); imageReceiver.draw(canvas); } @@ -158,6 +186,10 @@ public int getOpacity() { } } + protected void onLoaded() { + + } + public void clearAnimationDrawable() { if (drawable != null) { drawable.stop(); @@ -176,6 +208,9 @@ protected void onAttachedToWindow() { attachedToWindow = true; if (imageReceiver != null) { imageReceiver.onAttachedToWindow(); + if (playing) { + imageReceiver.startAnimation(); + } } if (drawable != null) { drawable.setCallback(this); @@ -194,7 +229,6 @@ protected void onDetachedFromWindow() { } if (imageReceiver != null) { imageReceiver.onDetachedFromWindow(); - imageReceiver = null; } } @@ -207,10 +241,13 @@ public void setAutoRepeat(boolean repeat) { } public void setProgress(float progress) { - if (drawable == null) { - return; + if (drawable != null) { + drawable.setProgress(progress); } - drawable.setProgress(progress); + } + + public ImageReceiver getImageReceiver() { + return imageReceiver; } @Override @@ -220,12 +257,14 @@ public void setImageResource(int resId) { } public void playAnimation() { - if (drawable == null) { + if (drawable == null && imageReceiver == null) { return; } playing = true; if (attachedToWindow) { - drawable.start(); + if (drawable != null) { + drawable.start(); + } if (imageReceiver != null) { imageReceiver.startAnimation(); } @@ -235,12 +274,14 @@ public void playAnimation() { } public void stopAnimation() { - if (drawable == null) { + if (drawable == null && imageReceiver == null) { return; } playing = false; if (attachedToWindow) { - drawable.stop(); + if (drawable != null) { + drawable.stop(); + } if (imageReceiver != null) { imageReceiver.stopAnimation(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedHeaderView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedHeaderView.java index 740c65edd51..bb7e9c9565c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedHeaderView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedHeaderView.java @@ -71,6 +71,7 @@ public ReactedHeaderView(@NonNull Context context, int currentAccount, MessageOb avatarsImageView = new AvatarsImageView(context, false); avatarsImageView.setStyle(AvatarsDrawable.STYLE_MESSAGE_SEEN); + avatarsImageView.setAvatarsTextSize(AndroidUtilities.dp(22)); addView(avatarsImageView, LayoutHelper.createFrameRelatively(24 + 12 + 12 + 8, LayoutHelper.MATCH_PARENT, Gravity.END | Gravity.CENTER_VERTICAL, 0, 0, 0, 0)); iconView = new ImageView(context); @@ -214,7 +215,7 @@ private void loadReactions() { if (message.messageOwner.reactions != null && message.messageOwner.reactions.results.size() == 1 && !list.reactions.isEmpty()) { for (TLRPC.TL_availableReaction r : MediaDataController.getInstance(currentAccount).getReactionsList()) { if (r.reaction.equals(list.reactions.get(0).reaction)) { - reactView.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_lastframe", "webp", null, r); + reactView.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_lastreactframe", "webp", null, r); reactView.setVisibility(VISIBLE); reactView.setAlpha(0); reactView.animate().alpha(1f).start(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java index bd0d8697147..4cf9aabe186 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java @@ -427,7 +427,7 @@ void setUserReaction(TLRPC.MessagePeerReaction reaction) { TLRPC.TL_availableReaction r = MediaDataController.getInstance(currentAccount).getReactionsMap().get(visibleReaction.emojicon); if (r != null) { SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(r.static_icon.thumbs, Theme.key_windowBackgroundGray, 1.0f); - reactView.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_lastframe", "webp", svgThumb, r); + reactView.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_lastreactframe", "webp", svgThumb, r); hasReactImage = true; } else { reactView.setImageDrawable(null); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionTabHolderView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionTabHolderView.java index 2a789dc3a85..3459dc4ebe8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionTabHolderView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionTabHolderView.java @@ -113,7 +113,7 @@ public void setCounter(int currentAccount, TLRPC.ReactionCount counter) { for (TLRPC.TL_availableReaction r : MediaDataController.getInstance(currentAccount).getReactionsList()) { if (r.reaction.equals(reaction.emojicon)) { SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(r.static_icon, Theme.key_windowBackgroundGray, 1.0f); - reactView.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_lastframe", "webp", svgThumb, r); + reactView.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_lastreactframe", "webp", svgThumb, r); reactView.setVisibility(VISIBLE); iconView.setVisibility(GONE); break; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatSelectionReactionMenuOverlay.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatSelectionReactionMenuOverlay.java new file mode 100644 index 00000000000..f769084b80c --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ChatSelectionReactionMenuOverlay.java @@ -0,0 +1,380 @@ +package org.telegram.ui.Components.Reactions; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.core.math.MathUtils; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessageObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Cells.ChatMessageCell; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.FragmentContextView; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.ReactionsContainerLayout; +import org.telegram.ui.Components.RecyclerListView; + +import java.util.Collections; +import java.util.List; + +public class ChatSelectionReactionMenuOverlay extends FrameLayout { + private ChatActivity parentFragment; + private ReactionsContainerLayout reactionsContainerLayout; + + private List selectedMessages = Collections.emptyList(); + private boolean isVisible; + private MessageObject currentPrimaryObject; + + private int mPadding = 22; + private int mSidePadding = 24; + + private float currentOffsetY; + private float toOffsetY; + private float translationOffsetY; + private long lastUpdate; + private boolean hiddenByScroll; + + private boolean messageSet; + + public ChatSelectionReactionMenuOverlay(ChatActivity fragment, Context context) { + super(context); + setVisibility(GONE); + + this.parentFragment = fragment; + + setClipToPadding(false); + setClipChildren(false); + + fragment.getChatListView().addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + invalidatePosition(); + } + }); + } + + private void checkCreateReactionsLayout() { + if (reactionsContainerLayout == null) { + reactionsContainerLayout = new ReactionsContainerLayout(parentFragment, getContext(), parentFragment.getCurrentAccount(), parentFragment.getResourceProvider()) { + float enabledAlpha = 1f; + long lastUpdate; + + { + setWillNotDraw(false); + } + + @Override + public void draw(Canvas canvas) { + long dt = Math.min(16, System.currentTimeMillis() - lastUpdate); + lastUpdate = System.currentTimeMillis(); + + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + canvas.saveLayerAlpha(AndroidUtilities.rectTmp, (int) (0xFF * enabledAlpha), Canvas.ALL_SAVE_FLAG); + super.draw(canvas); + canvas.restore(); + + if (!isEnabled() && enabledAlpha != 0f) { + enabledAlpha = Math.max(0, enabledAlpha - dt / 150f); + invalidate(); + + if (enabledAlpha == 0) { + setVisibility(GONE); + } + } else if (isEnabled() && enabledAlpha != 1f) { + enabledAlpha = Math.min(1, enabledAlpha + dt / 150f); + invalidate(); + } + } + + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + + if (visibility == View.GONE && enabledAlpha != 0) { + enabledAlpha = 0; + } + } + }; + reactionsContainerLayout.setPadding(AndroidUtilities.dp(4) + (LocaleController.isRTL ? 0 : mSidePadding), AndroidUtilities.dp(4), AndroidUtilities.dp(4) + (LocaleController.isRTL ? mSidePadding : 0), AndroidUtilities.dp(mPadding)); + reactionsContainerLayout.setDelegate(new ReactionsContainerLayout.ReactionsContainerDelegate() { + @Override + public void onReactionClicked(View view, ReactionsLayoutInBubble.VisibleReaction visibleReaction, boolean longpress, boolean addToRecent) { + parentFragment.selectReaction(currentPrimaryObject, reactionsContainerLayout, view, 0, 0, visibleReaction, false, longpress, addToRecent); + AndroidUtilities.runOnUIThread(() -> { + reactionsContainerLayout.dismissParent(true); + hideMenu(); + }); + } + + @Override + public void hideMenu() { + parentFragment.clearSelectionMode(true); + } + }); + reactionsContainerLayout.setClipChildren(false); + reactionsContainerLayout.setClipToPadding(false); + addView(reactionsContainerLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 70 + mPadding, Gravity.RIGHT)); + } + } + + public boolean isVisible() { + return isVisible && !hiddenByScroll; + } + + public void invalidatePosition() { + invalidatePosition(true); + } + + private int[] pos = new int[2]; + public void invalidatePosition(boolean animate) { + if (!isVisible || currentPrimaryObject == null || reactionsContainerLayout == null) { + return; + } + + long dt = Math.min(16, System.currentTimeMillis() - lastUpdate); + lastUpdate = System.currentTimeMillis(); + if (currentOffsetY != toOffsetY) { + float a = dt / 220f; + if (toOffsetY > currentOffsetY) { + currentOffsetY = Math.min(currentOffsetY + a, toOffsetY); + } else if (toOffsetY < currentOffsetY) { + currentOffsetY = Math.max(currentOffsetY - a, toOffsetY); + } + AndroidUtilities.runOnUIThread(this::invalidatePosition); + } + + RecyclerListView listView = parentFragment.getChatListView(); + listView.getLocationInWindow(pos); + float listY = pos[1]; + getLocationInWindow(pos); + float offsetY = listY - pos[1] - parentFragment.getPullingDownOffset(); + + for (int i = 0; i < listView.getChildCount(); i++) { + View ch = listView.getChildAt(i); + if (ch instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) ch; + + MessageObject obj = cell.getMessageObject(); + if (obj.getId() == currentPrimaryObject.getId()) { + boolean mirrorX = obj.isOutOwner(); + if (reactionsContainerLayout != null) { + reactionsContainerLayout.setMirrorX(mirrorX); + reactionsContainerLayout.setPadding(AndroidUtilities.dp(4) + (LocaleController.isRTL || mirrorX ? 0 : mSidePadding), AndroidUtilities.dp(mPadding), AndroidUtilities.dp(4) + (LocaleController.isRTL || mirrorX ? mSidePadding : 0), AndroidUtilities.dp(mPadding)); + } + int height = getHeight() != 0 ? getHeight() : listView.getHeight(); + int groupHeight; + + if (cell.getCurrentMessagesGroup() != null) { + MessageObject.GroupedMessages group = cell.getCurrentMessagesGroup(); + groupHeight = group.transitionParams.bottom - group.transitionParams.top; + } else { + groupHeight = cell.getHeight(); + } + + float y = cell.getY() + offsetY - AndroidUtilities.dp(74); + float min = AndroidUtilities.dp(14), max = height - AndroidUtilities.dp(218); + FragmentContextView fragmentContextView = parentFragment.getFragmentContextView(); + if (fragmentContextView != null && fragmentContextView.getVisibility() == View.VISIBLE) { + min += fragmentContextView.getHeight(); + } + boolean newVisibleOffset; + boolean flippedVertically; + if (y > min - groupHeight / 2f && y < max) { + newVisibleOffset = true; + flippedVertically = false; + toOffsetY = 0f; + } else if (y < min - groupHeight - AndroidUtilities.dp(92) || y > max) { + newVisibleOffset = false; + flippedVertically = false; + } else { + newVisibleOffset = true; + translationOffsetY = groupHeight + AndroidUtilities.dp(56); + flippedVertically = true; + toOffsetY = 1f; + } + if (!animate) { + currentOffsetY = toOffsetY; + } + + y += CubicBezierInterpolator.DEFAULT.getInterpolation(currentOffsetY) * translationOffsetY; + if (reactionsContainerLayout == null) { + return; + } + if (flippedVertically != reactionsContainerLayout.isFlippedVertically()) { + reactionsContainerLayout.setFlippedVertically(flippedVertically); + AndroidUtilities.runOnUIThread(this::invalidatePosition); + } + if (newVisibleOffset != reactionsContainerLayout.isEnabled()) { + reactionsContainerLayout.setEnabled(newVisibleOffset); + reactionsContainerLayout.invalidate(); + if (newVisibleOffset) { + reactionsContainerLayout.setVisibility(VISIBLE); + if (!messageSet) { + messageSet = true; + reactionsContainerLayout.setMessage(currentPrimaryObject, parentFragment.getCurrentChatInfo()); + } + } + } + reactionsContainerLayout.setTranslationY(MathUtils.clamp(y, min, max)); + reactionsContainerLayout.setTranslationX(cell.getNonAnimationTranslationX(true)); + + boolean invalidate = false; + LayoutParams params = (LayoutParams) reactionsContainerLayout.getLayoutParams(); + int left = Math.max(0, cell.getBackgroundDrawableLeft() - AndroidUtilities.dp(32)); + int right = Math.max((int) cell.getNonAnimationTranslationX(true), cell.getWidth() - cell.getBackgroundDrawableRight() - AndroidUtilities.dp(32)); + + int minWidth = AndroidUtilities.dp(40) * 8; + if (getWidth() - right - left < minWidth) { + if (mirrorX) { + right = 0; + left = Math.min(left, getWidth() - right - minWidth); + } else { + left = 0; + right = Math.min(right, getWidth() - left - minWidth); + } + } + + int gravity = mirrorX ? Gravity.RIGHT : Gravity.LEFT; + if (gravity != params.gravity) { + params.gravity = gravity; + invalidate = true; + } + if (left != params.leftMargin) { + params.leftMargin = left; + invalidate = true; + } + if (right != params.rightMargin) { + params.rightMargin = right; + invalidate = true; + } + if (invalidate) { + reactionsContainerLayout.requestLayout(); + } + return; + } + } + } + + if (reactionsContainerLayout != null && reactionsContainerLayout.isEnabled()) { + reactionsContainerLayout.setEnabled(false); + } + } + + private MessageObject findPrimaryObject() { + if (isVisible && !selectedMessages.isEmpty()) { + MessageObject msg = selectedMessages.get(0); + + if (msg.getGroupId() != 0) { + MessageObject.GroupedMessages groupedMessages = parentFragment.getGroup(msg.getGroupId()); + + for (MessageObject obj : groupedMessages.messages) { + if (obj.messageOwner != null && obj.messageOwner.reactions != null && obj.messageOwner.reactions.results != null && + !obj.messageOwner.reactions.results.isEmpty()) { + return obj; + } + } + } + + return msg; + } + return null; + } + + private boolean isMessageTypeAllowed(MessageObject obj) { + return MessageObject.isPhoto(obj.messageOwner) || obj.getDocument() != null && MessageObject.isVideoDocument(obj.getDocument()); + } + + public void setSelectedMessages(List messages) { + this.selectedMessages = messages; + + boolean visible = false; + + if (parentFragment.getCurrentChatInfo() != null && parentFragment.getCurrentChatInfo().available_reactions instanceof TLRPC.TL_chatReactionsNone) { + visible = false; + } else if (!messages.isEmpty()) { + visible = true; + + boolean hasGroupId = false; + long groupId = 0; + for (MessageObject obj : messages) { + if (!isMessageTypeAllowed(obj)) { + visible = false; + break; + } + if (!hasGroupId) { + hasGroupId = true; + groupId = obj.getGroupId(); + } else if (groupId != obj.getGroupId() || groupId == 0) { + visible = false; + break; + } + } + } + + if (visible != isVisible) { + isVisible = visible; + hiddenByScroll = false; + animateVisible(visible); + } else if (visible) { + currentPrimaryObject = findPrimaryObject(); + } + } + + private void animateVisible(boolean visible) { + if (visible) { + currentPrimaryObject = findPrimaryObject(); + checkCreateReactionsLayout(); + invalidatePosition(false); + + setVisibility(VISIBLE); + if (reactionsContainerLayout.isEnabled()) { + messageSet = true; + reactionsContainerLayout.setMessage(currentPrimaryObject, parentFragment.getCurrentChatInfo()); + reactionsContainerLayout.startEnterAnimation(); + } else { + messageSet = false; + reactionsContainerLayout.setTransitionProgress(1f); + } + } else { + messageSet = false; + ValueAnimator animator = ValueAnimator.ofFloat(1, 0).setDuration(150); + animator.addUpdateListener(animation -> { + float val = (float) animation.getAnimatedValue(); + if (reactionsContainerLayout != null) { + reactionsContainerLayout.setAlpha(val); + } + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + setVisibility(GONE); + if (reactionsContainerLayout != null) { + removeView(reactionsContainerLayout); + reactionsContainerLayout = null; + } + currentPrimaryObject = null; + } + }); + animator.start(); + } + } + + public void setHiddenByScroll(boolean hiddenByScroll) { + this.hiddenByScroll = hiddenByScroll; + + if (hiddenByScroll) { + animateVisible(false); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java index 76c4318d67a..15603f2856e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/CustomEmojiReactionsWindow.java @@ -59,6 +59,7 @@ public class CustomEmojiReactionsWindow { public RectF drawingRect = new RectF(); float enterTransitionProgress; boolean enterTransitionFinished; + boolean isShowing; SelectAnimatedEmojiDialog selectAnimatedEmojiDialog; ReactionsContainerLayout reactionsContainerLayout; @@ -150,6 +151,11 @@ protected void onEmojiSelected(View emojiView, Long documentId, TLRPC.Document d reactionsContainerLayout.onReactionClicked(emojiView, ReactionsLayoutInBubble.VisibleReaction.fromCustomEmoji(documentId), false); AndroidUtilities.hideKeyboard(windowView); } + + @Override + protected void invalidateParent() { + containerView.invalidate(); + } }; selectAnimatedEmojiDialog.setOnLongPressedListener(new SelectAnimatedEmojiDialog.onLongPressedListener() { @Override @@ -181,14 +187,12 @@ public void onRecentCleared() { this.reactionsContainerLayout = reactionsContainerLayout; reactionsContainerLayout.prepareAnimation(true); - containerView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { - @Override - public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { - containerView.removeOnLayoutChangeListener(this); - reactionsContainerLayout.prepareAnimation(false); - createTransition(true); - } - }); + AndroidUtilities.runOnUIThread(() -> { + isShowing = true; + containerView.invalidate(); + reactionsContainerLayout.prepareAnimation(false); + createTransition(true); + }, 50); NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 7); } @@ -412,6 +416,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @Override protected void dispatchDraw(Canvas canvas) { + if (!isShowing) { + return; + } dimPaint.setAlpha((int) (0.2f * enterTransitionProgress * 255)); canvas.drawPaint(dimPaint); AndroidUtilities.rectTmp.set(0, 0, getMeasuredWidth(), getMeasuredHeight()); @@ -619,7 +626,6 @@ protected void dispatchDraw(Canvas canvas) { } selectAnimatedEmojiDialog.drawBigReaction(canvas, this); - invalidate(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsEffectOverlay.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsEffectOverlay.java index 338ac6f21bd..1b5dc54374d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsEffectOverlay.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsEffectOverlay.java @@ -593,7 +593,7 @@ protected void onDetachedFromWindow() { if (animationType != SHORT_ANIMATION) { if (availableReaction != null) { - emojiStaticImageView.getImageReceiver().setImage(ImageLocation.getForDocument(availableReaction.center_icon), "40_40_lastframe", null, "webp", availableReaction, 1); + emojiStaticImageView.getImageReceiver().setImage(ImageLocation.getForDocument(availableReaction.center_icon), "40_40_lastreactframe", null, "webp", availableReaction, 1); } container.addView(emojiStaticImageView); emojiStaticImageView.getLayoutParams().width = emojiSize; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java index c6af97580a7..1c9e53fc1a4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java @@ -526,7 +526,7 @@ public ReactionButton(TLRPC.ReactionCount reactionCount, boolean isSmall) { if (r != null) { SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(r.static_icon, Theme.key_windowBackgroundGray, 1.0f); //imageReceiver.setImage(ImageLocation.getForDocument(r.static_icon), "40_40", svgThumb, "webp", r, 1); - imageReceiver.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_lastframe", svgThumb, "webp", r, 1); + imageReceiver.setImage(ImageLocation.getForDocument(r.center_icon), "40_40_lastreactframe", svgThumb, "webp", r, 1); } } else if (visibleReaction.documentId != 0) { animatedEmojiDrawable = new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW, currentAccount, visibleReaction.documentId); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java index 19c21165b18..affc86f772d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java @@ -106,6 +106,11 @@ public void set(ReactionsContainerLayout object, Float value) { private int currentAccount; private long waitingLoadingChatId; + private boolean mirrorX; + private boolean isFlippedVertically; + private float flipVerticalProgress; + private long lastUpdate; + ValueAnimator cancelPressedAnimation; FrameLayout premiumLockContainer; FrameLayout customReactionsContainer; @@ -486,7 +491,6 @@ private void showCustomEmojiReactionDialog() { return; } reactionsWindow = new CustomEmojiReactionsWindow(fragment, allReactionsList, selectedReactions, this, resourcesProvider); - reactionsWindow.onDismissListener(() -> { reactionsWindow = null; }); @@ -519,6 +523,20 @@ public void setDelegate(ReactionsContainerDelegate delegate) { this.delegate = delegate; } + public boolean isFlippedVertically() { + return isFlippedVertically; + } + + public void setFlippedVertically(boolean flippedVertically) { + isFlippedVertically = flippedVertically; + invalidate(); + } + + public void setMirrorX(boolean mirrorX) { + this.mirrorX = mirrorX; + invalidate(); + } + @SuppressLint("NotifyDataSetChanged") private void setVisibleReactionsList(List visibleReactionsList) { this.visibleReactionsList.clear(); @@ -560,6 +578,17 @@ private void setVisibleReactionsList(List 0) { selectorDrawable = Theme.createRadSelectorDrawable(color, topBottomSelectorRadius, topBottomSelectorRadius); - } else if (selectorRadius > 0) { + } else if (selectorRadius > 0 && selectorType != Theme.RIPPLE_MASK_CIRCLE_20DP) { selectorDrawable = Theme.createSimpleSelectorRoundRectDrawable(selectorRadius, 0, color, 0xff000000); } else if (selectorType == 2) { selectorDrawable = Theme.getSelectorDrawable(color, false); } else { - selectorDrawable = Theme.createSelectorDrawable(color, selectorType); + selectorDrawable = Theme.createSelectorDrawable(color, selectorType, selectorRadius); } selectorDrawable.setCallback(this); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java index a5f2b7c63ac..ff74f81152f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java @@ -662,11 +662,10 @@ public void setImages() { ImageLocation imageLocation; if (object instanceof TLRPC.Document) { - TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(sticker.thumbs, 90); if (!tabView.inited) { tabView.svgThumb = DocumentObject.getSvgThumb((TLRPC.Document) object, Theme.key_emptyListPlaceholder, 0.2f); } - imageLocation = ImageLocation.getForDocument(thumb, sticker); + imageLocation = ImageLocation.getForDocument(sticker); } else if (object instanceof TLRPC.PhotoSize) { TLRPC.PhotoSize thumb = (TLRPC.PhotoSize) object; int thumbVersion = 0; @@ -700,9 +699,9 @@ public void setImages() { } } else if (MessageObject.isAnimatedStickerDocument(sticker, true)) { if (svgThumb != null) { - imageView.setImage(ImageLocation.getForDocument(sticker), imageFilter, svgThumb, 0, parentObject); + imageView.setImage(imageLocation, imageFilter, svgThumb, 0, parentObject); } else { - imageView.setImage(ImageLocation.getForDocument(sticker), imageFilter, imageLocation, null, 0, parentObject); + imageView.setImage(imageLocation, imageFilter, imageLocation, null, 0, parentObject); } } else if (imageLocation.imageType == FileLoader.IMAGE_TYPE_LOTTIE) { imageView.setImage(imageLocation, imageFilter, "tgs", svgThumb, parentObject); @@ -740,6 +739,14 @@ protected void onScrollChanged(int l, int t, int oldl, int oldt) { private Paint selectorPaint = new Paint(); + private boolean showSelected = true; + private AnimatedFloat showSelectedAlpha = new AnimatedFloat(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + + public void showSelected(boolean show) { + this.showSelected = show; + invalidate(); + } + @Override protected void dispatchDraw(Canvas canvas) { final float dif = (stickerTabWidth - stickerTabExpandedWidth); @@ -761,6 +768,8 @@ protected void dispatchDraw(Canvas canvas) { height = getHeight() - AndroidUtilities.dp(50) * (1f - expandProgress); } + float selectedAlpha = showSelectedAlpha.set(showSelected ? 1 : 0); + if (!(isInEditMode() || tabCount == 0) && indicatorHeight >= 0) { float position = currentPositionAnimated.set(currentPosition); int floorPosition = (int) Math.floor(position); @@ -808,6 +817,7 @@ protected void dispatchDraw(Canvas canvas) { tabBounds.set(cx - w / 2, cy - h / 2, cx + w / 2, cy + h / 2); selectorPaint.setColor(0x2effffff & getThemedColor(Theme.key_chat_emojiPanelIcon)); + selectorPaint.setAlpha((int) (selectorPaint.getAlpha() * selectedAlpha)); canvas.drawRoundRect(tabBounds, AndroidUtilities.dp(8), AndroidUtilities.dp(8), selectorPaint); } @@ -909,8 +919,10 @@ public void setUnderlineColorResource(int resId) { } public void setUnderlineHeight(int value) { - underlineHeight = value; - invalidate(); + if (underlineHeight != value) { + underlineHeight = value; + invalidate(); + } } protected void invalidateOverlays() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchDownloadsContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchDownloadsContainer.java index 4feb1e63238..20b1d40192e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchDownloadsContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchDownloadsContainer.java @@ -141,11 +141,12 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { boolean openInPhotoViewer = message.canPreviewDocument(); if (!openInPhotoViewer) { boolean noforwards = message.messageOwner != null && message.messageOwner.noforwards; - if (message.isFromChat()) { - TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-message.getFromChatId()); - if (chat != null) { - noforwards = chat.noforwards; - } + TLRPC.Chat chatTo = messageObject.messageOwner.peer_id.channel_id != 0 ? MessagesController.getInstance(UserConfig.selectedAccount).getChat(messageObject.messageOwner.peer_id.channel_id) : null; + if (chatTo == null) { + chatTo = messageObject.messageOwner.peer_id.chat_id != 0 ? MessagesController.getInstance(UserConfig.selectedAccount).getChat(messageObject.messageOwner.peer_id.chat_id) : null; + } + if (chatTo != null) { + noforwards = chatTo.noforwards; } openInPhotoViewer = openInPhotoViewer || noforwards; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchStateDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchStateDrawable.java new file mode 100644 index 00000000000..7cb4bb7d983 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchStateDrawable.java @@ -0,0 +1,339 @@ +package org.telegram.ui.Components; + +import static org.telegram.messenger.AndroidUtilities.lerp; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; + +import androidx.annotation.IntDef; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.google.zxing.common.detector.MathUtils; + +import org.telegram.messenger.AndroidUtilities; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +public class SearchStateDrawable extends Drawable { + + @IntDef({ State.STATE_SEARCH, State.STATE_BACK, State.STATE_PROGRESS }) + @Retention(RetentionPolicy.SOURCE) + public @interface State { + int STATE_SEARCH = 0; + int STATE_BACK = 1; + int STATE_PROGRESS = 2; + } + + private int alpha = 0xFF; + private Paint paint; + + private Path path = new Path(); + + private RectF progressRect = new RectF(); + private final float progressRadius = .25f; + private long progressStart = -1; + private boolean progressStartedWithOverTo; + private float progressAngleFrom = 0, progressAngleTo = 0; + private float[] progressSegments = new float[2]; + + private @State int fromState; + private @State int toState = State.STATE_SEARCH; + private boolean waitingForProgressToEnd = false, wereNotWaitingForProgressToEnd; + + private AnimatedFloat progress = new AnimatedFloat(1, this::invalidateSelf, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private Runnable delaySetProgress; + + public SearchStateDrawable() { + paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setColor(Color.WHITE); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeJoin(Paint.Join.ROUND); + paint.setStrokeCap(Paint.Cap.ROUND); + paint.setStrokeWidth(AndroidUtilities.dp(1.333f)); + } + + public @State int getIconState() { + return this.toState; + } + + public void setIconState(@State int state) { + setIconState(state, true); + } + public void setIconState(@State int state, boolean animated) { + setIconState(state, animated, false); + } + + private void setIconState(@State int state, boolean animated, boolean skipProgressDelay) { + if (getIconState() == state) { + if (state != State.STATE_PROGRESS) { + AndroidUtilities.cancelRunOnUIThread(delaySetProgress); + delaySetProgress = null; + } + return; + } + + if (!skipProgressDelay && state == State.STATE_PROGRESS) { + if (delaySetProgress == null) { + AndroidUtilities.runOnUIThread(delaySetProgress = () -> { + delaySetProgress = null; + setIconState(state, animated, true); + }, 65); + } + return; + } else if (delaySetProgress != null) { + AndroidUtilities.cancelRunOnUIThread(delaySetProgress); + } + + if (progress.get() < 1 && animated) { + setIconState(toState, false); + } + + if (state == State.STATE_PROGRESS) { + progressAngleFrom = 180; + progressStart = -1; + } else if (toState == State.STATE_PROGRESS) { + if (state == State.STATE_SEARCH) { + progressAngleTo = -45; + } else { + progressAngleTo = 0; + } + } + + if (animated) { + fromState = toState; + toState = state; + waitingForProgressToEnd = fromState == State.STATE_PROGRESS && state != State.STATE_PROGRESS; + progress.set(0, true); + } else { + fromState = toState = state; + waitingForProgressToEnd = false; + progress.set(1, true); + } + invalidateSelf(); + } + + public void setStrokeWidth(float strokeWidth) { + paint.setStrokeWidth(strokeWidth); + } + + public void setColor(int color) { + paint.setColor(color); + } + + @Override + public void draw(@NonNull Canvas canvas) { + final Rect bounds = getBounds(); + this.mn = Math.min(bounds.width(), bounds.height()); + this.cx = bounds.centerX(); + this.cy = bounds.centerY(); + + if (alpha < 0xFF) { + canvas.saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom, alpha, Canvas.ALL_SAVE_FLAG); + } + + float value = progress.set(waitingForProgressToEnd ? 0 : 1); + + float searchValue = toState == State.STATE_SEARCH ? fromState == State.STATE_SEARCH ? 1 : value : fromState == State.STATE_SEARCH ? 1f - value : 0; + float backValue = toState == State.STATE_BACK ? fromState == State.STATE_BACK ? 1 : value : fromState == State.STATE_BACK ? 1f - value : 0; + float progressValue = toState == State.STATE_PROGRESS ? fromState == State.STATE_PROGRESS ? 1 : value : fromState == State.STATE_PROGRESS ? 1f - value : 0; + + if (searchValue > 0) { + // o + drawCircle( + canvas, + lerp(x(.25f), x(.444f), searchValue), + lerp(y(.5f), y(.444f), searchValue), + lerp(0, w(.208f), searchValue) + ); + } + + if (searchValue > 0 || backValue > 0) { + // — + canvas.save(); + canvas.rotate(searchValue * 45, cx, cy); + drawLine( + canvas, + lerp3( + x(.914f), x(.7638f), fromState == State.STATE_PROGRESS ? x(.5f + progressRadius) : x(.2409f), + searchValue, backValue, progressValue + ), y(.5f), + lerp3( + x(.658f), x(.2409f), fromState == State.STATE_PROGRESS ? x(.5f + progressRadius) : x(.2409f), + searchValue, backValue, progressValue + ), y(.5f) + ); + canvas.restore(); + } + + if (backValue > 0) { + // < + float ax = fromState == State.STATE_PROGRESS ? lerp(x(.5f + progressRadius), x(.2409f), backValue) : x(.2409f); + + canvas.save(); + canvas.rotate(searchValue * 45, cx, cy); + drawLines( + canvas, + + ax + x(.2452f) * backValue, + lerp(y(.5f), y(.25f), backValue), + + ax, y(.5f), + + ax + x(.2452f) * backValue, + lerp(y(.5f), y(.75f), backValue) + ); + canvas.restore(); + } + + if (progressValue > 0) { + if (progressStart < 0 && progressValue > .8f) { + progressStart = System.currentTimeMillis(); + wereNotWaitingForProgressToEnd = waitingForProgressToEnd; + } + if (progressStart > 0) { + + CircularProgressDrawable.getSegments( + (System.currentTimeMillis() - progressStart) % 5400f, + progressSegments + ); + float fromAngle = progressSegments[0], toAngle = progressSegments[1]; + if (getIconState() != State.STATE_PROGRESS && !waitingForProgressToEnd) { + float m = Math.max(0, (float) Math.floor((fromAngle - 180) / 360f) * 360f + 180); + toAngle = Math.min(toAngle, m + progressAngleTo); + fromAngle = Math.min(fromAngle, m + progressAngleTo); + fromAngle = lerp(toAngle, fromAngle, progressValue); + } + + boolean progressOverTo = containsAngle(progressAngleTo, progressAngleFrom + fromAngle, progressAngleFrom + toAngle); + if (waitingForProgressToEnd && !wereNotWaitingForProgressToEnd) { + wereNotWaitingForProgressToEnd = waitingForProgressToEnd; + progressStartedWithOverTo = progressOverTo; + } + if (progressStartedWithOverTo && !progressOverTo) { + progressStartedWithOverTo = false; + } + if (waitingForProgressToEnd && progressOverTo && !progressStartedWithOverTo) { + waitingForProgressToEnd = false; + } + + progressRect.set(x(.5f - progressRadius), y(.5f - progressRadius), x(.5f + progressRadius), y(.5f + progressRadius)); + canvas.drawArc( + progressRect, + progressAngleFrom + fromAngle, + toAngle - fromAngle, + false, + paint + ); + + invalidateSelf(); + } + } + + if (alpha < 0xFF) { + canvas.restore(); + } + + if (value < 1) { + invalidateSelf(); + } + } + + private boolean containsAngle(float angle, float angleFrom, float angleTo) { + angleFrom = angleFrom % 360; + if (angleFrom < 0) { + angleFrom = 360 + angleFrom; + } + angleTo = angleTo % 360; + if (angleTo < 0) { + angleTo = 360 + angleTo; + } + if (angleFrom > angleTo) + return angle >= angleFrom || angle <= angleTo; + return angle >= angleFrom && angle <= angleTo; + } + + private void drawCircle(Canvas canvas, float x, float y, float r) { + if (r < w(.075f)) { + return; + } + canvas.drawCircle(x, y, r, paint); + } + + private void drawLine(Canvas canvas, float x1, float y1, float x2, float y2) { + if (MathUtils.distance(x1, y1, x2, y2) <= w(.075f)) { + return; + } + canvas.drawLine(x1, y1, x2, y2, paint); + } + + private void drawLines(Canvas canvas, float x1, float y1, float x2, float y2, float x3, float y3) { + if (Math.max(MathUtils.distance(x1, y1, x2, y2), MathUtils.distance(x3, y3, x2, y2)) <= w(.075f)) { + return; + } + path.rewind(); + path.moveTo(x1, y1); + path.lineTo(x2, y2); + path.lineTo(x3, y3); + canvas.drawPath(path, paint); + } + + private float lerp3( + float x1, + float x2, + float x3, + // t1 + t2 + t3 = 1 + float t1, + float t2, + float t3 + ) { + return x1 * t1 + x2 * t2 + x3 * t3; + } + + private float mn, cx, cy; + + private float x(float t) { + return cx - mn * (.5f - t); + } + + private float y(float t) { + return cy - mn * (.5f - t); + } + + private float w(float t) { + return mn * t; + } + + @Override + public void setAlpha(int alpha) { + this.alpha = alpha; + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + paint.setColorFilter(colorFilter); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + + @Override + public int getIntrinsicWidth() { + return AndroidUtilities.dp(24); + } + + @Override + public int getIntrinsicHeight() { + return AndroidUtilities.dp(24); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java index 90302d6ab12..fbdd47ce859 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java @@ -145,6 +145,14 @@ public void notifyDataSetChanged() { } } }; + if (initialDialogsType == DialogsActivity.DIALOGS_TYPE_BOT_REQUEST_PEER) { + ArrayList dialogs = fragment.getDialogsArray(currentAccount, initialDialogsType, folderId, true); + ArrayList dialogIds = new ArrayList<>(); + for (int i = 0; i < dialogs.size(); ++i) { + dialogIds.add(dialogs.get(i).id); + } + dialogsSearchAdapter.setFilterDialogIds(dialogIds); + } fragmentView = (SizeNotifierFrameLayout) fragment.getFragmentView(); searchListView = new BlurredRecyclerView(context) { @@ -510,7 +518,7 @@ public void onActionBarItemClick(int id) { } else if (id == forwardItemId) { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate((fragment1, dids, message, param) -> { ArrayList fmessages = new ArrayList<>(); @@ -545,13 +553,14 @@ public void onActionBarItemClick(int id) { args1.putLong("chat_id", -did); } if (!AccountInstance.getInstance(currentAccount).getMessagesController().checkCanOpenChat(args1, fragment1)) { - return; + return true; } } ChatActivity chatActivity = new ChatActivity(args1); fragment1.presentFragment(chatActivity, true); chatActivity.showFieldPanelForForward(true, fmessages); } + return true; }); parent.presentFragment(fragment); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarView.java index c6210db571a..ae5c86eacc1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarView.java @@ -66,7 +66,7 @@ public class SeekBarView extends FrameLayout { private float transitionProgress = 1f; private int transitionThumbX; private int separatorsCount; - private int lineWidthDp = 2; + private int lineWidthDp = 3; private boolean twoSided; private final Theme.ResourcesProvider resourcesProvider; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java index 9c8ad6a83f8..cfdadd9d3e8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java @@ -3254,7 +3254,7 @@ public void onActionBarItemClick(View v, int id) { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); args.putBoolean("canSelectTopics", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate((fragment1, dids, message, param) -> { ArrayList fmessages = new ArrayList<>(); @@ -3308,7 +3308,7 @@ public void onActionBarItemClick(View v, int id) { args1.putLong("chat_id", -did); } if (!profileActivity.getMessagesController().checkCanOpenChat(args1, fragment1)) { - return; + return true; } } @@ -3319,6 +3319,7 @@ public void onActionBarItemClick(View v, int id) { fragment1.presentFragment(chatActivity, true); chatActivity.showFieldPanelForForward(true, fmessages); } + return true; }); profileActivity.presentFragment(fragment); } else if (id == gotochat) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleThemeDescription.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleThemeDescription.java index 39efa4c62cb..7c79b6cc4ec 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleThemeDescription.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleThemeDescription.java @@ -18,4 +18,8 @@ public static ArrayList createThemeDescriptions(ThemeDescripti } return l; } + + public static void add(ArrayList descriptions, Runnable upd, String... keys) { + descriptions.addAll(SimpleThemeDescription.createThemeDescriptions(upd::run, keys)); + } } \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerCategoriesListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerCategoriesListView.java new file mode 100644 index 00000000000..0e5024141d1 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerCategoriesListView.java @@ -0,0 +1,956 @@ +package org.telegram.ui.Components; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.OvershootInterpolator; + +import androidx.annotation.IntDef; +import androidx.annotation.NonNull; +import androidx.core.graphics.ColorUtils; +import androidx.recyclerview.widget.LinearLayoutManager; + +import org.telegram.SQLite.SQLiteCursor; +import org.telegram.SQLite.SQLiteDatabase; +import org.telegram.SQLite.SQLitePreparedStatement; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Fetcher; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.R; +import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.NativeByteBuffer; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.HashSet; +import java.util.Set; + +public class StickerCategoriesListView extends RecyclerListView { + + @IntDef({CategoriesType.DEFAULT, CategoriesType.STATUS, CategoriesType.PROFILE_PHOTOS}) + @Retention(RetentionPolicy.SOURCE) + public static @interface CategoriesType { + int DEFAULT = 0; + int STATUS = 1; + int PROFILE_PHOTOS = 2; + } + + private float shownButtonsAtStart = 6.5f; + + private static EmojiGroupFetcher fetcher = new EmojiGroupFetcher(); + public static Fetcher search = new EmojiSearch(); + private EmojiCategory[] categories = null; + + private Adapter adapter; + private LinearLayoutManager layoutManager; + + private AnimatedFloat leftBoundAlpha = new AnimatedFloat(this, 360, CubicBezierInterpolator.EASE_OUT_QUINT); + private AnimatedFloat rightBoundAlpha = new AnimatedFloat(this, 360, CubicBezierInterpolator.EASE_OUT_QUINT); + private Drawable leftBoundDrawable; + private Drawable rightBoundDrawable; + private Paint backgroundPaint; + + @CategoriesType + private int categoriesType; + private static Set loadedIconsType = new HashSet<>(); + + private Paint selectedPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + private int paddingWidth; + private int dontOccupyWidth; + private Utilities.Callback onScrollIntoOccupiedWidth; + private Utilities.Callback onScrollFully; + private boolean scrolledIntoOccupiedWidth; + private boolean scrolledFully; + + private View paddingView; + + public Integer layerNum; + + private int selectedCategoryIndex = -1; + private Utilities.Callback onCategoryClick; + + public static void preload(int account, @CategoriesType int type) { + fetcher.fetch(account, type, emojiGroups -> { + for (TLRPC.TL_emojiGroup group : emojiGroups.groups) { + AnimatedEmojiDrawable.getDocumentFetcher(account).fetchDocument(group.icon_emoji_id, null); + } + }); + } + + public StickerCategoriesListView(Context context, @CategoriesType int categoriesType) { + this(context, null, categoriesType, null); + } + + public StickerCategoriesListView(Context context, @CategoriesType int categoriesType, Theme.ResourcesProvider resourcesProvider) { + this(context, null, categoriesType, resourcesProvider); + } + + public StickerCategoriesListView(Context context, EmojiCategory[] additionalCategories, @CategoriesType int categoriesType) { + this(context, additionalCategories, categoriesType, null); + } + + public StickerCategoriesListView(Context context, EmojiCategory[] additionalCategories, @CategoriesType int categoriesType, Theme.ResourcesProvider resourcesProvider) { + super(context, resourcesProvider); + + this.categoriesType = categoriesType; + setPadding(0, 0, dp(2), 0); + + setAdapter(adapter = new Adapter()); + setLayoutManager(layoutManager = new LinearLayoutManager(context)); + layoutManager.setOrientation(HORIZONTAL); + +// setSelectorRadius(dp(15)); +// setSelectorType(Theme.RIPPLE_MASK_CIRCLE_20DP); +// setSelectorDrawableColor(getThemedColor(Theme.key_listSelector)); + selectedPaint.setColor(getThemedColor(Theme.key_listSelector)); + setSelectorDrawableColor(0); + + setWillNotDraw(false); + + setOnItemClickListener((view, position) -> onItemClick(position, view)); + + long start = System.currentTimeMillis(); + fetcher.fetch(UserConfig.selectedAccount, categoriesType, (emojiGroups) -> { + if (emojiGroups != null) { + categories = new EmojiCategory[(additionalCategories == null ? 0 : additionalCategories.length) + emojiGroups.groups.size()]; + int i = 0; + if (additionalCategories != null) { + for (; i < additionalCategories.length; ++i) { + categories[i] = additionalCategories[i]; + } + } + for (int j = 0; j < emojiGroups.groups.size(); ++j) { + categories[i + j] = EmojiCategory.remote(emojiGroups.groups.get(j)); + } + adapter.notifyDataSetChanged(); + setCategoriesShownT(0); + updateCategoriesShown(categoriesShouldShow, System.currentTimeMillis() - start > 16); + } + }); + } + + public void setShownButtonsAtStart(float buttonsCount) { + shownButtonsAtStart = buttonsCount; + } + + private void onItemClick(int position, View view) { + if (position < 1) { + return; + } + + if (categories == null) { + return; + } + + EmojiCategory category = categories[position - 1]; + int minimumPadding = dp(64); + if (getMeasuredWidth() - view.getRight() < minimumPadding) { + smoothScrollBy((minimumPadding - (getMeasuredWidth() - view.getRight())), 0, CubicBezierInterpolator.EASE_OUT_QUINT); + } else if (view.getLeft() < minimumPadding) { + smoothScrollBy(-(minimumPadding - view.getLeft()), 0, CubicBezierInterpolator.EASE_OUT_QUINT); + } + if (onCategoryClick != null) { + onCategoryClick.run(category); + } + } + + private int getScrollToStartWidth() { + if (getChildCount() > 0) { + View child = getChildAt(0); + if (child instanceof CategoryButton) { + return paddingWidth + Math.max(0, (getChildAdapterPosition(child) - 1) * getHeight()) + (-child.getLeft()); + } else { + return -child.getLeft(); + } + } + return 0; + } + + public void scrollToStart() { + smoothScrollBy(-getScrollToStartWidth(), 0, CubicBezierInterpolator.EASE_OUT_QUINT); + } + + public void selectCategory(EmojiCategory category) { + int index = -1; + if (categories != null) { + for (int i = 0; i < categories.length; ++i) { + if (categories[i] == category) { + index = i; + break; + } + } + } + selectCategory(index); + } + + public void selectCategory(int categoryIndex) { + if (selectedCategoryIndex < 0) { + selectedIndex.set(categoryIndex, true); + } + this.selectedCategoryIndex = categoryIndex; + for (int i = 0; i < getChildCount(); ++i) { + View child = getChildAt(i); + if (child instanceof CategoryButton) { + final int position = getChildAdapterPosition(child); + ((CategoryButton) child).setSelected(selectedCategoryIndex == position - 1, true); + } + } + invalidate(); + } + + public EmojiCategory getSelectedCategory() { + if (categories == null || selectedCategoryIndex < 0 || selectedCategoryIndex >= categories.length) { + return null; + } + return categories[selectedCategoryIndex]; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + updateCategoriesShown(categoriesShouldShow, false); + } + + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + if (paddingView != null) { + paddingView.requestLayout(); + } + } + + private float categoriesShownT = 0; + private ValueAnimator categoriesShownAnimator; + private boolean categoriesShouldShow = true; + public void updateCategoriesShown(boolean show, boolean animated) { + categoriesShouldShow = show; + if (categories == null) { + show = false; + } + + if (categoriesShownT == (show ? 1 : 0)) { + return; + } + + if (categoriesShownAnimator != null) { + categoriesShownAnimator.cancel(); + categoriesShownAnimator = null; + } + + if (animated) { + categoriesShownAnimator = ValueAnimator.ofFloat(categoriesShownT, show ? 1 : 0); + categoriesShownAnimator.addUpdateListener(anm -> { + setCategoriesShownT((float) anm.getAnimatedValue()); + }); + categoriesShownAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + setCategoriesShownT((float) categoriesShownAnimator.getAnimatedValue()); + categoriesShownAnimator = null; + } + }); + categoriesShownAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + categoriesShownAnimator.setDuration((categories == null ? 5 : categories.length) * 120L); + categoriesShownAnimator.start(); + } else { + setCategoriesShownT(show ? 1 : 0); + } + } + + private void setCategoriesShownT(float t) { + categoriesShownT = t; + + for (int i = 0; i < getChildCount(); ++i) { + View child = getChildAt(i); + if (child instanceof CategoryButton) { + int position = getChildAdapterPosition(child); + float childT = AndroidUtilities.cascade(t, getChildCount() - 1 - position, getChildCount() - 1, 3f); + if (childT > 0 && child.getAlpha() <= 0) { + ((CategoryButton) child).play(); + } + child.setAlpha(childT); + child.setScaleX(childT); + child.setScaleY(childT); + } + } + + invalidate(); + } + + public boolean isCategoriesShown() { + return categoriesShownT > .5f; + } + + @Override + public void onScrolled(int dx, int dy) { + super.onScrolled(dx, dy); + + boolean scrolledIntoOccupiedWidth = false; + boolean scrolledFully = false; + if (getChildCount() > 0) { + View child = getChildAt(0); + if (child instanceof CategoryButton) { + scrolledIntoOccupiedWidth = true; + scrolledFully = true; + } else { + scrolledIntoOccupiedWidth = child.getRight() <= dontOccupyWidth; + } + } + if (this.scrolledIntoOccupiedWidth != scrolledIntoOccupiedWidth) { + this.scrolledIntoOccupiedWidth = scrolledIntoOccupiedWidth; + if (onScrollIntoOccupiedWidth != null) { + onScrollIntoOccupiedWidth.run(this.scrolledIntoOccupiedWidth ? Math.max(0, getScrollToStartWidth() - (paddingWidth - dontOccupyWidth)) : 0); + } + invalidate(); + } else if (this.scrolledIntoOccupiedWidth && onScrollIntoOccupiedWidth != null) { + onScrollIntoOccupiedWidth.run(Math.max(0, getScrollToStartWidth() - (paddingWidth - dontOccupyWidth))); + } + if (this.scrolledFully != scrolledFully) { + this.scrolledFully = scrolledFully; + if (onScrollFully != null) { + onScrollFully.run(this.scrolledFully); + } + invalidate(); + } + } + + public void setDontOccupyWidth(int dontOccupyWidth) { + this.dontOccupyWidth = dontOccupyWidth; + } + + public void setOnScrollIntoOccupiedWidth(Utilities.Callback onScrollIntoOccupiedWidth) { + this.onScrollIntoOccupiedWidth = onScrollIntoOccupiedWidth; + } + + public void setOnScrollFully(Utilities.Callback onScrollFully) { + this.onScrollFully = onScrollFully; + } + + public void setOnCategoryClick(Utilities.Callback onCategoryClick) { + this.onCategoryClick = onCategoryClick; + } + + public boolean isScrolledIntoOccupiedWidth() { + return scrolledIntoOccupiedWidth; + } + + @Override + public void setBackgroundColor(int color) { + if (backgroundPaint == null) { + backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + } + backgroundPaint.setColor(color); + leftBoundDrawable = getContext().getResources().getDrawable(R.drawable.gradient_right).mutate(); + leftBoundDrawable.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY)); + rightBoundDrawable = getContext().getResources().getDrawable(R.drawable.gradient_left).mutate(); + rightBoundDrawable.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY)); + } + + private AnimatedFloat selectedAlpha = new AnimatedFloat(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + private AnimatedFloat selectedIndex = new AnimatedFloat(this, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + + @Override + public void draw(Canvas canvas) { + + if (backgroundPaint != null) { + int left = Integer.MAX_VALUE; + int right = Integer.MIN_VALUE; + + for (int i = 0; i < getChildCount(); ++i) { + final View child = getChildAt(i); + if (child instanceof CategoryButton) { + left = Math.min(left, child.getLeft()); + right = Math.max(right, child.getRight()); + } + } + + if (left < right) { + left += (getWidth() + dp(32)) * (1f - categoriesShownT); + right += (getWidth() + dp(32)) * (1f - categoriesShownT); + +// if (left > 0 && rightBoundDrawable != null) { +// rightBoundDrawable.setAlpha(0xFF); +// rightBoundDrawable.setBounds(left - rightBoundDrawable.getIntrinsicWidth(), 0, left, getHeight()); +// rightBoundDrawable.draw(canvas); +// } + canvas.drawRect(left, 0, right, getHeight(), backgroundPaint); + if (right < getWidth() && leftBoundDrawable != null) { + leftBoundDrawable.setAlpha(0xFF); + leftBoundDrawable.setBounds(right, 0, right + leftBoundDrawable.getIntrinsicWidth(), getHeight()); + leftBoundDrawable.draw(canvas); + } + } + } + + drawSelectedHighlight(canvas); + + super.draw(canvas); + + if (leftBoundDrawable != null) { + leftBoundDrawable.setAlpha((int) (0xFF * leftBoundAlpha.set(canScrollHorizontally(-1) && scrolledFully ? 1 : 0) * categoriesShownT)); + if (leftBoundDrawable.getAlpha() > 0) { + leftBoundDrawable.setBounds(0, 0, leftBoundDrawable.getIntrinsicWidth(), getHeight()); + leftBoundDrawable.draw(canvas); + } + } + +// if (rightBoundDrawable != null) { +// rightBoundDrawable.setAlpha((int) (0xFF * rightBoundAlpha.set(canScrollHorizontally(1) ? 1 : 0) * categoriesShownT)); +// if (rightBoundDrawable.getAlpha() > 0) { +// rightBoundDrawable.setBounds(getWidth() - rightBoundDrawable.getIntrinsicWidth(), 0, getWidth(), getHeight()); +// rightBoundDrawable.draw(canvas); +// } +// } + } + + private RectF rect1 = new RectF(), rect2 = new RectF(), rect3 = new RectF(); + private void drawSelectedHighlight(Canvas canvas) { + float alpha = selectedAlpha.set(selectedCategoryIndex >= 0 ? 1 : 0); + float index = selectedCategoryIndex >= 0 ? selectedIndex.set(selectedCategoryIndex) : selectedIndex.get(); + + if (alpha <= 0) { + return; + } + + int fromPosition = Math.max(1, (int) Math.floor(index + 1)); + int toPosition = Math.max(1, (int) Math.ceil(index + 1)); + + View fromChild = null, toChild = null; + + for (int i = 0; i < getChildCount(); ++i) { + View child = getChildAt(i); + int position = getChildAdapterPosition(child); + + if (position == fromPosition) { + fromChild = child; + } + if (position == toPosition) { + toChild = child; + } + + if (fromChild != null && toChild != null) { + break; + } + } + + int wasAlpha = selectedPaint.getAlpha(); + selectedPaint.setAlpha((int) (wasAlpha * alpha)); + if (fromChild != null && toChild != null) { + float t = fromPosition == toPosition ? .5f : (index + 1 - fromPosition) / (toPosition - fromPosition); + getChildBounds(fromChild, rect1); + getChildBounds(toChild, rect2); + AndroidUtilities.lerp(rect1, rect2, t, rect3); +// float T = selectedIndex.getTransitionProgress(); +// float isMiddle = 4f * T * (1f - T); +// float hw = rect3.width() / 2 * (1f + isMiddle * .05f); +// float hh = rect3.height() / 2 * (1f - isMiddle * .1f); +// rect3.set(rect3.centerX() - hw, rect3.centerY() - hh, rect3.centerX() + hw, rect3.centerY() + hh); + canvas.drawRoundRect(rect3, AndroidUtilities.dp(15), AndroidUtilities.dp(15), selectedPaint); + } + selectedPaint.setAlpha(wasAlpha); + } + + private void getChildBounds(View child, RectF rect) { + float cx = (child.getRight() + child.getLeft()) / 2f; + float cy = (child.getBottom() + child.getTop()) / 2f; + float r = child.getWidth() / 2f - dp(1); + float s = child instanceof CategoryButton ? ((CategoryButton) child).getScale() : 1f; + rect.set( + cx - r * s, cy - r * s, + cx + r * s, cy + r * s + ); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + final View child = findChildViewUnder(ev.getX(), ev.getY()); + if (!(child instanceof CategoryButton) || child.getAlpha() < .5f) { + return false; + } + } + return super.dispatchTouchEvent(ev); + } + + private class Adapter extends RecyclerListView.SelectionAdapter { + + private static final int VIEW_TYPE_PADDING = 0; + private static final int VIEW_TYPE_CATEGORY = 1; + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + if (viewType == VIEW_TYPE_PADDING) { + view = paddingView = new View(getContext()) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int fullWidth = MeasureSpec.getSize(widthMeasureSpec); + if (fullWidth <= 0) { + fullWidth = ((View) getParent()).getMeasuredWidth(); + } + final int BUTTON_WIDTH = MeasureSpec.getSize(heightMeasureSpec) - dp(4); + super.onMeasure( + MeasureSpec.makeMeasureSpec( + paddingWidth = Math.max( + dontOccupyWidth > 0 ? dontOccupyWidth + dp(4) : 0, + (int) (fullWidth - Math.min((getItemCount() - 1) * BUTTON_WIDTH + dp(4), shownButtonsAtStart * BUTTON_WIDTH)) + ), + MeasureSpec.EXACTLY + ), + heightMeasureSpec + ); + } + }; + } else { + view = new CategoryButton(getContext()); + } + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + if (holder.getItemViewType() == VIEW_TYPE_CATEGORY && categories != null) { + final EmojiCategory category = categories[position - 1]; + final CategoryButton button = (CategoryButton) holder.itemView; + button.set(category, position - 1, selectedCategoryIndex == position - 1); + button.setAlpha(categoriesShownT); + button.setScaleX(categoriesShownT); + button.setScaleY(categoriesShownT); + button.play(); + } + } + + @Override + public void onViewAttachedToWindow(@NonNull ViewHolder holder) { + if (holder.getItemViewType() == VIEW_TYPE_CATEGORY) { + final CategoryButton button = (CategoryButton) holder.itemView; + final int position = holder.getAdapterPosition(); + button.setSelected(selectedCategoryIndex == position - 1, false); + button.play(); + } + } + + @Override + public int getItemViewType(int position) { + return position == 0 ? VIEW_TYPE_PADDING : VIEW_TYPE_CATEGORY; + } + + private int lastItemCount; + + @Override + public int getItemCount() { + final int itemCount = 1 + (categories == null ? 0 : categories.length); + if (itemCount != lastItemCount) { + if (paddingView != null) { + paddingView.requestLayout(); + } + lastItemCount = itemCount; + } + return itemCount; + } + + @Override + public boolean isEnabled(ViewHolder holder) { + return holder.getItemViewType() == VIEW_TYPE_CATEGORY; + } + } + + protected boolean isTabIconsAnimationEnabled(boolean loaded) { + return !SharedConfig.getLiteMode().enabled() && !loaded; + } + + static int loadedCategoryIcons = 0; + + private class CategoryButton extends RLottieImageView { + + private int imageColor; + private float selectedT; + private ValueAnimator selectedAnimator; + private int index; + + public CategoryButton(Context context) { + super(context); + + setImageColor(getThemedColor(Theme.key_chat_emojiPanelIcon)); + setScaleType(ScaleType.CENTER); + + setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), Theme.RIPPLE_MASK_CIRCLE_20DP, dp(15))); + + setLayerNum(layerNum); + } + + public void set(EmojiCategory category, int index, boolean selected) { + this.index = index; + if (loadAnimator != null) { + loadAnimator.cancel(); + loadAnimator = null; + } + if (category.remote) { + setImageResource(0); +// cached = true; + clearAnimationDrawable(); + boolean animated = isTabIconsAnimationEnabled(true); + loaded = false; + loadProgress = 1; + AnimatedEmojiDrawable.getDocumentFetcher(UserConfig.selectedAccount) + .fetchDocument(category.documentId, document -> { + setOnlyLastFrame(!animated); + setAnimation(document, 24, 24); + playAnimation(); + }); + AndroidUtilities.runOnUIThread(() -> { + if (!loaded) { + loadProgress = 0; + } + }, 60); + } else if (category.animated) { + cached = false; + setImageResource(0); + setAnimation(category.iconResId, 24, 24); + playAnimation(); + loadProgress = 1; + } else { + clearAnimationDrawable(); + setImageResource(category.iconResId); + loadProgress = 1; + } + setSelected(selected, false); + } + + private boolean loaded = false; + + @Override + protected void onLoaded() { + loaded = true; + if (loadProgress < 1) { + if (loadAnimator != null) { + loadAnimator.cancel(); + loadAnimator = null; + } + loadAnimator = ValueAnimator.ofFloat(loadProgress, 1f); + loadAnimator.addUpdateListener(anm -> { + loadProgress = (float) anm.getAnimatedValue(); + invalidate(); + }); + loadAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + loadProgress = 1f; + invalidate(); + loadAnimator = null; + } + }); + loadAnimator.setDuration(320); + loadAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + loadAnimator.start(); + } + } + + public void setSelected(boolean selected, boolean animated) { + if (Math.abs(selectedT - (selected ? 1 : 0)) > .01f) { + if (selectedAnimator != null) { + selectedAnimator.cancel(); + selectedAnimator = null; + } + + if (animated) { + selectedAnimator = ValueAnimator.ofFloat(selectedT, selected ? 1 : 0); + selectedAnimator.addUpdateListener(anm -> { + updateSelectedT((float) anm.getAnimatedValue()); + }); + selectedAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + updateSelectedT((float) selectedAnimator.getAnimatedValue()); + selectedAnimator = null; + } + }); + selectedAnimator.setDuration(350); + selectedAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + selectedAnimator.start(); + } else { + updateSelectedT(selected ? 1 : 0); + } + } + } + + private void updateSelectedT(float t) { + selectedT = t; + setImageColor( + ColorUtils.blendARGB( + getThemedColor(Theme.key_chat_emojiPanelIcon), + getThemedColor(Theme.key_chat_emojiPanelIconSelected), + selectedT + ) + ); + invalidate(); + } + + public void setImageColor(int color) { + if (imageColor != color) { + setColorFilter(new PorterDuffColorFilter(imageColor = color, PorterDuff.Mode.MULTIPLY)); + } + } + + @Override + public void draw(Canvas canvas) { + updatePressedProgress(); + float scale = getScale(); + if (scale != 1) { + canvas.save(); + canvas.scale(scale, scale, getMeasuredWidth() / 2f, getMeasuredHeight() / 2f); + } + super.draw(canvas); + if (scale != 1) { + canvas.restore(); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int size = MeasureSpec.getSize(heightMeasureSpec); + super.onMeasure( + MeasureSpec.makeMeasureSpec(size - dp(4), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY) + ); + } + + private long lastPlayed; + public void play() { + if (System.currentTimeMillis() - lastPlayed > 250) { + lastPlayed = System.currentTimeMillis(); + RLottieDrawable drawable = getAnimatedDrawable(); + if (drawable == null && getImageReceiver() != null) { + drawable = getImageReceiver().getLottieAnimation(); + } + if (drawable != null) { + drawable.stop(); + drawable.setCurrentFrame(0); + drawable.restart(true); + } else if (drawable == null) { + setProgress(0); + playAnimation(); + } + } + } + + float loadProgress = 1f; + float pressedProgress; + ValueAnimator backAnimator; + ValueAnimator loadAnimator; + + public void updatePressedProgress() { + if (isPressed() && pressedProgress != 1f) { + pressedProgress = Utilities.clamp(pressedProgress + (1000f / AndroidUtilities.screenRefreshRate) / 100f, 1f, 0); + invalidate(); + StickerCategoriesListView.this.invalidate(); + } + } + + public float getScale() { + return (0.85f + 0.15f * (1f - pressedProgress)) * loadProgress; + } + + @Override + public void setPressed(boolean pressed) { + if (isPressed() != pressed) { + super.setPressed(pressed); + invalidate(); + StickerCategoriesListView.this.invalidate(); + if (pressed) { + if (backAnimator != null) { + backAnimator.removeAllListeners(); + backAnimator.cancel(); + } + } + if (!pressed && pressedProgress != 0) { + backAnimator = ValueAnimator.ofFloat(pressedProgress, 0); + backAnimator.addUpdateListener(animation -> { + pressedProgress = (float) animation.getAnimatedValue(); + invalidate(); + }); + backAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + backAnimator = null; + } + }); + backAnimator.setInterpolator(new OvershootInterpolator(3.0f)); + backAnimator.setDuration(350); + backAnimator.start(); + } + } + } + } + + public static class EmojiCategory { + + public boolean animated; + public int iconResId; + public String emojis; + + public boolean remote; + public long documentId; + + public String title; + + public static EmojiCategory withAnimatedIcon(int animatedIconResId, String emojis) { + EmojiCategory category = new EmojiCategory(); + category.animated = true; + category.iconResId = animatedIconResId; + category.emojis = emojis; + return category; + } + + public static EmojiCategory withIcon(int iconResId, String emojis) { + EmojiCategory category = new EmojiCategory(); + category.animated = false; + category.iconResId = iconResId; + category.emojis = emojis; + return category; + } + + public static EmojiCategory remote(TLRPC.TL_emojiGroup group) { + EmojiCategory category = new EmojiCategory(); + category.remote = true; + category.documentId = group.icon_emoji_id; + category.emojis = TextUtils.concat(group.emoticons.toArray(new String[0])).toString(); + category.title = group.title; + return category; + } + } + + private static class EmojiGroupFetcher extends Fetcher { + + @Override + protected void getRemote(int currentAccount, @CategoriesType Integer type, long hash, Utilities.Callback3 onResult) { + TLObject req; + if (type == CategoriesType.STATUS) { + req = new TLRPC.TL_messages_getEmojiStatusGroups(); + ((TLRPC.TL_messages_getEmojiStatusGroups) req).hash = (int) hash; + } else if (type == CategoriesType.PROFILE_PHOTOS) { + req = new TLRPC.TL_messages_getEmojiProfilePhotoGroups(); + ((TLRPC.TL_messages_getEmojiProfilePhotoGroups) req).hash = (int) hash; + } else { + req = new TLRPC.TL_messages_getEmojiGroups(); + ((TLRPC.TL_messages_getEmojiGroups) req).hash = (int) hash; + } + + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> { + if (res instanceof TLRPC.TL_messages_emojiGroupsNotModified) { + onResult.run(true, null, 0L); + } else if (res instanceof TLRPC.TL_messages_emojiGroups) { + TLRPC.TL_messages_emojiGroups result = (TLRPC.TL_messages_emojiGroups) res; + onResult.run(false, result, (long) result.hash); + } else { + onResult.run(false, null, 0L); + } + }); + } + + @Override + protected void getLocal(int currentAccount, Integer type, Utilities.Callback2 onResult) { + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + SQLiteCursor cursor = null; + try { + SQLiteDatabase database = MessagesStorage.getInstance(currentAccount).getDatabase(); + if (database != null) { + TLRPC.messages_EmojiGroups maybeResult = null; + cursor = database.queryFinalized("SELECT data FROM emoji_groups WHERE type = ?", type); + if (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + maybeResult = TLRPC.messages_EmojiGroups.TLdeserialize(data, data.readInt32(false), true); + data.reuse(); + } + } + + if (!(maybeResult instanceof TLRPC.TL_messages_emojiGroups)) { + onResult.run(0L, null); + } else { + TLRPC.TL_messages_emojiGroups result = (TLRPC.TL_messages_emojiGroups) maybeResult; + onResult.run((long) result.hash, result); + } + } + } catch (Exception e) { + FileLog.e(e); + onResult.run(0L, null); + } finally { + if (cursor != null) { + cursor.dispose(); + } + } + }); + } + + @Override + protected void setLocal(int currentAccount, Integer type, TLRPC.TL_messages_emojiGroups data, long hash) { + MessagesStorage.getInstance(currentAccount).getStorageQueue().postRunnable(() -> { + try { + SQLiteDatabase database = MessagesStorage.getInstance(currentAccount).getDatabase(); + if (database != null) { + if (data == null) { + database.executeFast("DELETE FROM emoji_groups WHERE type = " + type).stepThis().dispose(); + } else { + SQLitePreparedStatement state = database.executeFast("REPLACE INTO emoji_groups VALUES(?, ?)"); + state.requery(); + NativeByteBuffer buffer = new NativeByteBuffer(data.getObjectSize()); + data.serializeToStream(buffer); + state.bindInteger(1, type); + state.bindByteBuffer(2, buffer); + state.step(); + buffer.reuse(); + state.dispose(); + } + } + } catch (Exception e) { + FileLog.e(e); + } + }); + } + } + + private static class EmojiSearch extends Fetcher { + @Override + protected void getRemote(int currentAccount, String query, long hash, Utilities.Callback3 onResult) { + TLRPC.TL_messages_searchCustomEmoji req = new TLRPC.TL_messages_searchCustomEmoji(); + req.emoticon = query; + req.hash = hash; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> { + if (res instanceof TLRPC.TL_emojiListNotModified) { + onResult.run(true, null, 0L); + } else if (res instanceof TLRPC.TL_emojiList) { + TLRPC.TL_emojiList list = (TLRPC.TL_emojiList) res; + onResult.run(false, list, list.hash); + } else { + onResult.run(false, null, 0L); + } + }); + } + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerMasksAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerMasksAlert.java index 00cc9d2a8cc..cfdd98c7218 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerMasksAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerMasksAlert.java @@ -142,7 +142,7 @@ public void sendSticker(TLRPC.Document sticker, String query, Object parent, boo } @Override - public boolean needSend() { + public boolean needSend(int contentType) { return false; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerSetBulletinLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerSetBulletinLayout.java index af281cb38c3..e911a5c4c75 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerSetBulletinLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickerSetBulletinLayout.java @@ -3,6 +3,9 @@ import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; +import android.graphics.Color; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import androidx.annotation.IntDef; import androidx.annotation.NonNull; @@ -122,6 +125,10 @@ public StickerSetBulletinLayout(@NonNull Context context, TLObject setObject, in imageView.setImage(null, null, "webp", null, setObject); } + if (MessageObject.isTextColorEmoji(sticker)) { + imageView.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)); + } + switch (type) { case TYPE_ADDED: if (stickerSet != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java index d039e8215ba..86db403bb6d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java @@ -206,7 +206,7 @@ public void remove(SendMessagesHelper.ImportingSticker importingSticker) { } @Override - public boolean needSend() { + public boolean needSend(int contentType) { return delegate != null; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StorageDiagramView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StorageDiagramView.java index d6a9beb5941..e36918ef49b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StorageDiagramView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StorageDiagramView.java @@ -271,10 +271,10 @@ protected void onDraw(Canvas canvas) { text1.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); text2.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); if (dialogId != null) { - int textWidth = text1.getCurrentWidth() + AndroidUtilities.dp(4) + text2.getCurrentWidth(); - int leftpad = (getWidth() - textWidth) / 2; - text1.setBounds(0, AndroidUtilities.dp(115), leftpad + text1.getCurrentWidth(), AndroidUtilities.dp(115 + 30)); - text2.setBounds(leftpad + textWidth - text2.getCurrentWidth(), AndroidUtilities.dp(115 + 3), getWidth(), AndroidUtilities.dp(115 + 3 + 30)); + float textWidth = text1.getCurrentWidth() + AndroidUtilities.dp(4) + text2.getCurrentWidth(); + float leftpad = (getWidth() - textWidth) / 2; + text1.setBounds(0, AndroidUtilities.dp(115), (int) (leftpad + text1.getCurrentWidth()), AndroidUtilities.dp(115 + 30)); + text2.setBounds((int) (leftpad + textWidth - text2.getCurrentWidth()), AndroidUtilities.dp(115 + 3), getWidth(), AndroidUtilities.dp(115 + 3 + 30)); } text1.draw(canvas); text2.draw(canvas); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SuggestEmojiView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SuggestEmojiView.java index 919000dbc26..3b014dfbe21 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SuggestEmojiView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SuggestEmojiView.java @@ -11,6 +11,7 @@ import android.text.Editable; import android.text.Spannable; import android.text.SpannableString; +import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextWatcher; import android.view.Gravity; @@ -29,12 +30,20 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.Emoji; +import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.ContentPreviewViewer; import java.util.ArrayList; import java.util.Arrays; @@ -67,9 +76,9 @@ public void setVisibility(int visibility) { boolean visible = visibility == View.VISIBLE; for (int i = 0; i < listView.getChildCount(); ++i) { if (visible) { - ((Adapter.EmojiImageView) listView.getChildAt(i)).attach(); + ((EmojiImageView) listView.getChildAt(i)).attach(); } else { - ((Adapter.EmojiImageView) listView.getChildAt(i)).detach(); + ((EmojiImageView) listView.getChildAt(i)).detach(); } } } @@ -79,6 +88,117 @@ public void setVisibility(int visibility) { private final Adapter adapter; private final LinearLayoutManager layout; + private ContentPreviewViewer.ContentPreviewViewerDelegate previewDelegate = new ContentPreviewViewer.ContentPreviewViewerDelegate() { + @Override + public boolean can() { + return true; + } + + @Override + public boolean needSend(int contentType) { + if (enterView == null) { + return false; + } + ChatActivity fragment = enterView.getParentFragment(); + return fragment != null && fragment.canSendMessage() && (UserConfig.getInstance(UserConfig.selectedAccount).isPremium() || fragment.getCurrentUser() != null && UserObject.isUserSelf(fragment.getCurrentUser())); + } + + @Override + public void sendEmoji(TLRPC.Document emoji) { + if (enterView == null) { + return; + } + ChatActivity fragment = enterView.getParentFragment(); + fragment.sendAnimatedEmoji(emoji, true, 0); + enterView.setFieldText(""); + } + + @Override + public boolean needCopy() { + return UserConfig.getInstance(UserConfig.selectedAccount).isPremium(); + } + + @Override + public void copyEmoji(TLRPC.Document document) { + Spannable spannable = SpannableStringBuilder.valueOf(MessageObject.findAnimatedEmojiEmoticon(document)); + spannable.setSpan(new AnimatedEmojiSpan(document, null), 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + if (AndroidUtilities.addToClipboard(spannable) && enterView != null) { + BulletinFactory.of(enterView.getParentFragment()).createCopyBulletin(LocaleController.getString("EmojiCopied", R.string.EmojiCopied)).show(); + } + } + + @Override + public Boolean canSetAsStatus(TLRPC.Document document) { + if (!UserConfig.getInstance(UserConfig.selectedAccount).isPremium()) { + return null; + } + TLRPC.User user = UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser(); + if (user == null) { + return null; + } + Long emojiStatusId = UserObject.getEmojiStatusDocumentId(user); + return document != null && (emojiStatusId == null || emojiStatusId != document.id); + } + + @Override + public void setAsEmojiStatus(TLRPC.Document document, Integer until) { + TLRPC.EmojiStatus status; + if (document == null) { + status = new TLRPC.TL_emojiStatusEmpty(); + } else if (until != null) { + status = new TLRPC.TL_emojiStatusUntil(); + ((TLRPC.TL_emojiStatusUntil) status).document_id = document.id; + ((TLRPC.TL_emojiStatusUntil) status).until = until; + } else { + status = new TLRPC.TL_emojiStatus(); + ((TLRPC.TL_emojiStatus) status).document_id = document.id; + } + TLRPC.User user = UserConfig.getInstance(UserConfig.selectedAccount).getCurrentUser(); + final TLRPC.EmojiStatus previousEmojiStatus = user == null ? new TLRPC.TL_emojiStatusEmpty() : user.emoji_status; + MessagesController.getInstance(currentAccount).updateEmojiStatus(status); + + Runnable undoAction = () -> MessagesController.getInstance(currentAccount).updateEmojiStatus(previousEmojiStatus); + BaseFragment fragment = enterView == null ? null : enterView.getParentFragment(); + if (fragment != null) { + if (document == null) { + final Bulletin.SimpleLayout layout = new Bulletin.SimpleLayout(getContext(), resourcesProvider); + layout.textView.setText(LocaleController.getString("RemoveStatusInfo", R.string.RemoveStatusInfo)); + layout.imageView.setImageResource(R.drawable.msg_settings_premium); + Bulletin.UndoButton undoButton = new Bulletin.UndoButton(getContext(), true, resourcesProvider); + undoButton.setUndoAction(undoAction); + layout.setButton(undoButton); + Bulletin.make(fragment, layout, Bulletin.DURATION_SHORT).show(); + } else { + BulletinFactory.of(fragment).createEmojiBulletin(document, LocaleController.getString("SetAsEmojiStatusInfo", R.string.SetAsEmojiStatusInfo), LocaleController.getString("Undo", R.string.Undo), undoAction).show(); + } + } + } + + @Override + public boolean canSchedule() { + return false; +// return delegate != null && delegate.canSchedule(); + } + + @Override + public boolean isInScheduleMode() { + if (enterView == null) { + return false; + } + ChatActivity fragment = enterView.getParentFragment(); + return fragment.isInScheduleMode(); + } + + @Override + public void openSet(TLRPC.InputStickerSet set, boolean clearsInputField) {} + + @Override + public long getDialogId() { + return 0; + } + }; + + private boolean show, forceClose; private ArrayList keywordResults = new ArrayList<>(); private boolean clear; @@ -102,6 +222,12 @@ public void onScrolled(int dx, int dy) { this.right = right; } } + + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + boolean result = ContentPreviewViewer.getInstance().onInterceptTouchEvent(event, listView, 0, previewDelegate, resourcesProvider); + return super.onInterceptTouchEvent(event) || result; + } }; this.listView.setAdapter(this.adapter = new Adapter()); this.layout = new LinearLayoutManager(context); @@ -112,9 +238,11 @@ public void onScrolled(int dx, int dy) { itemAnimator.setTranslationInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); this.listView.setItemAnimator(itemAnimator); this.listView.setSelectorDrawableColor(Theme.getColor(Theme.key_listSelector, resourcesProvider)); - this.listView.setOnItemClickListener((view, position) -> { - onClick(((Adapter.EmojiImageView) view).emoji); + RecyclerListView.OnItemClickListener onItemClickListener; + this.listView.setOnItemClickListener(onItemClickListener = (view, position) -> { + onClick(((EmojiImageView) view).emoji); }); + listView.setOnTouchListener((v, event) -> ContentPreviewViewer.getInstance().onTouch(event, listView, 0, onItemClickListener, previewDelegate, resourcesProvider)); this.containerView.addView(this.listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 44 + 8)); this.addView(this.containerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 8 + 44 + 8 + 6.66f, Gravity.BOTTOM)); @@ -619,102 +747,102 @@ public void invalidateContent() { containerView.invalidate(); } - private class Adapter extends RecyclerListView.SelectionAdapter { + public class EmojiImageView extends View { - private class EmojiImageView extends View { + private String emoji; + public Drawable drawable; + private boolean attached; - private String emoji; - private Drawable drawable; - private boolean attached; + private AnimatedFloat pressed = new AnimatedFloat(this, 350, new OvershootInterpolator(5.0f)); - private AnimatedFloat pressed = new AnimatedFloat(this, 350, new OvershootInterpolator(5.0f)); - - public EmojiImageView(Context context) { - super(context); - } + public EmojiImageView(Context context) { + super(context); + } - private final int paddingDp = 3; - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setPadding(AndroidUtilities.dp(paddingDp), AndroidUtilities.dp(paddingDp), AndroidUtilities.dp(paddingDp), AndroidUtilities.dp(paddingDp + 6.66f)); - super.onMeasure( + private final int paddingDp = 3; + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setPadding(AndroidUtilities.dp(paddingDp), AndroidUtilities.dp(paddingDp), AndroidUtilities.dp(paddingDp), AndroidUtilities.dp(paddingDp + 6.66f)); + super.onMeasure( MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(44), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(44 + 8), MeasureSpec.EXACTLY) - ); - } + ); + } - private void setEmoji(String emoji) { - this.emoji = emoji; - if (emoji != null && emoji.startsWith("animated_")) { - try { - long documentId = Long.parseLong(emoji.substring(9)); - if (!(drawable instanceof AnimatedEmojiDrawable) || ((AnimatedEmojiDrawable) drawable).getDocumentId() != documentId) { - setImageDrawable(AnimatedEmojiDrawable.make(currentAccount, AnimatedEmojiDrawable.CACHE_TYPE_KEYBOARD, documentId)); - } - } catch (Exception ignore) { - setImageDrawable(null); + private void setEmoji(String emoji) { + this.emoji = emoji; + if (emoji != null && emoji.startsWith("animated_")) { + try { + long documentId = Long.parseLong(emoji.substring(9)); + if (!(drawable instanceof AnimatedEmojiDrawable) || ((AnimatedEmojiDrawable) drawable).getDocumentId() != documentId) { + setImageDrawable(AnimatedEmojiDrawable.make(currentAccount, AnimatedEmojiDrawable.CACHE_TYPE_KEYBOARD, documentId)); } - } else { - setImageDrawable(Emoji.getEmojiBigDrawable(emoji)); + } catch (Exception ignore) { + setImageDrawable(null); } + } else { + setImageDrawable(Emoji.getEmojiBigDrawable(emoji)); } + } - public void setImageDrawable(@Nullable Drawable drawable) { - if (this.drawable instanceof AnimatedEmojiDrawable) { - ((AnimatedEmojiDrawable) this.drawable).removeView(this); - } - this.drawable = drawable; - if (drawable instanceof AnimatedEmojiDrawable && attached) { - ((AnimatedEmojiDrawable) drawable).addView(this); - } + public void setImageDrawable(@Nullable Drawable drawable) { + if (this.drawable instanceof AnimatedEmojiDrawable) { + ((AnimatedEmojiDrawable) this.drawable).removeView(this); } - - @Override - public void setPressed(boolean pressed) { - super.setPressed(pressed); - invalidate(); + this.drawable = drawable; + if (drawable instanceof AnimatedEmojiDrawable && attached) { + ((AnimatedEmojiDrawable) drawable).addView(this); } + } - @Override - protected void dispatchDraw(Canvas canvas) { - float scale = 0.8f + 0.2f * (1f - pressed.set(isPressed() ? 1f : 0f)); - if (drawable != null) { - int cx = getWidth() / 2; - int cy = (getHeight() - getPaddingBottom() + getPaddingTop()) / 2; - drawable.setBounds(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); - canvas.scale(scale, scale, cx, cy); - if (drawable instanceof AnimatedEmojiDrawable) { - ((AnimatedEmojiDrawable) drawable).setTime(System.currentTimeMillis()); - } - drawable.draw(canvas); + @Override + public void setPressed(boolean pressed) { + super.setPressed(pressed); + invalidate(); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + float scale = 0.8f + 0.2f * (1f - pressed.set(isPressed() ? 1f : 0f)); + if (drawable != null) { + int cx = getWidth() / 2; + int cy = (getHeight() - getPaddingBottom() + getPaddingTop()) / 2; + drawable.setBounds(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); + canvas.scale(scale, scale, cx, cy); + if (drawable instanceof AnimatedEmojiDrawable) { + ((AnimatedEmojiDrawable) drawable).setTime(System.currentTimeMillis()); } + drawable.draw(canvas); } + } - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - attach(); - } + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + attach(); + } - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - detach(); - } + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + detach(); + } - public void detach() { - if (drawable instanceof AnimatedEmojiDrawable) { - ((AnimatedEmojiDrawable) drawable).removeView(this); - } - attached = false; + public void detach() { + if (drawable instanceof AnimatedEmojiDrawable) { + ((AnimatedEmojiDrawable) drawable).removeView(this); } - public void attach() { - if (drawable instanceof AnimatedEmojiDrawable) { - ((AnimatedEmojiDrawable) drawable).addView(this); - } - attached = true; + attached = false; + } + public void attach() { + if (drawable instanceof AnimatedEmojiDrawable) { + ((AnimatedEmojiDrawable) drawable).addView(this); } + attached = true; } + } + + private class Adapter extends RecyclerListView.SelectionAdapter { public Adapter() { // setHasStableIds(true); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert.java deleted file mode 100644 index dd647cb2a9b..00000000000 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert.java +++ /dev/null @@ -1,1803 +0,0 @@ -package org.telegram.ui.Components; - -import static org.telegram.messenger.AndroidUtilities.displayMetrics; -import static org.telegram.messenger.AndroidUtilities.dp; -import static org.telegram.messenger.AndroidUtilities.lerp; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; -import android.app.Dialog; -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.LinearGradient; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.Region; -import android.graphics.Shader; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.os.Bundle; -import android.os.SystemClock; -import android.text.Layout; -import android.text.Spannable; -import android.text.SpannableStringBuilder; -import android.text.Spanned; -import android.text.TextPaint; -import android.text.TextUtils; -import android.text.method.LinkMovementMethod; -import android.text.style.ClickableSpan; -import android.text.style.URLSpan; -import android.text.util.Linkify; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewParent; -import android.view.Window; -import android.view.WindowManager; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.Toast; - -import androidx.annotation.NonNull; -import androidx.core.widget.NestedScrollView; - -import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ApplicationLoader; -import org.telegram.messenger.DispatchQueue; -import org.telegram.messenger.Emoji; -import org.telegram.messenger.FileLog; -import org.telegram.messenger.LocaleController; -import org.telegram.messenger.MessageObject; -import org.telegram.messenger.R; -import org.telegram.messenger.Utilities; -import org.telegram.messenger.XiaomiUtilities; -import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.TLRPC; -import org.telegram.ui.ActionBar.BaseFragment; -import org.telegram.ui.ActionBar.Theme; - -import java.util.ArrayList; - -public class TranslateAlert extends Dialog { - - public static volatile DispatchQueue translateQueue = new DispatchQueue("translateQueue", false); - - private FrameLayout bulletinContainer; - private FrameLayout contentView; - private FrameLayout container; - private TextView titleView; - private LinearLayout subtitleView; - private InlineLoadingTextView subtitleFromView; - private ImageView subtitleArrowView; - private TextView subtitleToView; - private ImageView backButton; - private FrameLayout header; - private FrameLayout headerShadowView; - private NestedScrollView scrollView; - private TextBlocksLayout textsView; - private TextView buttonTextView; - private FrameLayout buttonView; - private FrameLayout buttonShadowView; - private TextView allTextsView; - private FrameLayout textsContainerView; - - private FrameLayout.LayoutParams titleLayout; - private FrameLayout.LayoutParams subtitleLayout; - private FrameLayout.LayoutParams headerLayout; - private FrameLayout.LayoutParams scrollViewLayout; - - private int blockIndex = 0; - private ArrayList textBlocks; - - private float containerOpenAnimationT = 0f; - private void openAnimation(float t) { - t = Math.min(Math.max(t, 0f), 1f); - if (containerOpenAnimationT == t) { - return; - } - containerOpenAnimationT = t; - - titleView.setScaleX(lerp(1f, 0.9473f, t)); - titleView.setScaleY(lerp(1f, 0.9473f, t)); - titleLayout.setMargins( - dp(lerp(22, 72, t)), - dp(lerp(22, 8, t)), - titleLayout.rightMargin, - titleLayout.bottomMargin - ); - titleView.setLayoutParams(titleLayout); - subtitleLayout.setMargins( - dp(lerp(22, 72, t)) - LoadingTextView2.paddingHorizontal, - dp(lerp(47, 30, t)) - LoadingTextView2.paddingVertical, - subtitleLayout.rightMargin, - subtitleLayout.bottomMargin - ); - subtitleView.setLayoutParams(subtitleLayout); - - backButton.setAlpha(t); - backButton.setScaleX(.75f + .25f * t); - backButton.setScaleY(.75f + .25f * t); - backButton.setClickable(t > .5f); - headerShadowView.setAlpha(scrollView.getScrollY() > 0 ? 1f : t); - - headerLayout.height = (int) lerp(dp(70), dp(56), t); - header.setLayoutParams(headerLayout); - - scrollViewLayout.setMargins( - scrollViewLayout.leftMargin, - (int) lerp(dp(70), dp(56), t), - scrollViewLayout.rightMargin, - scrollViewLayout.bottomMargin - ); - scrollView.setLayoutParams(scrollViewLayout); - } - - - private boolean openAnimationToAnimatorPriority = false; - private ValueAnimator openAnimationToAnimator = null; - private void openAnimationTo(float to, boolean priority) { - openAnimationTo(to, priority, null); - } - private void openAnimationTo(float to, boolean priority, Runnable onAnimationEnd) { - if (openAnimationToAnimatorPriority && !priority) { - return; - } - openAnimationToAnimatorPriority = priority; - to = Math.min(Math.max(to, 0), 1); - if (openAnimationToAnimator != null) { - openAnimationToAnimator.cancel(); - } - openAnimationToAnimator = ValueAnimator.ofFloat(containerOpenAnimationT, to); - openAnimationToAnimator.addUpdateListener(a -> openAnimation((float) a.getAnimatedValue())); - openAnimationToAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animator) { - openAnimationToAnimatorPriority = false; - if (onAnimationEnd != null) - onAnimationEnd.run(); - } - @Override - public void onAnimationCancel(Animator animator) { - openAnimationToAnimatorPriority = false; - } - }); - openAnimationToAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT); - openAnimationToAnimator.setDuration(220); - openAnimationToAnimator.start(); - if (to >= .5 && blockIndex <= 1) { - fetchNext(); - } - } - - private int firstMinHeight = -1; - private int minHeight() { - return minHeight(false); - } - private int minHeight(boolean full) { - int textsViewHeight = textsView == null ? 0 : textsView.getMeasuredHeight(); - int height = - textsViewHeight + - dp( - 66 + // header - 1 + // button separator - 16 + // button top padding - 48 + // button - 16 // button bottom padding - ); - if (firstMinHeight < 0 && textsViewHeight > 0) - firstMinHeight = height; - if (firstMinHeight > 0 && textBlocks.size() > 1 && !full) - return firstMinHeight; - return height; - } - private boolean canExpand() { - return ( - textsView.getBlocksCount() < textBlocks.size() || - minHeight(true) >= (AndroidUtilities.displayMetrics.heightPixels * heightMaxPercent) - ); - } - private void updateCanExpand() { - boolean canExpand = canExpand(); - if (containerOpenAnimationT > 0f && !canExpand) { - openAnimationTo(0f, false); - } - - buttonShadowView.animate().alpha(canExpand ? 1f : 0f).setDuration((long) (Math.abs(buttonShadowView.getAlpha() - (canExpand ? 1f : 0f)) * 220)).start(); - } - - public interface OnLinkPress { - public boolean run(URLSpan urlSpan); - } - - private int currentAccount; - private TLRPC.InputPeer peer; - private int msgId; - private boolean allowScroll = true; - private String fromLanguage, toLanguage; - private CharSequence text; - private BaseFragment fragment; - private boolean noforwards; - private OnLinkPress onLinkPress; - private Runnable onDismiss; - public TranslateAlert(BaseFragment fragment, Context context, int currentAccount, String fromLanguage, String toLanguage, CharSequence text, boolean noforwards, OnLinkPress onLinkPress, Runnable onDismiss) { - this(fragment, context, currentAccount, null, -1, fromLanguage, toLanguage, text, noforwards, onLinkPress, onDismiss); - } - public TranslateAlert(BaseFragment fragment, Context context, int currentAccount, TLRPC.InputPeer peer, int msgId, String fromLanguage, String toLanguage, CharSequence text, boolean noforwards, OnLinkPress onLinkPress, Runnable onDismiss) { - super(context, R.style.TransparentDialog); - - this.onLinkPress = onLinkPress; - this.noforwards = noforwards; - this.fragment = fragment; - this.fromLanguage = fromLanguage != null && fromLanguage.equals("und") ? "auto" : fromLanguage; - this.toLanguage = toLanguage; - this.text = text; - this.textBlocks = new ArrayList<>(); - this.textBlocks.add(text); -// cutInBlocks(text, 1024); - this.onDismiss = onDismiss; - - this.currentAccount = currentAccount; - this.peer = peer; - this.msgId = msgId; - - if (Build.VERSION.SDK_INT >= 30) { - getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); - } else if (Build.VERSION.SDK_INT >= 21) { - getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); - } - - if (noforwards) { - getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); - } - - contentView = new FrameLayout(context); - contentView.setBackground(backDrawable); - contentView.setClipChildren(false); - contentView.setClipToPadding(false); - if (Build.VERSION.SDK_INT >= 21) { - contentView.setFitsSystemWindows(true); - if (Build.VERSION.SDK_INT >= 30) { - contentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); - } else { - contentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); - } - } - - Paint containerPaint = new Paint(); - containerPaint.setColor(Theme.getColor(Theme.key_dialogBackground)); - containerPaint.setShadowLayer(dp(2), 0, dp(-0.66f), 0x1e000000); - container = new FrameLayout(context) { - private int contentHeight = Integer.MAX_VALUE; - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int fullWidth = MeasureSpec.getSize(widthMeasureSpec); - int fullHeight = MeasureSpec.getSize(widthMeasureSpec); - int minHeight = (int) (AndroidUtilities.displayMetrics.heightPixels * heightMaxPercent); - if (textsView != null && textsView.getMeasuredHeight() <= 0) { - textsView.measure( - MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec) - textsView.getPaddingLeft() - textsView.getPaddingRight() - textsContainerView.getPaddingLeft() - textsContainerView.getPaddingRight(), MeasureSpec.EXACTLY), - 0 - ); - } - int fromHeight = Math.min(minHeight, minHeight()); - int height = (int) (fromHeight + (AndroidUtilities.displayMetrics.heightPixels - fromHeight) * containerOpenAnimationT); - updateCanExpand(); - super.onMeasure( - MeasureSpec.makeMeasureSpec( - (int) Math.max(fullWidth * 0.8f, Math.min(dp(480), fullWidth)), - MeasureSpec.getMode(widthMeasureSpec) - ), - MeasureSpec.makeMeasureSpec( - height, - MeasureSpec.EXACTLY - ) - ); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - contentHeight = Math.min(contentHeight, bottom - top); - } - - private Path containerPath = new Path(); - private RectF containerRect = new RectF(); - private RectF rectF = new RectF(); - @Override - protected void onDraw(Canvas canvas) { - int w = getWidth(), h = getHeight(), r = dp(12 * (1f - containerOpenAnimationT)); - canvas.clipRect(0, 0, w, h); - - containerRect.set(0, 0, w, h + r); - canvas.translate(0, (1f - openingT) * h); - - canvas.drawRoundRect(containerRect, r, r, containerPaint); - super.onDraw(canvas); - } - }; - container.setWillNotDraw(false); - - header = new FrameLayout(context); - - titleView = new TextView(context); - titleView.setPivotX(LocaleController.isRTL ? titleView.getWidth() : 0); - titleView.setPivotY(0); - titleView.setLines(1); - titleView.setText(LocaleController.getString("AutomaticTranslation", R.string.AutomaticTranslation)); - titleView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); - titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - titleView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); - titleView.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp(19)); - header.addView(titleView, titleLayout = LayoutHelper.createFrame( - LayoutHelper.MATCH_PARENT, - LayoutHelper.WRAP_CONTENT, - Gravity.FILL_HORIZONTAL | Gravity.TOP, - 22, 22,22, 0 - )); - titleView.post(() -> { - titleView.setPivotX(LocaleController.isRTL ? titleView.getWidth() : 0); - }); - - subtitleView = new LinearLayout(context); - subtitleView.setOrientation(LinearLayout.HORIZONTAL); - if (Build.VERSION.SDK_INT >= 17) { - subtitleView.setLayoutDirection(LocaleController.isRTL ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR); - } - subtitleView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); - - String fromLanguageName = languageName(fromLanguage); - subtitleFromView = new InlineLoadingTextView(context, fromLanguageName == null ? languageName(toLanguage) : fromLanguageName, dp(14), Theme.getColor(Theme.key_player_actionBarSubtitle)) { - @Override - protected void onLoadAnimation(float t) { - MarginLayoutParams lp = (MarginLayoutParams) subtitleFromView.getLayoutParams(); - if (lp != null) { - if (LocaleController.isRTL) { - lp.leftMargin = dp(2f - t * 6f); - } else { - lp.rightMargin = dp(2f - t * 6f); - } - subtitleFromView.setLayoutParams(lp); - } - } - }; - subtitleFromView.showLoadingText = false; - subtitleArrowView = new ImageView(context); - subtitleArrowView.setImageResource(R.drawable.search_arrow); - subtitleArrowView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_player_actionBarSubtitle), PorterDuff.Mode.MULTIPLY)); - if (LocaleController.isRTL) { - subtitleArrowView.setScaleX(-1f); - } - - subtitleToView = new TextView(context); - subtitleToView.setLines(1); - subtitleToView.setTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle)); - subtitleToView.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp(14)); - subtitleToView.setText(languageName(toLanguage)); - - if (LocaleController.isRTL) { - subtitleView.setPadding(InlineLoadingTextView.paddingHorizontal, 0, 0, 0); - subtitleView.addView(subtitleToView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); - subtitleView.addView(subtitleArrowView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 3, 1, 0, 0)); - subtitleView.addView(subtitleFromView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 2, 0, 0, 0)); - } else { - subtitleView.setPadding(0, 0, InlineLoadingTextView.paddingHorizontal, 0); - subtitleView.addView(subtitleFromView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 0, 2, 0)); - subtitleView.addView(subtitleArrowView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 1, 3, 0)); - subtitleView.addView(subtitleToView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); - } - if (fromLanguageName != null) { - subtitleFromView.set(fromLanguageName); - } - - header.addView(subtitleView, subtitleLayout = LayoutHelper.createFrame( - LayoutHelper.MATCH_PARENT, - LayoutHelper.WRAP_CONTENT, - Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), - 22 - LoadingTextView2.paddingHorizontal / AndroidUtilities.density, - 47 - LoadingTextView2.paddingVertical / AndroidUtilities.density, - 22 - LoadingTextView2.paddingHorizontal / AndroidUtilities.density, - 0 - )); - - backButton = new ImageView(context); - backButton.setImageResource(R.drawable.ic_ab_back); - backButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogTextBlack), PorterDuff.Mode.MULTIPLY)); - backButton.setScaleType(ImageView.ScaleType.FIT_CENTER); - backButton.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0); - backButton.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_dialogButtonSelector))); - backButton.setClickable(false); - backButton.setAlpha(0f); - backButton.setOnClickListener(e -> dismiss()); - header.addView(backButton, LayoutHelper.createFrame(56, 56, Gravity.LEFT | Gravity.CENTER_HORIZONTAL)); - - headerShadowView = new FrameLayout(context); - headerShadowView.setBackgroundColor(Theme.getColor(Theme.key_dialogShadowLine)); - headerShadowView.setAlpha(0); - header.addView(headerShadowView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL)); - - header.setClipChildren(false); - container.addView(header, headerLayout = LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 70, Gravity.FILL_HORIZONTAL | Gravity.TOP)); - - scrollView = new NestedScrollView(context) { - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - return allowScroll && containerOpenAnimationT >= 1f && canExpand() && super.onInterceptTouchEvent(ev); - } - - @Override - public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) { - super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed); - } - - @Override - protected void onScrollChanged(int l, int t, int oldl, int oldt) { - super.onScrollChanged(l, t, oldl, oldt); - if (checkForNextLoading()) { - openAnimationTo(1f, true); - } - } - }; - scrollView.setClipChildren(true); - - allTextsView = new TextView(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MOST_SPEC); - } - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - canvas.translate(getPaddingLeft(), getPaddingTop()); - if (links != null && links.draw(canvas)) { - invalidate(); - } - } - @Override - public boolean onTextContextMenuItem(int id) { - if (id == android.R.id.copy && isFocused()) { - android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); - android.content.ClipData clip = android.content.ClipData.newPlainText( - "label", - getText().subSequence( - Math.max(0, Math.min(getSelectionStart(), getSelectionEnd())), - Math.max(0, Math.max(getSelectionStart(), getSelectionEnd())) - ) - ); - clipboard.setPrimaryClip(clip); - BulletinFactory.of(bulletinContainer, null).createCopyBulletin(LocaleController.getString("TextCopied", R.string.TextCopied)).show(); - clearFocus(); - return true; - } else { - return super.onTextContextMenuItem(id); - } - } - }; - links = new LinkSpanDrawable.LinkCollector(allTextsView); - allTextsView.setTextColor(0x00000000); - allTextsView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - allTextsView.setTextIsSelectable(!noforwards); - allTextsView.setHighlightColor(Theme.getColor(Theme.key_chat_inTextSelectionHighlight)); - int handleColor = Theme.getColor(Theme.key_chat_TextSelectionCursor); - try { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && !XiaomiUtilities.isMIUI()) { - Drawable left = allTextsView.getTextSelectHandleLeft(); - left.setColorFilter(handleColor, PorterDuff.Mode.SRC_IN); - allTextsView.setTextSelectHandleLeft(left); - - Drawable right = allTextsView.getTextSelectHandleRight(); - right.setColorFilter(handleColor, PorterDuff.Mode.SRC_IN); - allTextsView.setTextSelectHandleRight(right); - } - } catch (Exception e) {} - allTextsView.setFocusable(true); - allTextsView.setMovementMethod(new LinkMovementMethod()); - - textsView = new TextBlocksLayout(context, dp(16), Theme.getColor(Theme.key_dialogTextBlack), allTextsView); - textsView.setPadding( - dp(22) - LoadingTextView2.paddingHorizontal, - dp(12) - LoadingTextView2.paddingVertical, - dp(22) - LoadingTextView2.paddingHorizontal, - dp(12) - LoadingTextView2.paddingVertical - ); - for (CharSequence blockText : textBlocks) - textsView.addBlock(blockText); - - textsContainerView = new FrameLayout(context); - textsContainerView.addView(textsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - - scrollView.addView(textsContainerView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f)); - - container.addView(scrollView, scrollViewLayout = LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.FILL, 0, 70, 0, 81)); - - fetchNext(); - - buttonShadowView = new FrameLayout(context); - buttonShadowView.setBackgroundColor(Theme.getColor(Theme.key_dialogShadowLine)); - container.addView(buttonShadowView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0, 0, 80)); - - buttonTextView = new TextView(context); - buttonTextView.setLines(1); - buttonTextView.setSingleLine(true); - buttonTextView.setGravity(Gravity.CENTER_HORIZONTAL); - buttonTextView.setEllipsize(TextUtils.TruncateAt.END); - buttonTextView.setGravity(Gravity.CENTER); - buttonTextView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); - buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - buttonTextView.setText(LocaleController.getString("CloseTranslation", R.string.CloseTranslation)); - - buttonView = new FrameLayout(context); -// buttonView.setBackground(Theme.AdaptiveRipple.filledRect(Theme.key_featuredStickers_addButton, 4)); - buttonView.setBackground(Theme.AdaptiveRipple.filledRect(Theme.getColor(Theme.key_featuredStickers_addButton), 4)); - buttonView.addView(buttonTextView); - buttonView.setOnClickListener(e -> dismiss()); - - container.addView(buttonView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM, 16, 16, 16, 16)); - contentView.addView(container, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL)); - - bulletinContainer = new FrameLayout(context); - contentView.addView(bulletinContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, 0, 0, 81)); - } - public void showDim(boolean enable) { - contentView.setBackground(enable ? backDrawable : null); - } - - private boolean scrollAtBottom() { - View view = (View) scrollView.getChildAt(scrollView.getChildCount() - 1); - int bottom = view.getBottom(); - LoadingTextView2 lastUnloadedBlock = textsView.getFirstUnloadedBlock(); - if (lastUnloadedBlock != null) { - bottom = lastUnloadedBlock.getTop(); - } - int diff = (bottom - (scrollView.getHeight() + scrollView.getScrollY())); - return diff <= textsContainerView.getPaddingBottom(); - } - - private void setScrollY(float t) { - openAnimation(t); - openingT = Math.max(Math.min(1f + t, 1), 0); - backDrawable.setAlpha((int) (openingT * 51)); - container.invalidate(); - bulletinContainer.setTranslationY((1f - openingT) * Math.min(minHeight(), displayMetrics.heightPixels * heightMaxPercent)); - } - private void scrollYTo(float t) { - scrollYTo(t, null); - } - private void scrollYTo(float t, Runnable onAnimationEnd) { - openAnimationTo(t, false, onAnimationEnd); - openTo(1f + t, false); - } - private float fromScrollY = 0; - private float getScrollY() { - return Math.max(Math.min(containerOpenAnimationT - (1 - openingT), 1), 0); - } - - private boolean hasSelection() { - return allTextsView.hasSelection(); - } - - private Rect containerRect = new Rect(); - private Rect textRect = new Rect(); - private Rect translateMoreRect = new Rect(); - private Rect buttonRect = new Rect(); - private Rect backRect = new Rect(); - private Rect scrollRect = new Rect(); - private float fromY = 0; - private boolean pressedOutside = false; - private boolean maybeScrolling = false; - private boolean scrolling = false; - private boolean fromScrollRect = false; - private boolean fromTranslateMoreView = false; - private float fromScrollViewY = 0; - private Spannable allTexts = null; - private LinkSpanDrawable pressedLink; - private LinkSpanDrawable.LinkCollector links; - - @Override - public boolean dispatchTouchEvent(@NonNull MotionEvent event) { - try { - float x = event.getX(); - float y = event.getY(); - - container.getGlobalVisibleRect(containerRect); - if (!containerRect.contains((int) x, (int) y)) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - pressedOutside = true; - return true; - } else if (event.getAction() == MotionEvent.ACTION_UP) { - if (pressedOutside) { - pressedOutside = false; - dismiss(); - return true; - } - } - } - - try { - allTextsView.getGlobalVisibleRect(textRect); - if (textRect.contains((int) x, (int) y) && !maybeScrolling) { - Layout allTextsLayout = allTextsView.getLayout(); - int tx = (int) (x - allTextsView.getLeft() - container.getLeft()), - ty = (int) (y - allTextsView.getTop() - container.getTop() - scrollView.getTop() + scrollView.getScrollY()); - final int line = allTextsLayout.getLineForVertical(ty); - final int off = allTextsLayout.getOffsetForHorizontal(line, tx); - - final float left = allTextsLayout.getLineLeft(line); - if (allTexts instanceof Spannable && left <= tx && left + allTextsLayout.getLineWidth(line) >= tx) { - ClickableSpan[] linkSpans = allTexts.getSpans(off, off, ClickableSpan.class); - if (linkSpans != null && linkSpans.length >= 1) { - if (event.getAction() == MotionEvent.ACTION_UP && pressedLink.getSpan() == linkSpans[0]) { - ((ClickableSpan) pressedLink.getSpan()).onClick(allTextsView); - if (links != null) { - links.removeLink(pressedLink); - } - pressedLink = null; - allTextsView.setTextIsSelectable(!noforwards); - } else if (event.getAction() == MotionEvent.ACTION_DOWN) { - pressedLink = new LinkSpanDrawable(linkSpans[0], fragment.getResourceProvider(), tx, ty, false); - if (links != null) { - links.addLink(pressedLink); - } - LinkPath path = pressedLink.obtainNewPath(); - int start = allTexts.getSpanStart(pressedLink.getSpan()); - int end = allTexts.getSpanEnd(pressedLink.getSpan()); - path.setCurrentLayout(allTextsLayout, start, 0); - allTextsLayout.getSelectionPath(start, end, path); - } - allTextsView.invalidate(); - return true; - } - } - } - if (pressedLink != null) { - if (links != null) { - links.clear(); - } - pressedLink = null; - } - } catch (Exception e2) { - e2.printStackTrace(); - } - - scrollView.getGlobalVisibleRect(scrollRect); - backButton.getGlobalVisibleRect(backRect); - buttonView.getGlobalVisibleRect(buttonRect); - if (pressedLink == null && /*!(scrollRect.contains((int) x, (int) y) && !canExpand() && containerOpenAnimationT < .5f && !scrolling) &&*/ !hasSelection()) { - if ( - !backRect.contains((int) x, (int) y) && - !buttonRect.contains((int) x, (int) y) && - event.getAction() == MotionEvent.ACTION_DOWN - ) { - fromScrollRect = scrollRect.contains((int) x, (int) y) && (containerOpenAnimationT > 0 || !canExpand()); - maybeScrolling = true; - scrolling = scrollRect.contains((int) x, (int) y) && textsView.getBlocksCount() > 0 && !((LoadingTextView2) textsView.getBlockAt(0)).loaded; - fromY = y; - fromScrollY = getScrollY(); - fromScrollViewY = scrollView.getScrollY(); - return super.dispatchTouchEvent(event) || true; - } else if (maybeScrolling && (event.getAction() == MotionEvent.ACTION_MOVE || event.getAction() == MotionEvent.ACTION_UP)) { - float dy = fromY - y; - if (fromScrollRect) { - dy = -Math.max(0, -(fromScrollViewY + dp(48)) - dy); - if (dy < 0) { - scrolling = true; - allTextsView.setTextIsSelectable(false); - } - } else if (Math.abs(dy) > dp(4) && !fromScrollRect) { - scrolling = true; - allTextsView.setTextIsSelectable(false); - scrollView.stopNestedScroll(); - allowScroll = false; - } - float fullHeight = AndroidUtilities.displayMetrics.heightPixels, - minHeight = Math.min(minHeight(), fullHeight * heightMaxPercent); - float scrollYPx = minHeight * (1f - -Math.min(Math.max(fromScrollY, -1), 0)) + (fullHeight - minHeight) * Math.min(1, Math.max(fromScrollY, 0)) + dy; - float scrollY = scrollYPx > minHeight ? (scrollYPx - minHeight) / (fullHeight - minHeight) : -(1f - scrollYPx / minHeight); - if (!canExpand()) { - scrollY = Math.min(scrollY, 0); - } - updateCanExpand(); - - if (scrolling) { - setScrollY(scrollY); - if (event.getAction() == MotionEvent.ACTION_UP) { - scrolling = false; - allTextsView.setTextIsSelectable(!noforwards); - maybeScrolling = false; - allowScroll = true; - scrollYTo( - Math.abs(dy) > dp(16) ? - Math.round(fromScrollY) + (scrollY > fromScrollY ? 1f : -1f) * (float) Math.ceil(Math.abs(fromScrollY - scrollY)) : - Math.round(fromScrollY), - () -> { - contentView.post(this::checkForNextLoading); - } - ); - } - return true; - } - } - } - if (hasSelection() && maybeScrolling) { - scrolling = false; - allTextsView.setTextIsSelectable(!noforwards); - maybeScrolling = false; - allowScroll = true; - scrollYTo(Math.round(fromScrollY)); - } - return super.dispatchTouchEvent(event); - } catch (Exception e) { - e.printStackTrace(); - return super.dispatchTouchEvent(event); - } - } - - private float openingT = 0f; - private ValueAnimator openingAnimator; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - contentView.setPadding(0, 0, 0, 0); - setContentView(contentView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - - Window window = getWindow(); - - window.setWindowAnimations(R.style.DialogNoAnimation); - WindowManager.LayoutParams params = window.getAttributes(); - params.width = ViewGroup.LayoutParams.MATCH_PARENT; - params.gravity = Gravity.TOP | Gravity.LEFT; - params.dimAmount = 0; - params.flags &= ~WindowManager.LayoutParams.FLAG_DIM_BEHIND; - params.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; - if (Build.VERSION.SDK_INT >= 21) { - params.flags |= - WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | - WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | - WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; - } - params.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; - params.height = ViewGroup.LayoutParams.MATCH_PARENT; - window.setAttributes(params); - - int navigationbarColor = Theme.getColor(Theme.key_windowBackgroundWhite); - AndroidUtilities.setNavigationBarColor(window, navigationbarColor); - AndroidUtilities.setLightNavigationBar(window, AndroidUtilities.computePerceivedBrightness(navigationbarColor) > .721); - - container.forceLayout(); - } - - protected ColorDrawable backDrawable = new ColorDrawable(0xff000000) { - @Override - public void setAlpha(int alpha) { - super.setAlpha(alpha); - container.invalidate(); - } - }; - @Override - public void show() { - super.show(); - - openAnimation(0); - openTo(1, true, true); - } - - private boolean dismissed = false; - @Override - public void dismiss() { - if (dismissed) - return; - dismissed = true; - - openTo(0, true); - } - private void openTo(float t, boolean priority) { - openTo(t, priority, false); - } - private void openTo(float t) { - openTo(t, false); - } - private float heightMaxPercent = .85f; - - private boolean fastHide = false; - private boolean openingAnimatorPriority = false; - private void openTo(float t, boolean priority, boolean setAfter) { - final float T = Math.min(Math.max(t, 0), 1); - if (openingAnimatorPriority && !priority) { - return; - } - openingAnimatorPriority = priority; - if (openingAnimator != null) { - openingAnimator.cancel(); - } - openingAnimator = ValueAnimator.ofFloat(openingT, T); - backDrawable.setAlpha((int) (openingT * 51)); - openingAnimator.addUpdateListener(a -> { - openingT = (float) a.getAnimatedValue(); - container.invalidate(); - backDrawable.setAlpha((int) (openingT * 51)); - bulletinContainer.setTranslationY((1f - openingT) * Math.min(minHeight(), displayMetrics.heightPixels * heightMaxPercent)); - }); - if (T <= 0f) { - if (onDismiss != null) { - onDismiss.run(); - } - } - openingAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animator) { - if (T <= 0f) { - dismissInternal(); - } else if (setAfter) { - allTextsView.setTextIsSelectable(!noforwards); - allTextsView.invalidate(); - scrollView.stopNestedScroll(); - openAnimation(T - 1f); - } - openingAnimatorPriority = false; - } - }); - openingAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); - openingAnimator.setDuration((long) (Math.abs(openingT - T) * (fastHide ? 200 : 380))); - openingAnimator.setStartDelay(setAfter ? 60 : 0); - openingAnimator.start(); - } - public void dismissInternal() { - try { - super.dismiss(); - } catch (Exception e) { - FileLog.e(e); - } - } - - public String languageName(String locale) { - // sorry, no more vodka - if (locale == null || locale.equals("und") || locale.equals("auto")) { - return null; - } - LocaleController.LocaleInfo thisLanguageInfo = LocaleController.getInstance().getBuiltinLanguageByPlural(locale), - currentLanguageInfo = LocaleController.getInstance().getCurrentLocaleInfo(); - if (thisLanguageInfo == null) { - return null; - } - boolean isCurrentLanguageEnglish = currentLanguageInfo != null && "en".equals(currentLanguageInfo.pluralLangCode); - if (isCurrentLanguageEnglish) { - // trying to show this language in a language of the interface, but there are only names in english and its own - return thisLanguageInfo.nameEnglish; - } else { - return thisLanguageInfo.name; - } - } - - public void updateSourceLanguage() { - if (languageName(fromLanguage) != null) { - subtitleView.setAlpha(1); - if (!subtitleFromView.loaded) { - subtitleFromView.loaded(languageName(fromLanguage)); - } - } else if (loaded) { - subtitleView.animate().alpha(0).setDuration(150).start(); - } - } - - private ArrayList cutInBlocks(CharSequence full, int maxBlockSize) { - ArrayList blocks = new ArrayList<>(); - if (full == null) { - return blocks; - } - while (full.length() > maxBlockSize) { - String maxBlockStr = full.subSequence(0, maxBlockSize).toString(); - int n = -1; - if (n == -1) n = maxBlockStr.lastIndexOf("\n\n"); - if (n == -1) n = maxBlockStr.lastIndexOf("\n"); - if (n == -1) n = maxBlockStr.lastIndexOf(". "); - if (n == -1) n = Math.min(maxBlockStr.length(), maxBlockSize); - blocks.add(full.subSequence(0, n + 1)); - full = full.subSequence(n + 1, full.length()); - } - if (full.length() > 0) { - blocks.add(full); - } - return blocks; - } - - private boolean loading = false; - private boolean loaded = false; - private boolean fetchNext() { - if (loading) { - return false; - } - loading = true; - - if (blockIndex >= textBlocks.size()) { - return false; - } - - fetchTranslation( - textBlocks.get(blockIndex), - Math.min((blockIndex + 1) * 1000, 3500), - (String translatedText, String sourceLanguage) -> { - loaded = true; - Spannable spannable = new SpannableStringBuilder(translatedText); - try { - MessageObject.addUrlsByPattern(false, spannable, false, 0, 0, true); - URLSpan[] urlSpans = spannable.getSpans(0, spannable.length(), URLSpan.class); - for (int i = 0; i < urlSpans.length; ++i) { - URLSpan urlSpan = urlSpans[i]; - int start = spannable.getSpanStart(urlSpan), - end = spannable.getSpanEnd(urlSpan); - if (start == -1 || end == -1) { - continue; - } - spannable.removeSpan(urlSpan); - spannable.setSpan( - new ClickableSpan() { - @Override - public void onClick(@NonNull View view) { - if (onLinkPress != null) { - if (onLinkPress.run(urlSpan)) { - fastHide = true; - dismiss(); - } - } else { - AlertsCreator.showOpenUrlAlert(fragment, urlSpan.getURL(), false, false); - } - } - - @Override - public void updateDrawState(@NonNull TextPaint ds) { - int alpha = Math.min(ds.getAlpha(), ds.getColor() >> 24 & 0xff); - if (!(urlSpan instanceof URLSpanNoUnderline)) { - ds.setUnderlineText(true); - } - ds.setColor(Theme.getColor(Theme.key_dialogTextLink)); - ds.setAlpha(alpha); - } - }, - start, end, - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE - ); - } - - AndroidUtilities.addLinks(spannable, Linkify.WEB_URLS); - urlSpans = spannable.getSpans(0, spannable.length(), URLSpan.class); - for (int i = 0; i < urlSpans.length; ++i) { - URLSpan urlSpan = urlSpans[i]; - int start = spannable.getSpanStart(urlSpan), - end = spannable.getSpanEnd(urlSpan); - if (start == -1 || end == -1) { - continue; - } - spannable.removeSpan(urlSpan); - spannable.setSpan( - new ClickableSpan() { - @Override - public void onClick(@NonNull View view) { - AlertsCreator.showOpenUrlAlert(fragment, urlSpan.getURL(), false, false); - } - - @Override - public void updateDrawState(@NonNull TextPaint ds) { - int alpha = Math.min(ds.getAlpha(), ds.getColor() >> 24 & 0xff); - if (!(urlSpan instanceof URLSpanNoUnderline)) - ds.setUnderlineText(true); - ds.setColor(Theme.getColor(Theme.key_dialogTextLink)); - ds.setAlpha(alpha); - } - }, - start, end, - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE - ); - } - - spannable = (Spannable) Emoji.replaceEmoji(spannable, allTextsView.getPaint().getFontMetricsInt(), dp(14), false); - } catch (Exception e) { - e.printStackTrace(); - } - - SpannableStringBuilder allTextsBuilder = new SpannableStringBuilder(allTexts == null ? "" : allTexts); - if (blockIndex != 0) { - allTextsBuilder.append("\n"); - } - allTextsBuilder.append(spannable); - allTexts = allTextsBuilder; - textsView.setWholeText(allTexts); - - LoadingTextView2 block = textsView.getBlockAt(blockIndex); - if (block != null) { - block.loaded(spannable, () -> contentView.post(this::checkForNextLoading)); - } - - if (sourceLanguage != null) { - fromLanguage = sourceLanguage; - } - updateSourceLanguage(); - - if (blockIndex == 0 && AndroidUtilities.isAccessibilityScreenReaderEnabled()) { - if (allTextsView != null) { - allTextsView.requestFocus(); - } - } - - blockIndex++; - loading = false; - }, - (boolean rateLimit) -> { - if (rateLimit) { - Toast.makeText(getContext(), LocaleController.getString("TranslationFailedAlert1", R.string.TranslationFailedAlert1), Toast.LENGTH_SHORT).show(); - } else { - Toast.makeText(getContext(), LocaleController.getString("TranslationFailedAlert2", R.string.TranslationFailedAlert2), Toast.LENGTH_SHORT).show(); - } - - if (blockIndex == 0) { - dismiss(); - } - } - ); - return true; - } - - private boolean checkForNextLoading() { - if (scrollAtBottom()) { - fetchNext(); - return true; - } - return false; - } - - public interface OnTranslationSuccess { - public void run(String translated, String sourceLanguage); - } - public interface OnTranslationFail { - public void run(boolean rateLimit); - } - private void fetchTranslation(CharSequence text, long minDuration, OnTranslationSuccess onSuccess, OnTranslationFail onFail) { - final long start = System.currentTimeMillis(); - Utilities.Callback onDone = (string) -> { - AndroidUtilities.runOnUIThread(() -> { - if (string != null) { - onSuccess.run(string, null); - } else { - onFail.run(false); - } - }, Math.max((System.currentTimeMillis() - start) - minDuration, 1)); - }; - if (peer != null) { - translateText(currentAccount, peer, msgId, fromLanguage, toLanguage, onDone); - } else if (text != null) { - translateText(currentAccount, text.toString(), fromLanguage, toLanguage, onDone); - } else { - onFail.run(false); - } - } - - private static void translateText(int currentAccount, TLRPC.InputPeer peer, int msg_id, String from_lang, String to_lang, Utilities.Callback onDone) { - if (onDone == null) { - return; - } - if (from_lang == null || from_lang.equals("und")) { - from_lang = null; - } - - TLRPC.TL_messages_translateText req = new TLRPC.TL_messages_translateText(); - req.peer = peer; - req.msg_id = msg_id; - req.flags |= 1; - if (from_lang != null) { - req.from_lang = from_lang; - req.flags |= 4; - } - req.to_lang = to_lang; - - try { - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> { - if (res instanceof TLRPC.TL_messages_translateResultText) { - onDone.run(((TLRPC.TL_messages_translateResultText) res).text); - return; - } - onDone.run(null); - }); - } catch (Exception e) { - FileLog.e(e); - } - } - - private static void translateText(int currentAccount, String text, String from_lang, String to_lang, Utilities.Callback onDone) { - if (onDone == null) { - return; - } - if (from_lang == null || from_lang.equals("und")) { - from_lang = null; - } - - TLRPC.TL_messages_translateText req = new TLRPC.TL_messages_translateText(); - req.flags |= 2; - req.text = text; - if (from_lang != null) { - req.from_lang = from_lang; - req.flags |= 4; - } - req.to_lang = to_lang; - - try { - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> { - if (res instanceof TLRPC.TL_messages_translateResultText) { - onDone.run(((TLRPC.TL_messages_translateResultText) res).text); - return; - } - onDone.run(null); - }); - } catch (Exception e) { - FileLog.e(e); - } - } - - public static TranslateAlert showAlert(Context context, BaseFragment fragment, int currentAccount, TLRPC.InputPeer peer, int msgId, String fromLanguage, String toLanguage, CharSequence text, boolean noforwards, OnLinkPress onLinkPress, Runnable onDismiss) { - TranslateAlert alert = new TranslateAlert(fragment, context, currentAccount, peer, msgId, fromLanguage, toLanguage, text, noforwards, onLinkPress, onDismiss); - if (fragment != null) { - if (fragment.getParentActivity() != null) { - fragment.showDialog(alert); - } - } else { - alert.show(); - } - return alert; - } - public static TranslateAlert showAlert(Context context, BaseFragment fragment, int currentAccount, String fromLanguage, String toLanguage, CharSequence text, boolean noforwards, OnLinkPress onLinkPress, Runnable onDismiss) { - TranslateAlert alert = new TranslateAlert(fragment, context, currentAccount, fromLanguage, toLanguage, text, noforwards, onLinkPress, onDismiss); - if (fragment != null) { - if (fragment.getParentActivity() != null) { - fragment.showDialog(alert); - } - } else { - alert.show(); - } - return alert; - } - - private static final int MOST_SPEC = View.MeasureSpec.makeMeasureSpec(999999, View.MeasureSpec.AT_MOST); - public static class TextBlocksLayout extends ViewGroup { - - private TextView wholeTextView; - private final int fontSize; - private final int textColor; - - public TextBlocksLayout(Context context, int fontSize, int textColor, TextView wholeTextView) { - super(context); - - this.fontSize = fontSize; - this.textColor = textColor; - - if (wholeTextView != null) { - wholeTextView.setPadding(LoadingTextView2.paddingHorizontal, LoadingTextView2.paddingVertical, LoadingTextView2.paddingHorizontal, LoadingTextView2.paddingVertical); - addView(this.wholeTextView = wholeTextView); - } - } - - public void setWholeText(CharSequence wholeText) { - // having focus on that text view can cause jumping scroll to the top after loading a new block - // TODO(dkaraush): preserve selection after setting a new text - wholeTextView.clearFocus(); - wholeTextView.setText(wholeText); - } - - public LoadingTextView2 addBlock(CharSequence fromText) { - LoadingTextView2 textView = new LoadingTextView2(getContext(), fromText, getBlocksCount() > 0, fontSize, textColor); - textView.setFocusable(false); - addView(textView); - if (wholeTextView != null) { - wholeTextView.bringToFront(); - } - return textView; - } - - public int getBlocksCount() { - return getChildCount() - (wholeTextView != null ? 1 : 0); - } - public LoadingTextView2 getBlockAt(int i) { - View child = getChildAt(i); - if (child instanceof LoadingTextView2) { - return (LoadingTextView2) child; - } - return null; - } - - public LoadingTextView2 getFirstUnloadedBlock() { - final int count = getBlocksCount(); - for (int i = 0; i < count; ++i) { - LoadingTextView2 block = getBlockAt(i); - if (block != null && !block.loaded) - return block; - } - return null; - } - - private static final int gap = -LoadingTextView2.paddingVertical * 4 + dp(.48f); - public int height() { - int height = 0; - final int count = getBlocksCount(); - for (int i = 0; i < count; ++i) { - height += getBlockAt(i).height(); - } - return getPaddingTop() + height + getPaddingBottom(); - } - - protected void onHeightUpdated(int height) {} - - public void updateHeight() { - boolean updated; - int newHeight = height(); - FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); - if (lp == null) { - lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, newHeight); - updated = true; - } else { - updated = lp.height != newHeight; - lp.height = newHeight; - } - - if (updated) { - this.setLayoutParams(lp); - onHeightUpdated(newHeight); - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - final int count = getBlocksCount(); - final int innerWidthMeasureSpec = MeasureSpec.makeMeasureSpec( - MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight(), - MeasureSpec.getMode(widthMeasureSpec) - ); - for (int i = 0; i < count; ++i) { - LoadingTextView2 block = getBlockAt(i); - block.measure(innerWidthMeasureSpec, MOST_SPEC); - } - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height(), MeasureSpec.EXACTLY)); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - int y = 0; - final int count = getBlocksCount(); - for (int i = 0; i < count; ++i) { - LoadingTextView2 block = getBlockAt(i); - final int blockHeight = block.height(); - final int translationY = i > 0 ? gap : 0; - block.layout(getPaddingLeft(), getPaddingTop() + y + translationY, r - l - getPaddingRight(), getPaddingTop() + y + blockHeight + translationY); - y += blockHeight; - if (i > 0 && i < count - 1) { - y += gap; - } - } - - wholeTextView.measure( - MeasureSpec.makeMeasureSpec(r - l - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(b - t - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY) - ); - wholeTextView.layout( - getPaddingLeft(), - getPaddingTop(), - (r - l) - getPaddingRight(), - getPaddingTop() + wholeTextView.getMeasuredHeight() - ); - } - } - - public static class InlineLoadingTextView extends ViewGroup { - - public static final int paddingHorizontal = dp(6), - paddingVertical = 0; - - - public boolean showLoadingText = true; - - private final TextView fromTextView; - private final TextView toTextView; - - private final ValueAnimator loadingAnimator; - - private final long start = SystemClock.elapsedRealtime(); - public InlineLoadingTextView(Context context, CharSequence fromText, int fontSize, int textColor) { - super(context); - - setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical); - setClipChildren(false); - setWillNotDraw(false); - - fromTextView = new TextView(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MOST_SPEC, MOST_SPEC); - } - }; - fromTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize); - fromTextView.setTextColor(textColor); - fromTextView.setText(fromText); - fromTextView.setLines(1); - fromTextView.setMaxLines(1); - fromTextView.setSingleLine(true); - fromTextView.setEllipsize(null); - fromTextView.setFocusable(false); - fromTextView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); - addView(fromTextView); - - toTextView = new TextView(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MOST_SPEC, MOST_SPEC); - } - }; - toTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize); - toTextView.setTextColor(textColor); - toTextView.setLines(1); - toTextView.setMaxLines(1); - toTextView.setSingleLine(true); - toTextView.setEllipsize(null); - toTextView.setFocusable(true); - addView(toTextView); - - int c1 = Theme.getColor(Theme.key_dialogBackground), - c2 = Theme.getColor(Theme.key_dialogBackgroundGray); - LinearGradient gradient = new LinearGradient(0, 0, gradientWidth, 0, new int[]{ c1, c2, c1 }, new float[] { 0, 0.67f, 1f }, Shader.TileMode.REPEAT); - loadingPaint.setShader(gradient); - - loadingAnimator = ValueAnimator.ofFloat(0f, 1f); - loadingAnimator.addUpdateListener(a -> invalidate()); - loadingAnimator.setDuration(Long.MAX_VALUE); - loadingAnimator.start(); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - fromTextView.measure(0, 0); - toTextView.measure(0, 0); - super.onMeasure( - MeasureSpec.makeMeasureSpec( - (int) AndroidUtilities.lerp(fromTextView.getMeasuredWidth(), toTextView.getMeasuredWidth(), loadingT) + getPaddingLeft() + getPaddingRight(), - MeasureSpec.EXACTLY - ), - MeasureSpec.makeMeasureSpec( - Math.max(fromTextView.getMeasuredHeight(), toTextView.getMeasuredHeight()), - MeasureSpec.EXACTLY - ) - ); - } - - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - fromTextView.layout(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + fromTextView.getMeasuredWidth(), getPaddingTop() + fromTextView.getMeasuredHeight()); - toTextView.layout(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + toTextView.getMeasuredWidth(), getPaddingTop() + toTextView.getMeasuredHeight()); - updateWidth(); - } - - private void updateWidth() { - boolean updated; - - int newWidth = (int) AndroidUtilities.lerp(fromTextView.getMeasuredWidth(), toTextView.getMeasuredWidth(), loadingT) + getPaddingLeft() + getPaddingRight(); - int newHeight = Math.max(fromTextView.getMeasuredHeight(), toTextView.getMeasuredHeight()); - LayoutParams lp = getLayoutParams(); - if (lp == null) { - lp = new LinearLayout.LayoutParams(newWidth, newHeight); - updated = true; - } else { - updated = lp.width != newWidth || lp.height != newHeight; - lp.width = newWidth; - lp.height = newHeight; - } - - if (updated) - setLayoutParams(lp); - } - - protected void onLoadAnimation(float t) {} - - public boolean loaded = false; - public float loadingT = 0f; - private ValueAnimator loadedAnimator = null; - public void loaded(CharSequence loadedText) { - loaded(loadedText, 350,null); - } - public void loaded(CharSequence loadedText, Runnable onLoadEnd) { - loaded(loadedText, 350, onLoadEnd); - } - public void loaded(CharSequence loadedText, long duration, Runnable onLoadEnd) { - loaded = true; - toTextView.setText(loadedText); - - if (loadingAnimator.isRunning()) { - loadingAnimator.cancel(); - } - if (loadedAnimator == null) { - loadedAnimator = ValueAnimator.ofFloat(0f, 1f); - loadedAnimator.addUpdateListener(a -> { - loadingT = (float) a.getAnimatedValue(); - updateWidth(); - invalidate(); - onLoadAnimation(loadingT); - }); - loadedAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (onLoadEnd != null) - onLoadEnd.run(); - } - }); - loadedAnimator.setDuration(duration); - loadedAnimator.setInterpolator(CubicBezierInterpolator.EASE_BOTH); - loadedAnimator.start(); - } - } - public void set(CharSequence loadedText) { - loaded = true; - toTextView.setText(loadedText); - - if (loadingAnimator.isRunning()) { - loadingAnimator.cancel(); - } - if (loadedAnimator != null) { - loadedAnimator.cancel(); - loadedAnimator = null; - } - loadingT = 1f; - requestLayout(); - updateWidth(); - invalidate(); - onLoadAnimation(1f); - } - - private final RectF rect = new RectF(); - private final Path inPath = new Path(), - tempPath = new Path(), - loadingPath = new Path(), - shadePath = new Path(); - private final Paint loadingPaint = new Paint(); - private final float gradientWidth = dp(350f); - @Override - protected void onDraw(Canvas canvas) { - float w = getWidth(), h = getHeight(); - - float cx = LocaleController.isRTL ? Math.max(w / 2f, w - 8f) : Math.min(w / 2f, 8f), - cy = Math.min(h / 2f, 8f), - R = (float) Math.sqrt(Math.max( - Math.max(cx*cx + cy*cy, (w-cx)*(w-cx) + cy*cy), - Math.max(cx*cx + (h-cy)*(h-cy), (w-cx)*(w-cx) + (h-cy)*(h-cy)) - )), - r = loadingT * R; - inPath.reset(); - inPath.addCircle(cx, cy, r, Path.Direction.CW); - - canvas.save(); - canvas.clipPath(inPath, Region.Op.DIFFERENCE); - - loadingPaint.setAlpha((int) ((1f - loadingT) * 255)); - float dx = gradientWidth - (((SystemClock.elapsedRealtime() - start) / 1000f * gradientWidth) % gradientWidth); - shadePath.reset(); - shadePath.addRect(0, 0, w, h, Path.Direction.CW); - - loadingPath.reset(); - rect.set(0, 0, w, h); - loadingPath.addRoundRect(rect, dp(4), dp(4), Path.Direction.CW); - canvas.clipPath(loadingPath); - canvas.translate(-dx, 0); - shadePath.offset(dx, 0f, tempPath); - canvas.drawPath(tempPath, loadingPaint); - canvas.translate(dx, 0); - canvas.restore(); - - if (showLoadingText && fromTextView != null) { - canvas.save(); - rect.set(0, 0, w, h); - canvas.clipPath(inPath, Region.Op.DIFFERENCE); - canvas.translate(paddingHorizontal, paddingVertical); - canvas.saveLayerAlpha(rect, (int) (255 * .08f), Canvas.ALL_SAVE_FLAG); - fromTextView.draw(canvas); - canvas.restore(); - canvas.restore(); - } - - if (toTextView != null) { - canvas.save(); - canvas.clipPath(inPath); - canvas.translate(paddingHorizontal, paddingVertical); - canvas.saveLayerAlpha(rect, (int) (255 * loadingT), Canvas.ALL_SAVE_FLAG); - toTextView.draw(canvas); - if (loadingT < 1f) { - canvas.restore(); - } - canvas.restore(); - } - } - - @Override - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - return false; - } - } - - public static class LoadingTextView2 extends ViewGroup { - - public static final int paddingHorizontal = dp(6), - paddingVertical = dp(1.5f); - - public boolean showLoadingText = true; - - private final TextView fromTextView; - private final TextView toTextView; - - private final boolean scaleFromZero; - private final ValueAnimator loadingAnimator; - - private final long start = SystemClock.elapsedRealtime(); - private float scaleT = 1f; - public LoadingTextView2(Context context, CharSequence fromText, boolean scaleFromZero, int fontSize, int textColor) { - super(context); - - setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical); - setClipChildren(false); - setWillNotDraw(false); - setFocusable(false); - - fromTextView = new TextView(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MOST_SPEC); - } - }; - fromTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize); - fromTextView.setTextColor(textColor); - fromTextView.setText(fromText); - fromTextView.setLines(0); - fromTextView.setMaxLines(0); - fromTextView.setSingleLine(false); - fromTextView.setEllipsize(null); - fromTextView.setFocusable(false); - fromTextView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); - addView(fromTextView); - - toTextView = new TextView(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MOST_SPEC); - } - }; - toTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize); - toTextView.setTextColor(textColor); - toTextView.setLines(0); - toTextView.setMaxLines(0); - toTextView.setSingleLine(false); - toTextView.setEllipsize(null); - toTextView.setFocusable(false); - toTextView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); - addView(toTextView); - - int c1 = Theme.getColor(Theme.key_dialogBackground), - c2 = Theme.getColor(Theme.key_dialogBackgroundGray); - LinearGradient gradient = new LinearGradient(0, 0, gradientWidth, 0, new int[]{ c1, c2, c1 }, new float[] { 0, 0.67f, 1f }, Shader.TileMode.REPEAT); - loadingPaint.setShader(gradient); - - this.scaleFromZero = scaleFromZero; - loadingAnimator = ValueAnimator.ofFloat(0f, 1f); - if (scaleFromZero) - scaleT = 0; - loadingAnimator.addUpdateListener(a -> { - invalidate(); - if (scaleFromZero) { - boolean scaleTWasNoFull = scaleT < 1f; - scaleT = Math.min(1, (SystemClock.elapsedRealtime() - start) / 400f); - if (scaleTWasNoFull) { - updateHeight(); - } - } - }); - loadingAnimator.setDuration(Long.MAX_VALUE); - loadingAnimator.start(); - } - - public int innerHeight() { - return (int) (AndroidUtilities.lerp(fromTextView.getMeasuredHeight(), toTextView.getMeasuredHeight(), loadingT) * scaleT); - } - public int height() { - return getPaddingTop() + innerHeight() + getPaddingBottom(); - } - - private void updateHeight() { - ViewParent parent = getParent(); - if (parent instanceof TextBlocksLayout) { - ((TextBlocksLayout) parent).updateHeight(); - } - } - - public boolean loaded = false; - private float loadingT = 0f; - private ValueAnimator loadedAnimator = null; - public void loaded(CharSequence loadedText, Runnable onLoadEnd) { - loaded = true; - toTextView.setText(loadedText); - layout(); - - if (loadingAnimator.isRunning()) { - loadingAnimator.cancel(); - } - if (loadedAnimator == null) { - loadedAnimator = ValueAnimator.ofFloat(0f, 1f); - loadedAnimator.addUpdateListener(a -> { - loadingT = (float) a.getAnimatedValue(); - updateHeight(); - invalidate(); - }); - loadedAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (onLoadEnd != null) - onLoadEnd.run(); - } - }); - loadedAnimator.setDuration(350); - loadedAnimator.setInterpolator(CubicBezierInterpolator.EASE_BOTH); - loadedAnimator.start(); - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int width = MeasureSpec.getSize(widthMeasureSpec), - innerWidth = width - getPaddingLeft() - getPaddingRight(); - if (fromTextView.getMeasuredWidth() <= 0 || lastWidth != innerWidth) { - measureChild(fromTextView, innerWidth); - updateLoadingPath(); - } - if (toTextView.getMeasuredWidth() <= 0 || lastWidth != innerWidth) { - measureChild(toTextView, innerWidth); - } - lastWidth = innerWidth; - super.onMeasure( - MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(height(), MeasureSpec.EXACTLY) - ); - } - - int lastWidth = 0; - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - layout(r - l - getPaddingLeft() - getPaddingRight(), true); - } - private void layout(int width, boolean force) { - if (lastWidth != width || force) { - layout(lastWidth = width); - } - } - private void layout(int width) { - measureChild(fromTextView, width); - layoutChild(fromTextView, width); - updateLoadingPath(); - measureChild(toTextView, width); - layoutChild(toTextView, width); - updateHeight(); - } - private void layout() { - layout(lastWidth); - } - private void measureChild(View view, int width) { - view.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MOST_SPEC); - } - private void layoutChild(View view, int width) { - view.layout(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + width, getPaddingTop() + view.getMeasuredHeight()); - } - - private RectF fetchedPathRect = new RectF(); - private void updateLoadingPath() { - if (fromTextView != null && fromTextView.getMeasuredWidth() > 0) { - loadingPath.reset(); - Layout loadingLayout = fromTextView.getLayout(); - if (loadingLayout != null) { - CharSequence text = loadingLayout.getText(); - final int lineCount = loadingLayout.getLineCount(); - for (int i = 0; i < lineCount; ++i) { - float s = loadingLayout.getLineLeft(i), - e = loadingLayout.getLineRight(i), - l = Math.min(s, e), - r = Math.max(s, e); - int start = loadingLayout.getLineStart(i), - end = loadingLayout.getLineEnd(i); - boolean hasNonEmptyChar = false; - for (int j = start; j < end; ++j) { - char c = text.charAt(j); - if (c != '\n' && c != '\t' && c != ' ') { - hasNonEmptyChar = true; - break; - } - } - if (!hasNonEmptyChar) - continue; - fetchedPathRect.set( - l - paddingHorizontal, - loadingLayout.getLineTop(i) - paddingVertical, - r + paddingHorizontal, - loadingLayout.getLineBottom(i) + paddingVertical - ); - loadingPath.addRoundRect(fetchedPathRect, dp(4), dp(4), Path.Direction.CW); - } - } - } - } - - private final RectF rect = new RectF(); - private final Path inPath = new Path(), - tempPath = new Path(), - loadingPath = new Path(), - shadePath = new Path(); - private final Paint loadingPaint = new Paint(); - private final float gradientWidth = dp(350f); - @Override - protected void onDraw(Canvas canvas) { - float w = getWidth(), h = getHeight(); - - float cx = LocaleController.isRTL ? Math.max(w / 2f, w - 8f) : Math.min(w / 2f, 8f), - cy = Math.min(h / 2f, 8f), - R = (float) Math.sqrt(Math.max( - Math.max(cx*cx + cy*cy, (w-cx)*(w-cx) + cy*cy), - Math.max(cx*cx + (h-cy)*(h-cy), (w-cx)*(w-cx) + (h-cy)*(h-cy)) - )), - r = loadingT * R; - inPath.reset(); - inPath.addCircle(cx, cy, r, Path.Direction.CW); - - canvas.save(); - canvas.clipPath(inPath, Region.Op.DIFFERENCE); - - loadingPaint.setAlpha((int) ((1f - loadingT) * 255)); - float dx = gradientWidth - (((SystemClock.elapsedRealtime() - start) / 1000f * gradientWidth) % gradientWidth); - shadePath.reset(); - shadePath.addRect(0, 0, w, h, Path.Direction.CW); - - canvas.translate(paddingHorizontal, paddingVertical); - canvas.clipPath(loadingPath); - canvas.translate(-paddingHorizontal, -paddingVertical); - canvas.translate(-dx, 0); - shadePath.offset(dx, 0f, tempPath); - canvas.drawPath(tempPath, loadingPaint); - canvas.translate(dx, 0); - canvas.restore(); - - if (showLoadingText && fromTextView != null) { - canvas.save(); - rect.set(0, 0, w, h); - canvas.clipPath(inPath, Region.Op.DIFFERENCE); - canvas.translate(paddingHorizontal, paddingVertical); - canvas.saveLayerAlpha(rect, (int) (255 * .08f), Canvas.ALL_SAVE_FLAG); - fromTextView.draw(canvas); - canvas.restore(); - canvas.restore(); - } - - if (toTextView != null) { - canvas.save(); - canvas.clipPath(inPath); - canvas.translate(paddingHorizontal, paddingVertical); - canvas.saveLayerAlpha(rect, (int) (255 * loadingT), Canvas.ALL_SAVE_FLAG); - toTextView.draw(canvas); - if (loadingT < 1f) { - canvas.restore(); - } - canvas.restore(); - } - } - - @Override - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - return false; - } - } -} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert2.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert2.java index 403f65fd2c5..7ae9144ac22 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert2.java @@ -1,589 +1,228 @@ package org.telegram.ui.Components; import static org.telegram.messenger.AndroidUtilities.dp; +import static org.telegram.messenger.AndroidUtilities.dpf2; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; -import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.Region; -import android.graphics.Shader; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; -import android.net.Uri; import android.os.Build; -import android.os.Bundle; -import android.os.SystemClock; -import android.text.Layout; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextPaint; import android.text.TextUtils; -import android.text.method.LinkMovementMethod; import android.text.style.ClickableSpan; import android.text.style.URLSpan; -import android.text.util.Linkify; -import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.view.ViewParent; import android.view.WindowManager; +import android.view.animation.LinearInterpolator; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; -import android.widget.Toast; import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.core.math.MathUtils; +import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import org.json.JSONArray; -import org.json.JSONTokener; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ApplicationLoader; -import org.telegram.messenger.DispatchQueue; import org.telegram.messenger.Emoji; -import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.TranslateController; +import org.telegram.messenger.Utilities; import org.telegram.messenger.XiaomiUtilities; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBarMenuSubItem; +import org.telegram.ui.ActionBar.ActionBarPopupWindow; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.Theme; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.net.HttpURLConnection; -import java.net.URI; -import java.nio.charset.Charset; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; -public class TranslateAlert2 extends BottomSheet { +public class TranslateAlert2 extends BottomSheet implements NotificationCenter.NotificationCenterDelegate { - public static volatile DispatchQueue translateQueue = new DispatchQueue("translateQueue", false); + private Integer reqId; + private CharSequence reqText; + private ArrayList reqMessageEntities; + private TLRPC.InputPeer reqPeer; + private int reqMessageId; - public RecyclerListView listView; - private LinearLayoutManager layoutManager; - private View paddingView; -// private FrameLayout container; - private TextView titleView; - private LinearLayout subtitleView; - private InlineLoadingTextView subtitleFromView; - private ImageView subtitleArrowView; - private TextView subtitleToView; - private ImageView backButton; - private HeaderView header; - private FrameLayout headerShadowView; -// private NestedScrollView scrollView; - private TextBlocksLayout textsView; - private TextView buttonTextView; - private FrameLayout buttonContainerView; - private FrameLayout buttonView; - private FrameLayout buttonShadowView; - private TextView allTextsView; -// private FrameLayout textsContainerView; - private FrameLayout bulletinContainer; - -// private FrameLayout.LayoutParams titleLayout; -// private FrameLayout.LayoutParams subtitleLayout; -// private FrameLayout.LayoutParams headerLayout; -// private FrameLayout.LayoutParams scrollViewLayout; - - private int blockIndex = 0; - private ArrayList textBlocks; -// -// private boolean canExpand() { -// return ( -// textsView.getBlocksCount() < textBlocks.size() || -// minHeight(true) >= (AndroidUtilities.displayMetrics.heightPixels * heightMaxPercent) -// ); -// } -// private void updateCanExpand() { -// boolean canExpand = canExpand(); -// if (containerOpenAnimationT > 0f && !canExpand) { -// openAnimationTo(0f, false); -// } -// -// buttonShadowView.animate().alpha(canExpand ? 1f : 0f).setDuration((long) (Math.abs(buttonShadowView.getAlpha() - (canExpand ? 1f : 0f)) * 220)).start(); -// } - - public interface OnLinkPress { - public boolean run(URLSpan urlSpan); - } - - @Override - public void onBackPressed() { - dismiss(); - } - - private class HeaderView extends FrameLayout { - - public HeaderView(Context context) { - super(context); - } - - private float expandedT = 0f; - public void setExpandedT(float value) { - backButton.setAlpha(value); - headerShadowView.setAlpha(value); - if (Math.abs(expandedT - value) > 0.01f) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && expandedT > .5f != value > .5f) { - int flags = containerView.getSystemUiVisibility(); - if (value > .5f) { - flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; - } else { - flags &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; - } - containerView.setSystemUiVisibility(flags); - } - expandedT = value; - invalidate(); - } - } + private String fromLanguage, toLanguage; + private String prevToLanguage; - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - titleView.layout( - dp(22), - dp(22), - right - left - dp(22), - dp(22) + titleView.getMeasuredHeight() - ); - subtitleView.layout( - dp(22) - LoadingTextView2.paddingHorizontal, - dp(47) - LoadingTextView2.paddingVertical, - right - left - dp(22) - LoadingTextView2.paddingHorizontal, - dp(47) - LoadingTextView2.paddingVertical + subtitleView.getMeasuredHeight() - ); - backButton.layout(0, 0, dp(56), dp(56)); - headerShadowView.layout(0, dp(55), right - left, dp(56)); - } + private HeaderView headerView; + private LoadingTextView loadingTextView; + private FrameLayout textViewContainer; + private LinkSpanDrawable.LinksTextView textView; - @Override - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - if (child == titleView) { - canvas.save(); - canvas.translate(dp(50 * expandedT), dp(-14 * expandedT)); - canvas.scale(1f - expandedT * 0.111f, 1f - expandedT * 0.111f, child.getX(), child.getY() + child.getMeasuredHeight() / 2); - boolean result = super.drawChild(canvas, child, drawingTime); - canvas.restore(); - return result; - } else if (child == subtitleView) { - canvas.save(); - canvas.translate(dp(50 * expandedT), dp(-17 * expandedT)); - boolean result = super.drawChild(canvas, child, drawingTime); - canvas.restore(); - return result; - } else { - return super.drawChild(canvas, child, drawingTime); - } - } + private boolean sheetTopNotAnimate; + private RecyclerListView listView; + private LinearLayoutManager layoutManager; + private PaddedAdapter adapter; - @Override - protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) { - if (child == backButton) { - backButton.measure( - MeasureSpec.makeMeasureSpec(dp(56), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(dp(56), MeasureSpec.EXACTLY) - ); - } else { - super.measureChild(child, parentWidthMeasureSpec, parentHeightMeasureSpec); - } - } - } + private View buttonShadowView; + private FrameLayout buttonView; + private TextView buttonTextView; - private boolean allowScroll = true; - private String fromLanguage, toLanguage; - private CharSequence text; private BaseFragment fragment; - private boolean noforwards; - private OnLinkPress onLinkPress; - private Runnable onDismiss; - - public void updateCanExpand() { - boolean canExpand = listView.canScrollVertically(1) || listView.canScrollVertically(-1); - float canExpandAlpha = canExpand ? 1f : 0f; - buttonShadowView.animate().alpha(canExpandAlpha).setDuration(200).start(); - allowScroll = canExpand; + private Utilities.CallbackReturn onLinkPress; + private boolean firstTranslation = true; + + public TranslateAlert2( + Context context, + String fromLanguage, String toLanguage, + CharSequence text, ArrayList entities, + Theme.ResourcesProvider resourcesProvider + ) { + this(context, fromLanguage, toLanguage, text, entities, null, 0, resourcesProvider); } - public TranslateAlert2(BaseFragment fragment, Context context, String fromLanguage, String toLanguage, CharSequence text, boolean noforwards, OnLinkPress onLinkPress, Runnable onDismiss) { - super(context, false); + private TranslateAlert2( + Context context, + String fromLanguage, String toLanguage, + CharSequence text, ArrayList entities, TLRPC.InputPeer peer, int messageId, + Theme.ResourcesProvider resourcesProvider + ) { + super(context, false, resourcesProvider); + + backgroundPaddingLeft = 0; + fixNavigationBar(); - this.onLinkPress = onLinkPress; - this.noforwards = noforwards; - this.fragment = fragment; - this.fromLanguage = fromLanguage != null && fromLanguage.equals("und") ? "auto" : fromLanguage; + this.reqText = text; + this.reqPeer = peer; + this.reqMessageId = messageId; + + this.fromLanguage = fromLanguage; this.toLanguage = toLanguage; - this.text = text; - this.textBlocks = cutInBlocks(text, 1024); - this.onDismiss = onDismiss; - if (noforwards) { - getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); - } + containerView = new ContainerView(context); + sheetTopAnimated = new AnimatedFloat(containerView, 320, CubicBezierInterpolator.EASE_OUT_QUINT); + + loadingTextView = new LoadingTextView(context); + loadingTextView.setPadding(dp(22), dp(12), dp(22), dp(6)); + loadingTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, SharedConfig.fontSize); + loadingTextView.setTextColor(getThemedColor(Theme.key_dialogTextBlack)); + loadingTextView.setLinkTextColor(Theme.multAlpha(getThemedColor(Theme.key_dialogTextBlack), .2f)); + loadingTextView.setText(Emoji.replaceEmoji(text == null ? "" : text.toString(), loadingTextView.getPaint().getFontMetricsInt(), true)); - allTextsView = new TextView(context) { + textViewContainer = new FrameLayout(context) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MOST_SPEC); - } - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - canvas.save(); - canvas.translate(getPaddingLeft(), getPaddingTop()); - if (links != null && links.draw(canvas)) { - invalidate(); - } - canvas.restore(); - } - @Override - public boolean onTextContextMenuItem(int id) { - if (id == android.R.id.copy && isFocused()) { - android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); - android.content.ClipData clip = android.content.ClipData.newPlainText( - "label", - getText().subSequence( - Math.max(0, Math.min(getSelectionStart(), getSelectionEnd())), - Math.max(0, Math.max(getSelectionStart(), getSelectionEnd())) - ) - ); - clipboard.setPrimaryClip(clip); - BulletinFactory.of(bulletinContainer, null).createCopyBulletin(LocaleController.getString("TextCopied", R.string.TextCopied)).show(); - clearFocus(); - return true; - } else { - return super.onTextContextMenuItem(id); - } + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), heightMeasureSpec); } }; - links = new LinkSpanDrawable.LinkCollector(allTextsView); - allTextsView.setTextColor(0x00000000); - allTextsView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - allTextsView.setTextIsSelectable(!noforwards); - allTextsView.setHighlightColor(Theme.getColor(Theme.key_chat_inTextSelectionHighlight)); + textView = new LinkSpanDrawable.LinksTextView(context, resourcesProvider); + textView.setDisablePaddingsOffsetY(true); + textView.setPadding(dp(22), dp(12), dp(22), dp(6)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, SharedConfig.fontSize); + textView.setTextColor(getThemedColor(Theme.key_dialogTextBlack)); + textView.setLinkTextColor(getThemedColor(Theme.key_chat_messageLinkIn)); + textView.setTextIsSelectable(true); + textView.setHighlightColor(getThemedColor(Theme.key_chat_inTextSelectionHighlight)); + int handleColor = getThemedColor(Theme.key_chat_TextSelectionCursor); try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && !XiaomiUtilities.isMIUI()) { - final int handleColor = Theme.getColor(Theme.key_chat_TextSelectionCursor); - - Drawable left = allTextsView.getTextSelectHandleLeft(); + Drawable left = textView.getTextSelectHandleLeft(); left.setColorFilter(handleColor, PorterDuff.Mode.SRC_IN); - allTextsView.setTextSelectHandleLeft(left); + textView.setTextSelectHandleLeft(left); - Drawable right = allTextsView.getTextSelectHandleRight(); + Drawable right = textView.getTextSelectHandleRight(); right.setColorFilter(handleColor, PorterDuff.Mode.SRC_IN); - allTextsView.setTextSelectHandleRight(right); + textView.setTextSelectHandleRight(right); } - } catch (Exception ignore) {} - allTextsView.setMovementMethod(new LinkMovementMethod()); - - textsView = new TextBlocksLayout(context, dp(16), Theme.getColor(Theme.key_dialogTextBlack), allTextsView) { - @Override - protected void onHeightUpdated(int height, int dy) { -// if (dy != 0 && listView != null && listView.canScrollVertically(-dy)) { -// try { -// listView.scrollBy(0, -dy); -// } catch (Exception ignore) {} -// } - paddingView.requestFocus(); - paddingView.requestLayout(); - } - }; - textsView.setPadding( - dp(22) - LoadingTextView2.paddingHorizontal, - dp(12 + 8) - LoadingTextView2.paddingVertical, - dp(22) - LoadingTextView2.paddingHorizontal, - dp(12) - LoadingTextView2.paddingVertical - ); - for (CharSequence blockText : textBlocks) { - textsView.addBlock(blockText); - } - - final Paint backgroundPaint = new Paint(); - backgroundPaint.setColor(Theme.getColor(Theme.key_dialogBackground)); - backgroundPaint.setShadowLayer(dp(2), 0, dp(-0.66f), 0x1e000000); - final Paint navigationBarPaint = new Paint(); - navigationBarPaint.setColor(Theme.getColor(Theme.key_dialogBackgroundGray)); - - containerView = new FrameLayout(context) { - @Override - public boolean hasOverlappingRendering() { - return false; - } - - @Override - protected void dispatchDraw(Canvas canvas) { - float top = getCurrentItemTop(); - float expandedT = 1f - Math.max(0, Math.min(top / dp(48), 1)); - header.setTranslationY(top); - header.setExpandedT(expandedT); - updateCanExpand(); - float r = dp(12) * (1f - expandedT); - AndroidUtilities.rectTmp.set(backgroundPaddingLeft, getPaddingTop() + top - (AndroidUtilities.statusBarHeight + dp(8)) * expandedT + dp(8), getWidth() - backgroundPaddingLeft, getPaddingTop() + top + dp(20)); - canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, navigationBarPaint); - AndroidUtilities.rectTmp.set(backgroundPaddingLeft, getPaddingTop() + top, getWidth() - backgroundPaddingLeft, getPaddingTop() + getHeight() + dp(12)); - canvas.drawRoundRect(AndroidUtilities.rectTmp, r, r, backgroundPaint); - - super.dispatchDraw(canvas); - } - - @Override - public void setTranslationY(float translationY) { - super.setTranslationY(translationY); - onContainerTranslationYChanged(translationY); - } - - @Override - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - if (child == listView) { - canvas.save(); - canvas.clipRect(0, getPaddingTop() + listView.getPaddingTop(), getWidth(), getHeight() - listView.getPaddingBottom()); - boolean result = super.drawChild(canvas, child, drawingTime); - canvas.restore(); - return result; - } else { - return super.drawChild(canvas, child, drawingTime); - } - } - }; - containerView.setPadding(backgroundPaddingLeft, AndroidUtilities.statusBarHeight, backgroundPaddingLeft, 0); - containerView.setClipChildren(false); - containerView.setClipToPadding(false); - containerView.setWillNotDraw(false); + } catch (Exception e) {} + textViewContainer.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); listView = new RecyclerListView(context) { - @Override - public View getFocusedChild() { - return textsView; - } - - @Override - public void onScrolled(int dx, int dy) { - checkForNextLoading(); - super.onScrolled(dx, dy); - containerView.invalidate(); - } - - @Override - public void onScrollStateChanged(int state) { - super.onScrollStateChanged(state); - - if (state == SCROLL_STATE_IDLE && header.expandedT > 0 && header.expandedT < 1) { - smoothScrollBy(0, (int) header.getTranslationY()); + public boolean dispatchTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getY() < getSheetTop() - getTop()) { + dismiss(); + return true; } + return super.dispatchTouchEvent(ev); } @Override - public boolean onTouchEvent(MotionEvent e) { - if (!allowScroll) { - return false; - } - return super.onTouchEvent(e); + protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { + return true; } @Override - public boolean onInterceptTouchEvent(MotionEvent e) { - if (!allowScroll) { - return false; - } - return super.onInterceptTouchEvent(e); - } + public void requestChildFocus(View child, View focused) {} }; - listView.setClipChildren(true); + listView.setOverScrollMode(View.OVER_SCROLL_IF_CONTENT_SCROLLS); + listView.setPadding(0, AndroidUtilities.statusBarHeight + dp(56), 0, dp(80)); listView.setClipToPadding(true); - listView.setPadding(0, dp(56), 0, dp(80)); - listView.setLayoutManager(layoutManager = new LinearLayoutManager(context) { - @Override - public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { - super.onLayoutChildren(recycler, state); - - } - }); - layoutManager.setOrientation(RecyclerView.VERTICAL); - layoutManager.setReverseLayout(true); - listView.setAdapter(new RecyclerView.Adapter() { - @NonNull - @Override - public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - if (viewType == 0) { - return new RecyclerListView.Holder(textsView); - } - return new RecyclerListView.Holder(paddingView); - } - - @Override - public int getItemViewType(int position) { - return position; - } - - @Override - public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {} - + listView.setLayoutManager(layoutManager = new LinearLayoutManager(context)); + listView.setAdapter(adapter = new PaddedAdapter(context, loadingTextView)); + listView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override - public int getItemCount() { - return 2; + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + containerView.invalidate(); + updateButtonShadow(listView.canScrollVertically(1)); } - }); - View redDot = new View(context) { @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(32), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(32), MeasureSpec.EXACTLY)); + public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { + if (newState == RecyclerView.SCROLL_STATE_IDLE) { + sheetTopNotAnimate = false; + } + if ((newState == RecyclerView.SCROLL_STATE_IDLE || newState == RecyclerView.SCROLL_STATE_SETTLING) && getSheetTop(false) > 0 && getSheetTop(false) < dp(64 + 32) && listView.canScrollVertically(1) && hasEnoughHeight()) { + sheetTopNotAnimate = true; + listView.smoothScrollBy(0, (int) getSheetTop(false)); + } } - }; - redDot.setBackgroundColor(0xffff0000); - containerView.addView(redDot); - - containerView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - - header = new HeaderView(context); - header.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - containerView.addView(header, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.FILL_HORIZONTAL)); - - titleView = new TextView(context); - titleView.setPivotX(LocaleController.isRTL ? titleView.getWidth() : 0); - titleView.setPivotY(0); - titleView.setLines(1); - titleView.setText(LocaleController.getString("AutomaticTranslation", R.string.AutomaticTranslation)); - titleView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); - titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - titleView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); - titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); - header.addView(titleView, LayoutHelper.createFrame( - LayoutHelper.MATCH_PARENT, - LayoutHelper.WRAP_CONTENT, - Gravity.FILL_HORIZONTAL | Gravity.TOP, - 22, 22,22, 0 - )); - titleView.post(() -> { - titleView.setPivotX(LocaleController.isRTL ? titleView.getWidth() : 0); }); - - subtitleView = new LinearLayout(context); - subtitleView.setOrientation(LinearLayout.HORIZONTAL); - if (Build.VERSION.SDK_INT >= 17) { - subtitleView.setLayoutDirection(LocaleController.isRTL ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR); - } - subtitleView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); - - String fromLanguageName = languageName(fromLanguage); - subtitleFromView = new InlineLoadingTextView(context, fromLanguageName == null ? languageName(toLanguage) : fromLanguageName, dp(14), Theme.getColor(Theme.key_player_actionBarSubtitle)) { + DefaultItemAnimator itemAnimator = new DefaultItemAnimator() { @Override - protected void onLoadAnimation(float t) { - MarginLayoutParams lp = (MarginLayoutParams) subtitleFromView.getLayoutParams(); - if (lp != null) { - if (LocaleController.isRTL) { - lp.leftMargin = dp(2f - t * 6f); - } else { - lp.rightMargin = dp(2f - t * 6f); - } - subtitleFromView.setLayoutParams(lp); - } - } - }; - subtitleFromView.showLoadingText = false; - subtitleArrowView = new ImageView(context); - subtitleArrowView.setImageResource(R.drawable.search_arrow); - subtitleArrowView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_player_actionBarSubtitle), PorterDuff.Mode.MULTIPLY)); - if (LocaleController.isRTL) { - subtitleArrowView.setScaleX(-1f); - } - - subtitleToView = new TextView(context); - subtitleToView.setLines(1); - subtitleToView.setTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle)); - subtitleToView.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp(14)); - subtitleToView.setText(languageName(toLanguage)); - - if (LocaleController.isRTL) { - subtitleView.setPadding(InlineLoadingTextView.paddingHorizontal, 0, 0, 0); - subtitleView.addView(subtitleToView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); - subtitleView.addView(subtitleArrowView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 3, 1, 3, 0)); - subtitleView.addView(subtitleFromView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 0, 0, 0)); - } else { - subtitleView.setPadding(0, 0, InlineLoadingTextView.paddingHorizontal, 0); - subtitleView.addView(subtitleFromView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 0, 0, 0)); - subtitleView.addView(subtitleArrowView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 3, 1, 3, 0)); - subtitleView.addView(subtitleToView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); - } - if (fromLanguageName != null) { - subtitleFromView.set(fromLanguageName); - } - - header.addView(subtitleView, LayoutHelper.createFrame( - LayoutHelper.MATCH_PARENT, - LayoutHelper.WRAP_CONTENT, - Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), - 22 - LoadingTextView2.paddingHorizontal / AndroidUtilities.density, - 47 - LoadingTextView2.paddingVertical / AndroidUtilities.density, - 22 - LoadingTextView2.paddingHorizontal / AndroidUtilities.density, - 0 - )); - - backButton = new ImageView(context); - backButton.setImageResource(R.drawable.ic_ab_back); - backButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogTextBlack), PorterDuff.Mode.MULTIPLY)); - backButton.setScaleType(ImageView.ScaleType.FIT_CENTER); - backButton.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0); - backButton.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_dialogButtonSelector))); - backButton.setClickable(false); - backButton.setAlpha(0f); - backButton.setOnClickListener(e -> { - if (backButton.getAlpha() > .5f) { - dismiss(); + protected void onChangeAnimationUpdate(RecyclerView.ViewHolder holder) { + containerView.invalidate(); } - }); - header.addView(backButton, LayoutHelper.createFrame(56, 56, Gravity.LEFT | Gravity.CENTER_HORIZONTAL)); - headerShadowView = new FrameLayout(context); - headerShadowView.setBackgroundColor(Theme.getColor(Theme.key_dialogShadowLine)); - headerShadowView.setAlpha(0); - header.addView(headerShadowView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL)); - - paddingView = new View(context) { @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int padding = (int) Math.max(AndroidUtilities.displaySize.y * .5f, listView.getMeasuredHeight() - listView.getPaddingTop() - listView.getPaddingBottom() - textsView.height()); - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(padding, MeasureSpec.EXACTLY)); + protected void onMoveAnimationUpdate(RecyclerView.ViewHolder holder) { + containerView.invalidate(); } }; + itemAnimator.setDurations(180); + itemAnimator.setInterpolator(new LinearInterpolator()); + listView.setItemAnimator(itemAnimator); + containerView.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); -// -// header.setClipChildren(false); -// container.addView(header, headerLayout = LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 70, Gravity.FILL_HORIZONTAL | Gravity.TOP)); - -// textsContainerView = new FrameLayout(context); -// textsContainerView.addView(textsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - -// scrollView.addView(textsContainerView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f)); - -// container.addView(scrollView, scrollViewLayout = LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.FILL, 0, 70, 0, 81)); - - fetchNext(); + headerView = new HeaderView(context); + containerView.addView(headerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 78, Gravity.TOP | Gravity.FILL_HORIZONTAL)); + buttonView = new FrameLayout(context); + buttonView.setBackgroundColor(getThemedColor(Theme.key_dialogBackground)); -// container.addView(buttonShadowView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0, 0, 80)); + buttonShadowView = new View(context); + buttonShadowView.setBackgroundColor(getThemedColor(Theme.key_dialogShadowLine)); + buttonShadowView.setAlpha(0); + buttonView.addView(buttonShadowView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, AndroidUtilities.getShadowHeight() / dpf2(1), Gravity.TOP | Gravity.FILL_HORIZONTAL)); buttonTextView = new TextView(context); buttonTextView.setLines(1); @@ -595,1219 +234,873 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); buttonTextView.setText(LocaleController.getString("CloseTranslation", R.string.CloseTranslation)); + buttonTextView.setBackground(Theme.AdaptiveRipple.filledRect(Theme.getColor(Theme.key_featuredStickers_addButton), 6)); + buttonTextView.setOnClickListener(e -> dismiss()); + buttonView.addView(buttonTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 16, 16, 16, 16)); - buttonView = new FrameLayout(context); - buttonView.setBackground(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), Theme.getColor(Theme.key_featuredStickers_addButton), Theme.getColor(Theme.key_featuredStickers_addButtonPressed))); - buttonView.addView(buttonTextView); - buttonView.setOnClickListener(e -> dismiss()); - - buttonContainerView = new FrameLayout(context); - buttonContainerView.addView(buttonView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 16, 16, 16, 16)); - - buttonShadowView = new FrameLayout(context); - buttonShadowView.setBackgroundColor(Theme.getColor(Theme.key_dialogShadowLine)); - buttonShadowView.setAlpha(0); - buttonContainerView.addView(buttonShadowView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1, Gravity.TOP | Gravity.FILL_HORIZONTAL)); - - containerView.addView(buttonContainerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 80, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL)); + containerView.addView(buttonView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL)); - bulletinContainer = new FrameLayout(context); - containerView.addView(bulletinContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, 0, 0, 81)); + translate(); } - private float getCurrentItemTop() { - View child = listView.getChildAt(0); - if (child == null) { - return 0; + private boolean hasEnoughHeight() { + float height = 0; + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + if (listView.getChildAdapterPosition(child) == 1) + height += child.getHeight(); } - RecyclerListView.Holder holder = (RecyclerListView.Holder) listView.findContainingViewHolder(child); - if (holder != null && holder.getAdapterPosition() == 0) { - return Math.max(0, child.getY() - header.getMeasuredHeight()); - } - return 0; - } - - @Override - protected boolean canDismissWithSwipe() { - return !listView.canScrollVertically(-1); - } - - // private boolean scrollAtBottom() { -// View view = (View) scrollView.getChildAt(scrollView.getChildCount() - 1); -// int bottom = view.getBottom(); -// LoadingTextView2 lastUnloadedBlock = textsView.getFirstUnloadedBlock(); -// if (lastUnloadedBlock != null) { -// bottom = lastUnloadedBlock.getTop(); -// } -// int diff = (bottom - (scrollView.getHeight() + scrollView.getScrollY())); -// return diff <= textsContainerView.getPaddingBottom(); -// } - - private boolean hasSelection() { - return allTextsView.hasSelection(); + return height >= listView.getHeight() - listView.getPaddingTop() - listView.getPaddingBottom(); } - private Rect containerRect = new Rect(); - private Rect textRect = new Rect(); - private Rect translateMoreRect = new Rect(); - private Rect buttonRect = new Rect(); - private Rect backRect = new Rect(); - private Rect scrollRect = new Rect(); - private float fromY = 0; - private boolean pressedOutside = false; - private boolean maybeScrolling = false; - private boolean scrolling = false; - private boolean fromScrollRect = false; - private boolean fromTranslateMoreView = false; - private float fromScrollViewY = 0; - private Spannable allTexts = null; - private LinkSpanDrawable pressedLink; - private LinkSpanDrawable.LinkCollector links; - -// @Override -// public boolean dispatchTouchEvent(@NonNull MotionEvent event) { -// try { -// float x = event.getX(); -// float y = event.getY(); -// -// container.getGlobalVisibleRect(containerRect); -// if (!containerRect.contains((int) x, (int) y)) { -// if (event.getAction() == MotionEvent.ACTION_DOWN) { -// pressedOutside = true; -// return true; -// } else if (event.getAction() == MotionEvent.ACTION_UP) { -// if (pressedOutside) { -// pressedOutside = false; -// dismiss(); -// return true; -// } -// } -// } -// -// try { -// allTextsView.getGlobalVisibleRect(textRect); -// if (textRect.contains((int) x, (int) y) && !maybeScrolling) { -// Layout allTextsLayout = allTextsView.getLayout(); -// int tx = (int) (x - allTextsView.getLeft() - container.getLeft()), -// ty = (int) (y - allTextsView.getTop() - container.getTop() - scrollView.getTop() + scrollView.getScrollY()); -// final int line = allTextsLayout.getLineForVertical(ty); -// final int off = allTextsLayout.getOffsetForHorizontal(line, tx); -// -// final float left = allTextsLayout.getLineLeft(line); -// if (allTexts instanceof Spannable && left <= tx && left + allTextsLayout.getLineWidth(line) >= tx) { -// ClickableSpan[] linkSpans = allTexts.getSpans(off, off, ClickableSpan.class); -// if (linkSpans != null && linkSpans.length >= 1) { -// if (event.getAction() == MotionEvent.ACTION_UP && pressedLink.getSpan() == linkSpans[0]) { -// ((ClickableSpan) pressedLink.getSpan()).onClick(allTextsView); -// if (links != null) { -// links.removeLink(pressedLink); -// } -// pressedLink = null; -// allTextsView.setTextIsSelectable(!noforwards); -// } else if (event.getAction() == MotionEvent.ACTION_DOWN) { -// pressedLink = new LinkSpanDrawable(linkSpans[0], fragment.getResourceProvider(), tx, ty, false); -// if (links != null) { -// links.addLink(pressedLink); -// } -// LinkPath path = pressedLink.obtainNewPath(); -// int start = allTexts.getSpanStart(pressedLink.getSpan()); -// int end = allTexts.getSpanEnd(pressedLink.getSpan()); -// path.setCurrentLayout(allTextsLayout, start, 0); -// allTextsLayout.getSelectionPath(start, end, path); -// } -// allTextsView.invalidate(); -// return true; -// } -// } -// } -// if (pressedLink != null) { -// if (links != null) { -// links.clear(); -// } -// pressedLink = null; -// } -// } catch (Exception e2) { -// e2.printStackTrace(); -// } -// -// scrollView.getGlobalVisibleRect(scrollRect); -// backButton.getGlobalVisibleRect(backRect); -// buttonView.getGlobalVisibleRect(buttonRect); -// if (pressedLink == null && /*!(scrollRect.contains((int) x, (int) y) && !canExpand() && containerOpenAnimationT < .5f && !scrolling) &&*/ !hasSelection()) { -// if ( -// !backRect.contains((int) x, (int) y) && -// !buttonRect.contains((int) x, (int) y) && -// event.getAction() == MotionEvent.ACTION_DOWN -// ) { -// fromScrollRect = scrollRect.contains((int) x, (int) y) && (containerOpenAnimationT > 0 || !canExpand()); -// maybeScrolling = true; -// scrolling = scrollRect.contains((int) x, (int) y) && textsView.getBlocksCount() > 0 && !((LoadingTextView2) textsView.getBlockAt(0)).loaded; -// fromY = y; -// fromScrollY = getScrollY(); -// fromScrollViewY = scrollView.getScrollY(); -// return super.dispatchTouchEvent(event) || true; -// } else if (maybeScrolling && (event.getAction() == MotionEvent.ACTION_MOVE || event.getAction() == MotionEvent.ACTION_UP)) { -// float dy = fromY - y; -// if (fromScrollRect) { -// dy = -Math.max(0, -(fromScrollViewY + dp(48)) - dy); -// if (dy < 0) { -// scrolling = true; -// allTextsView.setTextIsSelectable(false); -// } -// } else if (Math.abs(dy) > dp(4) && !fromScrollRect) { -// scrolling = true; -// allTextsView.setTextIsSelectable(false); -// scrollView.stopNestedScroll(); -// allowScroll = false; -// } -// float fullHeight = AndroidUtilities.displayMetrics.heightPixels, -// minHeight = Math.min(minHeight(), fullHeight * heightMaxPercent); -// float scrollYPx = minHeight * (1f - -Math.min(Math.max(fromScrollY, -1), 0)) + (fullHeight - minHeight) * Math.min(1, Math.max(fromScrollY, 0)) + dy; -// float scrollY = scrollYPx > minHeight ? (scrollYPx - minHeight) / (fullHeight - minHeight) : -(1f - scrollYPx / minHeight); -// if (!canExpand()) { -// scrollY = Math.min(scrollY, 0); -// } -// updateCanExpand(); -// -// if (scrolling) { -// setScrollY(scrollY); -// if (event.getAction() == MotionEvent.ACTION_UP) { -// scrolling = false; -// allTextsView.setTextIsSelectable(!noforwards); -// maybeScrolling = false; -// allowScroll = true; -// scrollYTo( -// Math.abs(dy) > dp(16) ? -// Math.round(fromScrollY) + (scrollY > fromScrollY ? 1f : -1f) * (float) Math.ceil(Math.abs(fromScrollY - scrollY)) : -// Math.round(fromScrollY), -// () -> { -// contentView.post(this::checkForNextLoading); -// } -// ); -// } -// return true; -// } -// } -// } -// if (hasSelection() && maybeScrolling) { -// scrolling = false; -// allTextsView.setTextIsSelectable(!noforwards); -// maybeScrolling = false; -// allowScroll = true; -// scrollYTo(Math.round(fromScrollY)); -// } -// return super.dispatchTouchEvent(event); -// } catch (Exception e) { -// e.printStackTrace(); -// return super.dispatchTouchEvent(event); -// } -// return super.dispatchTouchEvent(event); -// } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - containerView.setPadding(backgroundPaddingLeft, AndroidUtilities.statusBarHeight, backgroundPaddingLeft, 0); - } -// -// contentView.setPadding(0, AndroidUtilities.statusBarHeight, 0, 0); -// contentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); -// setContentView(contentView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); -// -// Window window = getWindow(); -// window.setWindowAnimations(R.style.DialogNoAnimation); -// WindowManager.LayoutParams params = window.getAttributes(); -// params.width = ViewGroup.LayoutParams.MATCH_PARENT; -// params.gravity = Gravity.TOP | Gravity.LEFT; -// params.dimAmount = 0; -// params.flags &= ~WindowManager.LayoutParams.FLAG_DIM_BEHIND; -// if (Build.VERSION.SDK_INT >= 21) { -// params.flags |= -// WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | -// WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM | -// WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | -// WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; -// } -// params.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; -// params.height = ViewGroup.LayoutParams.MATCH_PARENT; -// if (Build.VERSION.SDK_INT >= 28) { -// params.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; -// } -// window.setAttributes(params); -// } - - protected ColorDrawable backDrawable = new ColorDrawable(0xff000000) { - @Override - public void setAlpha(int alpha) { - super.setAlpha(alpha); -// contentView.invalidate(); + public void translate() { + if (reqId != null) { + ConnectionsManager.getInstance(currentAccount).cancelRequest(reqId, true); + reqId = null; } - }; - - public String languageName(String locale) { - // sorry, no more vodka - if (locale == null || locale.equals("und") || locale.equals("auto")) { - return null; - } - LocaleController.LocaleInfo thisLanguageInfo = LocaleController.getInstance().getBuiltinLanguageByPlural(locale); - if (thisLanguageInfo == null) { - return null; - } - LocaleController.LocaleInfo currentLanguageInfo = LocaleController.getInstance().getCurrentLocaleInfo(); - boolean isCurrentLanguageEnglish = currentLanguageInfo != null && "en".equals(currentLanguageInfo.pluralLangCode); - if (isCurrentLanguageEnglish) { - // trying to show this language in a language of the interface, but there are only names in english and its own - return thisLanguageInfo.nameEnglish; + TLRPC.TL_messages_translateText req = new TLRPC.TL_messages_translateText(); + TLRPC.TL_textWithEntities textWithEntities = new TLRPC.TL_textWithEntities(); + textWithEntities.text = reqText == null ? "" : reqText.toString(); + if (reqMessageEntities != null) { + textWithEntities.entities = reqMessageEntities; + } + if (reqPeer != null) { + req.flags |= 1; + req.peer = reqPeer; + req.id.add(reqMessageId); } else { - return thisLanguageInfo.name; - } - } - - public void updateSourceLanguage() { - String fromLanguageName = languageName(fromLanguage); - if (fromLanguageName != null) { - subtitleView.setAlpha(1); - if (!subtitleFromView.loaded) { - subtitleFromView.loaded(fromLanguageName); - } - } else if (loaded) { - subtitleView.animate().alpha(0).setDuration(150).start(); - titleView.animate().scaleX(1.2f).scaleY(1.2f).translationY(dp(5)).setDuration(150).start(); + req.flags |= 2; + req.text.add(textWithEntities); } +// if (fromLanguage != null && !"und".equals(fromLanguage)) { +// req.flags |= 4; +// req.from_lang = fromLanguage; +// } + String lang = toLanguage; + if (lang != null) { + lang = lang.split("_")[0]; + } + if ("nb".equals(lang)) { + lang = "no"; + } + req.to_lang = lang; + reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> { + AndroidUtilities.runOnUIThread(() -> { + reqId = null; + if (res instanceof TLRPC.TL_messages_translateResult && + !((TLRPC.TL_messages_translateResult) res).result.isEmpty() && + ((TLRPC.TL_messages_translateResult) res).result.get(0) != null && + ((TLRPC.TL_messages_translateResult) res).result.get(0).text != null + ) { + firstTranslation = false; + TLRPC.TL_textWithEntities text = preprocess(textWithEntities, ((TLRPC.TL_messages_translateResult) res).result.get(0)); + CharSequence translated = SpannableStringBuilder.valueOf(text.text); + MessageObject.addEntitiesToText(translated, text.entities, false, true, false, false); + translated = preprocessText(translated); + textView.setText(translated); + adapter.updateMainView(textViewContainer); + } else if (firstTranslation) { + dismiss(); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.showBulletin, Bulletin.TYPE_ERROR, LocaleController.getString("TranslationFailedAlert2", R.string.TranslationFailedAlert2)); + } else { + BulletinFactory.of((FrameLayout) containerView, resourcesProvider).createErrorBulletin(LocaleController.getString("TranslationFailedAlert2", R.string.TranslationFailedAlert2)).show(); + headerView.toLanguageTextView.setText(languageName(toLanguage = prevToLanguage)); + adapter.updateMainView(textViewContainer); + } + }); + }); } - private ArrayList cutInBlocks(CharSequence full, int maxBlockSize) { - ArrayList blocks = new ArrayList<>(); - if (full == null) { - return blocks; - } - while (full.length() > maxBlockSize) { - String maxBlockStr = full.subSequence(0, maxBlockSize).toString(); - int n = maxBlockStr.lastIndexOf("\n\n"); - if (n == -1) n = maxBlockStr.lastIndexOf("\n"); - if (n == -1) n = maxBlockStr.lastIndexOf(". "); - if (n == -1) n = maxBlockStr.length(); - blocks.add(full.subSequence(0, n + 1)); - full = full.subSequence(n + 1, full.length()); - } - if (full.length() > 0) { - blocks.add(full); + public static TLRPC.TL_textWithEntities preprocess(TLRPC.TL_textWithEntities source, TLRPC.TL_textWithEntities received) { + if (received == null || received.text == null) { + return null; } - return blocks; - } - - private boolean loading = false; - private boolean loaded = false; - private boolean fetchNext() { - if (loading) { - return false; + for (int i = 0; i < received.entities.size(); ++i) { + TLRPC.MessageEntity entity = received.entities.get(i); + if (entity instanceof TLRPC.TL_messageEntityTextUrl) { + if (entity.url == null) { + continue; + } + String text = received.text.substring(entity.offset, entity.offset + entity.length); + if (TextUtils.equals(text, entity.url)) { + TLRPC.TL_messageEntityUrl newEntity = new TLRPC.TL_messageEntityUrl(); + newEntity.offset = entity.offset; + newEntity.length = entity.length; + received.entities.set(i, newEntity); + } else if ( + entity.url.startsWith("https://t.me/") && + text.startsWith("@") && + TextUtils.equals(text.substring(1), entity.url.substring(13)) + ) { + TLRPC.TL_messageEntityMention newEntity = new TLRPC.TL_messageEntityMention(); + newEntity.offset = entity.offset; + newEntity.length = entity.length; + received.entities.set(i, newEntity); + } + } } - loading = true; + if (source != null && source.text != null && !source.entities.isEmpty()) { - if (blockIndex >= textBlocks.size()) { - return false; - } + HashMap> srcIndexes = groupEmojiRanges(source.text); + HashMap> destIndexes = groupEmojiRanges(received.text); - fetchTranslation( - textBlocks.get(blockIndex), - Math.min((blockIndex + 1) * 1000, 3500), - (String translatedText, String sourceLanguage) -> { - loaded = true; - Spannable spannable = new SpannableStringBuilder(translatedText); - try { - MessageObject.addUrlsByPattern(false, spannable, false, 0, 0, true); - URLSpan[] urlSpans = spannable.getSpans(0, spannable.length(), URLSpan.class); - for (int i = 0; i < urlSpans.length; ++i) { - URLSpan urlSpan = urlSpans[i]; - int start = spannable.getSpanStart(urlSpan), - end = spannable.getSpanEnd(urlSpan); - if (start == -1 || end == -1) { - continue; + for (int i = 0; i < source.entities.size(); ++i) { + TLRPC.MessageEntity entity = source.entities.get(i); + if (entity instanceof TLRPC.TL_messageEntityCustomEmoji) { + String code = source.text.substring(entity.offset, entity.offset + entity.length); + if (TextUtils.isEmpty(code)) { + continue; + } + ArrayList srcRanges = srcIndexes.get(code); + ArrayList destRanges = destIndexes.get(code); + if (srcRanges == null || destRanges == null) { + continue; + } + int srcIndex = -1; + for (int j = 0; j < srcRanges.size(); ++j) { + Emoji.EmojiSpanRange range = srcRanges.get(j); + if (range.start == entity.offset && range.end == entity.offset + entity.length) { + srcIndex = j; + break; } - spannable.removeSpan(urlSpan); - spannable.setSpan( - new ClickableSpan() { - @Override - public void onClick(@NonNull View view) { - if (onLinkPress != null) { - onLinkPress.run(urlSpan); - dismiss(); - } else { - AlertsCreator.showOpenUrlAlert(fragment, urlSpan.getURL(), false, false); - } - } - - @Override - public void updateDrawState(@NonNull TextPaint ds) { - int alpha = Math.min(ds.getAlpha(), ds.getColor() >> 24 & 0xff); - if (!(urlSpan instanceof URLSpanNoUnderline)) { - ds.setUnderlineText(true); - } - ds.setColor(Theme.getColor(Theme.key_dialogTextLink)); - ds.setAlpha(alpha); - } - }, - start, end, - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE - ); + } + if (srcIndex < 0 || srcIndex >= destRanges.size()) { + continue; + } + Emoji.EmojiSpanRange destRange = destRanges.get(srcIndex); + if (destRange == null) { + continue; } - AndroidUtilities.addLinks(spannable, Linkify.WEB_URLS); - urlSpans = spannable.getSpans(0, spannable.length(), URLSpan.class); - for (int i = 0; i < urlSpans.length; ++i) { - URLSpan urlSpan = urlSpans[i]; - int start = spannable.getSpanStart(urlSpan), - end = spannable.getSpanEnd(urlSpan); - if (start == -1 || end == -1) { - continue; + boolean alreadyContainsOne = false; + for (int j = 0; j < received.entities.size(); ++j) { + TLRPC.MessageEntity destEntity = received.entities.get(j); + if ( + destEntity instanceof TLRPC.TL_messageEntityCustomEmoji && + AndroidUtilities.intersect1d(destRange.start, destRange.end, destEntity.offset, destEntity.offset + destEntity.length) + ) { + alreadyContainsOne = true; + break; } - spannable.removeSpan(urlSpan); - spannable.setSpan( - new ClickableSpan() { - @Override - public void onClick(@NonNull View view) { - AlertsCreator.showOpenUrlAlert(fragment, urlSpan.getURL(), false, false); - } - - @Override - public void updateDrawState(@NonNull TextPaint ds) { - int alpha = Math.min(ds.getAlpha(), ds.getColor() >> 24 & 0xff); - if (!(urlSpan instanceof URLSpanNoUnderline)) - ds.setUnderlineText(true); - ds.setColor(Theme.getColor(Theme.key_dialogTextLink)); - ds.setAlpha(alpha); - } - }, - start, end, - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE - ); + } + if (alreadyContainsOne) { + continue; } - spannable = (Spannable) Emoji.replaceEmoji(spannable, allTextsView.getPaint().getFontMetricsInt(), dp(14), false); - } catch (Exception e) { - e.printStackTrace(); - } - - SpannableStringBuilder allTextsBuilder = new SpannableStringBuilder(allTexts == null ? "" : allTexts); - if (blockIndex != 0) { - allTextsBuilder.append("\n"); - } - allTextsBuilder.append(spannable); - allTexts = allTextsBuilder; - textsView.setWholeText(allTexts); - - LoadingTextView2 block = textsView.getBlockAt(blockIndex); - if (block != null) { - block.loaded(spannable, () -> AndroidUtilities.runOnUIThread(this::checkForNextLoading)); - } - - if (sourceLanguage != null) { - fromLanguage = sourceLanguage; - updateSourceLanguage(); - } - - blockIndex++; - loading = false; - }, - (boolean rateLimit) -> { - Toast.makeText( - getContext(), - rateLimit ? - LocaleController.getString("TranslationFailedAlert1", R.string.TranslationFailedAlert1) : - LocaleController.getString("TranslationFailedAlert2", R.string.TranslationFailedAlert2), - Toast.LENGTH_SHORT - ).show(); - - if (blockIndex == 0) { - dismiss(); + TLRPC.TL_messageEntityCustomEmoji newEntity = new TLRPC.TL_messageEntityCustomEmoji(); + newEntity.document_id = ((TLRPC.TL_messageEntityCustomEmoji) entity).document_id; + newEntity.document = ((TLRPC.TL_messageEntityCustomEmoji) entity).document; + newEntity.offset = destRange.start; + newEntity.length = destRange.end - destRange.start; + received.entities.add(newEntity); } } - ); - return true; + } + return received; } - @Override - public void dismissInternal() { - super.dismissInternal(); - if (onDismiss != null) { - onDismiss.run(); + private static HashMap> groupEmojiRanges(CharSequence text) { + HashMap> result = new HashMap<>(); + if (text == null) { + return result; + } + ArrayList ranges = Emoji.parseEmojis(text); + if (ranges == null) { + return result; } + String string = text.toString(); + for (int i = 0; i < ranges.size(); ++i) { + Emoji.EmojiSpanRange range = ranges.get(i); + if (range == null || range.code == null) { + continue; + } + String code = string.substring(range.start, range.end); + ArrayList codeRanges = result.get(code); + if (codeRanges == null) { + result.put(code, codeRanges = new ArrayList<>()); + } + codeRanges.add(range); + } + return result; } -// @Override -// public boolean dispatchTouchEvent(@NonNull MotionEvent event) { -// if (event.getAction() == MotionEvent.ACTION_DOWN && event.getY() < contentView.getPaddingTop() + header.getTranslationY()) { -// dismiss(); -// return true; -// } -// return super.dispatchTouchEvent(event); -// } - - private void checkForNextLoading() { - if (!listView.canScrollVertically(-1)) { - fetchNext(); + public static ArrayList preprocess(ArrayList received) { + if (received == null) { + return null; + } + for (int i = 0; i < received.size(); ++i) { + received.set(i, preprocess(null, received.get(i))); } + return received; } - public interface OnTranslationSuccess { - public void run(String translated, String sourceLanguage); - } - public interface OnTranslationFail { - public void run(boolean rateLimit); - } - private void fetchTranslation(CharSequence text, long minDuration, OnTranslationSuccess onSuccess, OnTranslationFail onFail) { - if (!translateQueue.isAlive()) { - translateQueue.start(); - } - translateQueue.postRunnable(() -> { - String uri = ""; - HttpURLConnection connection = null; - long start = SystemClock.elapsedRealtime(); - try { - uri = "https://translate.googleapis.com/translate_a/single?client=gtx&sl="; - uri += Uri.encode(fromLanguage); - uri += "&tl="; - uri += Uri.encode(toLanguage); - uri += "&dt=t&ie=UTF-8&oe=UTF-8&otf=1&ssel=0&tsel=0&kc=7&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&q="; - uri += Uri.encode(text.toString()); - connection = (HttpURLConnection) new URI(uri).toURL().openConnection(); - connection.setRequestMethod("GET"); - connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36"); - connection.setRequestProperty("Content-Type", "application/json"); - - StringBuilder textBuilder = new StringBuilder(); - try (Reader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), Charset.forName("UTF-8")))) { - int c; - while ((c = reader.read()) != -1) { - textBuilder.append((char) c); - } - } - String jsonString = textBuilder.toString(); - - JSONTokener tokener = new JSONTokener(jsonString); - JSONArray array = new JSONArray(tokener); - JSONArray array1 = array.getJSONArray(0); - String sourceLanguage = null; - try { - sourceLanguage = array.getString(2); - } catch (Exception e2) {} - if (sourceLanguage != null && sourceLanguage.contains("-")) { - sourceLanguage = sourceLanguage.substring(0, sourceLanguage.indexOf("-")); - } - StringBuilder result = new StringBuilder(); - for (int i = 0; i < array1.length(); ++i) { - String blockText = array1.getJSONArray(i).getString(0); - if (blockText != null && !blockText.equals("null")) { - result.append(blockText); - } - } - if (text.length() > 0 && text.charAt(0) == '\n') { - result.insert(0, "\n"); + private CharSequence preprocessText(CharSequence text) { + Spannable spannable = new SpannableStringBuilder(text); + URLSpan[] urlSpans; + if (onLinkPress != null || fragment != null) { + urlSpans = spannable.getSpans(0, spannable.length(), URLSpan.class); + for (int i = 0; i < urlSpans.length; ++i) { + URLSpan urlSpan = urlSpans[i]; + int start = spannable.getSpanStart(urlSpan), + end = spannable.getSpanEnd(urlSpan); + if (start == -1 || end == -1) { + continue; } - final String finalResult = result.toString(); - final String finalSourceLanguage = sourceLanguage; + spannable.removeSpan(urlSpan); + spannable.setSpan( + new ClickableSpan() { + @Override + public void onClick(@NonNull View view) { + if (onLinkPress != null) { + if (onLinkPress.run(urlSpan)) { + dismiss(); + } + } else if (fragment != null) { + AlertsCreator.showOpenUrlAlert(fragment, urlSpan.getURL(), false, false); + } + } - long elapsed = SystemClock.elapsedRealtime() - start; - AndroidUtilities.runOnUIThread(() -> { - if (onSuccess != null) { - onSuccess.run(finalResult, finalSourceLanguage); - } - }, Math.max(0, minDuration - elapsed)); - } catch (Exception e) { - try { - Log.e("translate", "failed to translate a text " + (connection != null ? connection.getResponseCode() : null) + " " + (connection != null ? connection.getResponseMessage() : null)); - } catch (IOException ioException) { - ioException.printStackTrace(); - } - e.printStackTrace(); - - if (onFail != null) { - try { - final boolean rateLimit = connection != null && connection.getResponseCode() == 429; - AndroidUtilities.runOnUIThread(() -> { - onFail.run(rateLimit); - }); - } catch (Exception e2) { - AndroidUtilities.runOnUIThread(() -> { - onFail.run(false); - }); - } - } + @Override + public void updateDrawState(@NonNull TextPaint ds) { + int alpha = Math.min(ds.getAlpha(), ds.getColor() >> 24 & 0xff); + if (!(urlSpan instanceof URLSpanNoUnderline)) { + ds.setUnderlineText(true); + } + ds.setColor(Theme.getColor(Theme.key_dialogTextLink)); + ds.setAlpha(alpha); + } + }, + start, end, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + ); } - }); + } + return Emoji.replaceEmoji(spannable, textView.getPaint().getFontMetricsInt(), true); } - private static void translateText(int currentAccount, TLRPC.InputPeer peer, int msg_id, String from_lang, String to_lang) { - TLRPC.TL_messages_translateText req = new TLRPC.TL_messages_translateText(); - req.peer = peer; - req.msg_id = msg_id; - req.flags |= 1; - - if (from_lang != null) { - req.from_lang = from_lang; - req.flags |= 4; + @Override + public void dismissInternal() { + if (reqId != null) { + ConnectionsManager.getInstance(currentAccount).cancelRequest(reqId, true); + reqId = null; } + super.dismissInternal(); + } - req.to_lang = to_lang; + public void setFragment(BaseFragment fragment) { + this.fragment = fragment; + } - try { - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (error, res) -> {}); - } catch (Exception e) { - FileLog.e(e); - } + public void setOnLinkPress(Utilities.CallbackReturn onLinkPress) { + this.onLinkPress = onLinkPress; } - public static TranslateAlert2 showAlert(Context context, BaseFragment fragment, int currentAccount, TLRPC.InputPeer peer, int msgId, String fromLanguage, String toLanguage, CharSequence text, boolean noforwards, OnLinkPress onLinkPress, Runnable onDismiss) { - if (peer != null) { - translateText(currentAccount, peer, msgId, fromLanguage != null && fromLanguage.equals("und") ? null : fromLanguage, toLanguage); + public void setNoforwards(boolean noforwards) { + if (textView != null) { + textView.setTextIsSelectable(!noforwards); } - TranslateAlert2 alert = new TranslateAlert2(fragment, context, fromLanguage, toLanguage, text, noforwards, onLinkPress, onDismiss); - if (fragment != null) { - if (fragment.getParentActivity() != null) { - fragment.showDialog(alert); - } + if (noforwards) { + getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); } else { - alert.show(); + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE); } - return alert; } - public static TranslateAlert2 showAlert(Context context, BaseFragment fragment, String fromLanguage, String toLanguage, CharSequence text, boolean noforwards, OnLinkPress onLinkPress, Runnable onDismiss) { - TranslateAlert2 alert = new TranslateAlert2(fragment, context, fromLanguage, toLanguage, text, noforwards, onLinkPress, onDismiss); - if (fragment != null) { - if (fragment.getParentActivity() != null) { - fragment.showDialog(alert); - } - } else { - alert.show(); - } - return alert; + + @Override + protected boolean canDismissWithSwipe() { + return false; } - private static final int MOST_SPEC = View.MeasureSpec.makeMeasureSpec(999999, View.MeasureSpec.AT_MOST); - public static class TextBlocksLayout extends ViewGroup { + private class LoadingTextView extends TextView { - private TextView wholeTextView; - private final int fontSize; - private final int textColor; + private final LinkPath path = new LinkPath(true); + private final LoadingDrawable loadingDrawable = new LoadingDrawable(); - public TextBlocksLayout(Context context, int fontSize, int textColor, TextView wholeTextView) { + public LoadingTextView(Context context) { super(context); + loadingDrawable.usePath(path); + loadingDrawable.setSpeed(.65f); + loadingDrawable.setRadiiDp(4); + setBackground(loadingDrawable); + } + + @Override + public void setTextColor(int color) { + super.setTextColor(Theme.multAlpha(color, .2f)); + loadingDrawable.setColors( + Theme.multAlpha(color, 0.03f), + Theme.multAlpha(color, 0.175f), + Theme.multAlpha(color, 0.2f), + Theme.multAlpha(color, 0.45f) + ); + } - this.fontSize = fontSize; - this.textColor = textColor; + private void updateDrawable() { + if (path == null || loadingDrawable == null) { + return; + } - if (wholeTextView != null) { - wholeTextView.setPadding(LoadingTextView2.paddingHorizontal, LoadingTextView2.paddingVertical, LoadingTextView2.paddingHorizontal, LoadingTextView2.paddingVertical); - addView(this.wholeTextView = wholeTextView); + path.rewind(); + if (getLayout() != null && getLayout().getText() != null) { + path.setCurrentLayout(getLayout(), 0, getPaddingLeft(), getPaddingTop()); + getLayout().getSelectionPath(0, getLayout().getText().length(), path); } + loadingDrawable.updateBounds(); } - public void setWholeText(CharSequence wholeText) { - // having focus on that text view can cause jumping scroll to the top after loading a new block - // TODO(dkaraush): preserve selection after setting a new text - wholeTextView.clearFocus(); - wholeTextView.setText(wholeText); + @Override + public void setText(CharSequence text, BufferType type) { + super.setText(text, type); + updateDrawable(); } - public LoadingTextView2 addBlock(CharSequence fromText) { - LoadingTextView2 textView = new LoadingTextView2(getContext(), fromText, getBlocksCount() > 0, fontSize, textColor); - addView(textView); - if (wholeTextView != null) { - wholeTextView.bringToFront(); - } - return textView; + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + updateDrawable(); } - public int getBlocksCount() { - return getChildCount() - (wholeTextView != null ? 1 : 0); + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + loadingDrawable.reset(); } - public LoadingTextView2 getBlockAt(int i) { - View child = getChildAt(i); - if (child instanceof LoadingTextView2) { - return (LoadingTextView2) child; - } - return null; + } + + private static class PaddedAdapter extends RecyclerListView.Adapter { + + private Context mContext; + private View mMainView; + + public PaddedAdapter(Context context, View mainView) { + mContext = context; + mMainView = mainView; } - public LoadingTextView2 getFirstUnloadedBlock() { - final int count = getBlocksCount(); - for (int i = 0; i < count; ++i) { - LoadingTextView2 block = getBlockAt(i); - if (block != null && !block.loaded) - return block; + private int mainViewType = 1; + + public void updateMainView(View newMainView) { + if (mMainView == newMainView) { + return; } - return null; + mainViewType++; + mMainView = newMainView; + notifyItemChanged(1); } - private static final int gap = -LoadingTextView2.paddingVertical * 4 + dp(.48f); - public int height() { - int height = 0; - final int count = getBlocksCount(); - for (int i = 0; i < count; ++i) { - height += getBlockAt(i).height(); + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + if (viewType == 0) { + return new RecyclerListView.Holder(new View(mContext) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec((int) (AndroidUtilities.displaySize.y * .4f), MeasureSpec.EXACTLY) + ); + } + }); + } else { + return new RecyclerListView.Holder(mMainView); } - return getPaddingTop() + height + getPaddingBottom(); } - protected void onHeightUpdated(int height, int dy) {} + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {} - public void updateHeight() { - boolean updated; - int newHeight = height(); - int dy = 0; - RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) getLayoutParams(); - if (lp == null) { - lp = new RecyclerView.LayoutParams(LayoutParams.MATCH_PARENT, newHeight); - updated = true; + @Override + public int getItemViewType(int position) { + if (position == 0) { + return 0; } else { - updated = lp.height != newHeight; - dy = newHeight - lp.height; - lp.height = newHeight; - } - - if (updated) { - this.setLayoutParams(lp); - onHeightUpdated(newHeight, dy); + return mainViewType; } } @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - final int count = getBlocksCount(); - final int innerWidthMeasureSpec = MeasureSpec.makeMeasureSpec( - MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight(), - MeasureSpec.getMode(widthMeasureSpec) - ); - for (int i = 0; i < count; ++i) { - LoadingTextView2 block = getBlockAt(i); - block.measure(innerWidthMeasureSpec, MOST_SPEC); - } - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height(), MeasureSpec.EXACTLY)); + public int getItemCount() { + return 2; } + } - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - int y = 0; - final int count = getBlocksCount(); - for (int i = 0; i < count; ++i) { - LoadingTextView2 block = getBlockAt(i); - final int blockHeight = block.height(); - final int translationY = i > 0 ? gap : 0; - block.layout(getPaddingLeft(), getPaddingTop() + y + translationY, r - l - getPaddingRight(), getPaddingTop() + y + blockHeight + translationY); - y += blockHeight; - if (i > 0 && i < count - 1) { - y += gap; - } + private AnimatedFloat sheetTopAnimated; + private float getSheetTop() { + return getSheetTop(true); + } + private float getSheetTop(boolean animated) { + float top = listView.getTop(); + if (listView.getChildCount() >= 1) { + top += Math.max(0, listView.getChildAt(listView.getChildCount() - 1).getTop()); + } + top = Math.max(0, top - dp(78)); + if (animated && sheetTopAnimated != null) { + if (!listView.scrollingByUser && !sheetTopNotAnimate) { + top = sheetTopAnimated.set(top); + } else { + sheetTopAnimated.set(top, true); } - - wholeTextView.measure( - MeasureSpec.makeMeasureSpec(r - l - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(b - t - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY) - ); - wholeTextView.layout( - getPaddingLeft(), - getPaddingTop(), - (r - l) - getPaddingRight(), - getPaddingTop() + wholeTextView.getMeasuredHeight() - ); } + return top; } - public static class InlineLoadingTextView extends ViewGroup { - - public static final int paddingHorizontal = dp(4), - paddingVertical = 0; - + private class HeaderView extends FrameLayout { - public boolean showLoadingText = true; + private ImageView backButton; + private TextView titleTextView; + private LinearLayout subtitleView; + private TextView fromLanguageTextView; + private ImageView arrowView; + private AnimatedTextView toLanguageTextView; - private final TextView fromTextView; - private final TextView toTextView; + private View backgroundView; - private final ValueAnimator loadingAnimator; + private View shadow; - private final long start = SystemClock.elapsedRealtime(); - public InlineLoadingTextView(Context context, CharSequence fromText, int fontSize, int textColor) { + public HeaderView(Context context) { super(context); - setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical); - setClipChildren(false); - setWillNotDraw(false); + backgroundView = new View(context); + backgroundView.setBackgroundColor(getThemedColor(Theme.key_dialogBackground)); + addView(backgroundView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 44, Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 12, 0, 0)); + + backButton = new ImageView(context); + backButton.setScaleType(ImageView.ScaleType.CENTER); + backButton.setImageResource(R.drawable.ic_ab_back); + backButton.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_dialogTextBlack), PorterDuff.Mode.MULTIPLY)); + backButton.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector))); + backButton.setAlpha(0f); + backButton.setOnClickListener(e -> dismiss()); + addView(backButton, LayoutHelper.createFrame(54, 54, Gravity.TOP, 1, 1, 1, 1)); - fromTextView = new TextView(context) { + titleTextView = new TextView(context) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MOST_SPEC, MOST_SPEC); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (LocaleController.isRTL) { + titleTextView.setPivotX(getMeasuredWidth()); + } } }; - fromTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize); - fromTextView.setTextColor(textColor); - fromTextView.setText(fromText); - fromTextView.setLines(1); - fromTextView.setMaxLines(1); - fromTextView.setSingleLine(true); - fromTextView.setEllipsize(null); - addView(fromTextView); - - toTextView = new TextView(context) { + titleTextView.setTextColor(getThemedColor(Theme.key_dialogTextBlack)); + titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + titleTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + titleTextView.setText(LocaleController.getString("AutomaticTranslation", R.string.AutomaticTranslation)); + titleTextView.setPivotX(0); + titleTextView.setPivotY(0); + addView(titleTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.FILL_HORIZONTAL, 22, 20, 22, 0)); + + subtitleView = new LinearLayout(context) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MOST_SPEC, MOST_SPEC); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (LocaleController.isRTL) { + subtitleView.setPivotX(getMeasuredWidth()); + } } }; - toTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize); - toTextView.setTextColor(textColor); - toTextView.setLines(1); - toTextView.setMaxLines(1); - toTextView.setSingleLine(true); - toTextView.setEllipsize(null); - addView(toTextView); - - int c1 = Theme.getColor(Theme.key_dialogBackground), - c2 = Theme.getColor(Theme.key_dialogBackgroundGray); - LinearGradient gradient = new LinearGradient(0, 0, gradientWidth, 0, new int[]{ c1, c2, c1 }, new float[] { 0, 0.67f, 1f }, Shader.TileMode.REPEAT); - loadingPaint.setShader(gradient); - - loadingAnimator = ValueAnimator.ofFloat(0f, 1f); - loadingAnimator.addUpdateListener(a -> invalidate()); - loadingAnimator.setDuration(Long.MAX_VALUE); - loadingAnimator.start(); - } + if (LocaleController.isRTL) { + subtitleView.setGravity(Gravity.RIGHT); + } + subtitleView.setPivotX(0); + subtitleView.setPivotY(0); + if (!TextUtils.isEmpty(fromLanguage) && !"und".equals(fromLanguage)) { + fromLanguageTextView = new TextView(context); + fromLanguageTextView.setLines(1); + fromLanguageTextView.setTextColor(getThemedColor(Theme.key_player_actionBarSubtitle)); + fromLanguageTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + fromLanguageTextView.setText(capitalFirst(languageName(fromLanguage))); + fromLanguageTextView.setPadding(0, dp(2), 0, dp(2)); + } - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - fromTextView.measure(0, 0); - toTextView.measure(0, 0); - super.onMeasure( - MeasureSpec.makeMeasureSpec( - (int) AndroidUtilities.lerp(fromTextView.getMeasuredWidth(), toTextView.getMeasuredWidth(), loadingT) + getPaddingLeft() + getPaddingRight(), - MeasureSpec.EXACTLY - ), - MeasureSpec.makeMeasureSpec( - Math.max(fromTextView.getMeasuredHeight(), toTextView.getMeasuredHeight()), - MeasureSpec.EXACTLY - ) - ); - } + arrowView = new ImageView(context); + arrowView.setImageResource(R.drawable.search_arrow); + arrowView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_player_actionBarSubtitle), PorterDuff.Mode.MULTIPLY)); + if (LocaleController.isRTL) { + arrowView.setScaleX(-1f); + } - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - fromTextView.layout(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + fromTextView.getMeasuredWidth(), getPaddingTop() + fromTextView.getMeasuredHeight()); - toTextView.layout(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + toTextView.getMeasuredWidth(), getPaddingTop() + toTextView.getMeasuredHeight()); - updateWidth(); - } + toLanguageTextView = new AnimatedTextView(context) { + private Paint bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(); - private void updateWidth() { - boolean updated; + @Override + protected void onDraw(Canvas canvas) { + if (LocaleController.isRTL) { + AndroidUtilities.rectTmp.set(getWidth() - width(), (getHeight() - dp(18)) / 2f, getWidth(), (getHeight() + dp(18)) / 2f); + } else { + AndroidUtilities.rectTmp.set(0, (getHeight() - dp(18)) / 2f, width(), (getHeight() + dp(18)) / 2f); + } + bgPaint.setColor(Theme.multAlpha(getThemedColor(Theme.key_player_actionBarSubtitle), .1175f)); + canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(4), dp(4), bgPaint); + if (links.draw(canvas)) { + invalidate(); + } - int newWidth = (int) AndroidUtilities.lerp(fromTextView.getMeasuredWidth(), toTextView.getMeasuredWidth(), loadingT) + getPaddingLeft() + getPaddingRight(); - int newHeight = Math.max(fromTextView.getMeasuredHeight(), toTextView.getMeasuredHeight()); - LayoutParams lp = getLayoutParams(); - if (lp == null) { - lp = new LinearLayout.LayoutParams(newWidth, newHeight); - updated = true; + super.onDraw(canvas); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + LinkSpanDrawable link = new LinkSpanDrawable(null, resourcesProvider, event.getX(), event.getY()); + link.setColor(Theme.multAlpha(getThemedColor(Theme.key_player_actionBarSubtitle), .1175f)); + LinkPath path = link.obtainNewPath(); + if (LocaleController.isRTL) { + AndroidUtilities.rectTmp.set(getWidth() - width(), (getHeight() - dp(18)) / 2f, getWidth(), (getHeight() + dp(18)) / 2f); + } else { + AndroidUtilities.rectTmp.set(0, (getHeight() - dp(18)) / 2f, width(), (getHeight() + dp(18)) / 2f); + } + path.addRect(AndroidUtilities.rectTmp, Path.Direction.CW); + links.addLink(link); + invalidate(); + return true; + } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + if (event.getAction() == MotionEvent.ACTION_UP) { + performClick(); + } + links.clear(); + invalidate(); + } + return super.onTouchEvent(event); + } + }; + if (LocaleController.isRTL) { + toLanguageTextView.setGravity(Gravity.RIGHT); + } + toLanguageTextView.setAnimationProperties(.25f, 0, 350, CubicBezierInterpolator.EASE_OUT_QUINT); + toLanguageTextView.setTextColor(getThemedColor(Theme.key_player_actionBarSubtitle)); + toLanguageTextView.setTextSize(dp(14)); + toLanguageTextView.setText(capitalFirst(languageName(toLanguage))); + toLanguageTextView.setPadding(dp(4), dp(2), dp(4), dp(2)); + toLanguageTextView.setOnClickListener(e -> openLanguagesSelect()); + + if (LocaleController.isRTL) { + subtitleView.addView(toLanguageTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 0, fromLanguageTextView != null ? 3 : 0, 0)); + if (fromLanguageTextView != null) { + subtitleView.addView(arrowView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 1, 0, 0)); + subtitleView.addView(fromLanguageTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 4, 0, 0, 0)); + } } else { - updated = lp.width != newWidth || lp.height != newHeight; - lp.width = newWidth; - lp.height = newHeight; + if (fromLanguageTextView != null) { + subtitleView.addView(fromLanguageTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 0, 4, 0)); + subtitleView.addView(arrowView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 1, 0, 0)); + } + subtitleView.addView(toLanguageTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, fromLanguageTextView != null ? 3 : 0, 0, 0, 0)); } - if (updated) - setLayoutParams(lp); + addView(subtitleView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.FILL_HORIZONTAL, 22, 43, 22, 0)); + + shadow = new View(context); + shadow.setBackgroundColor(getThemedColor(Theme.key_dialogShadowLine)); + shadow.setAlpha(0); + addView(shadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, AndroidUtilities.getShadowHeight() / dpf2(1), Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 56, 0, 0)); } - protected void onLoadAnimation(float t) {} + public void openLanguagesSelect() { + ActionBarPopupWindow.ActionBarPopupWindowLayout layout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getContext()) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, + MeasureSpec.makeMeasureSpec(Math.min((int) (AndroidUtilities.displaySize.y * .33f), MeasureSpec.getSize(heightMeasureSpec)), MeasureSpec.EXACTLY) + ); + } + }; - public boolean loaded = false; - public float loadingT = 0f; - private ValueAnimator loadedAnimator = null; - public void loaded(CharSequence loadedText) { - loaded(loadedText, 350,null); - } - public void loaded(CharSequence loadedText, Runnable onLoadEnd) { - loaded(loadedText, 350, onLoadEnd); - } - public void loaded(CharSequence loadedText, long duration, Runnable onLoadEnd) { - loaded = true; - toTextView.setText(loadedText); + Drawable shadowDrawable2 = ContextCompat.getDrawable(getContext(), R.drawable.popup_fixed_alert).mutate(); + shadowDrawable2.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_actionBarDefaultSubmenuBackground), PorterDuff.Mode.MULTIPLY)); + layout.setBackground(shadowDrawable2); - if (loadingAnimator.isRunning()) { - loadingAnimator.cancel(); - } - if (loadedAnimator == null) { - loadedAnimator = ValueAnimator.ofFloat(0f, 1f); - loadedAnimator.addUpdateListener(a -> { - loadingT = (float) a.getAnimatedValue(); - updateWidth(); - invalidate(); - onLoadAnimation(loadingT); - }); - loadedAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (onLoadEnd != null) - onLoadEnd.run(); + final Runnable[] dismiss = new Runnable[1]; + + ArrayList locales = TranslateController.getLocales(); + boolean first = true; + for (int i = 0; i < locales.size(); ++i) { + LocaleController.LocaleInfo localeInfo = locales.get(i); + + if ( + localeInfo.pluralLangCode.equals(fromLanguage) || + !"remote".equals(localeInfo.pathToFile) + ) { + continue; + } + + ActionBarMenuSubItem button = new ActionBarMenuSubItem(getContext(), 2, first, i == locales.size() - 1, resourcesProvider); + button.setText(capitalFirst(languageName(localeInfo.pluralLangCode))); + button.setChecked(TextUtils.equals(toLanguage, localeInfo.pluralLangCode)); + button.setOnClickListener(e -> { + if (dismiss[0] != null) { + dismiss[0].run(); + } + + if (TextUtils.equals(toLanguage, localeInfo.pluralLangCode)) { + return; + } + + if (adapter.mMainView == textViewContainer) { + prevToLanguage = toLanguage; } + toLanguageTextView.setText(capitalFirst(languageName(toLanguage = localeInfo.pluralLangCode))); + adapter.updateMainView(loadingTextView); + setToLanguage(toLanguage); + translate(); }); - loadedAnimator.setDuration(duration); - loadedAnimator.setInterpolator(CubicBezierInterpolator.EASE_BOTH); - loadedAnimator.start(); - } - } - public void set(CharSequence loadedText) { - loaded = true; - toTextView.setText(loadedText); + layout.addView(button); - if (loadingAnimator.isRunning()) { - loadingAnimator.cancel(); - } - if (loadedAnimator != null) { - loadedAnimator.cancel(); - loadedAnimator = null; + first = false; } - loadingT = 1f; - requestLayout(); - updateWidth(); - invalidate(); - onLoadAnimation(1f); + + ActionBarPopupWindow window = new ActionBarPopupWindow(layout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT); + dismiss[0] = () -> window.dismiss(); + window.setPauseNotifications(true); + window.setDismissAnimationDuration(220); + window.setOutsideTouchable(true); + window.setClippingEnabled(true); + window.setAnimationStyle(R.style.PopupContextAnimation); + window.setFocusable(true); + int[] location = new int[2]; + toLanguageTextView.getLocationInWindow(location); + layout.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.y, MeasureSpec.AT_MOST)); + int height = layout.getMeasuredHeight(); + int y = location[1] > AndroidUtilities.displaySize.y * .9f - height ? location[1] - height + dp(8) : location[1] + toLanguageTextView.getMeasuredHeight() - dp(8); + window.showAtLocation(containerView, Gravity.TOP | Gravity.LEFT, location[0] - dp(8), y); } - private final RectF rect = new RectF(); - private final Path inPath = new Path(), - tempPath = new Path(), - loadingPath = new Path(), - shadePath = new Path(); - private final Paint loadingPaint = new Paint(); - private final float gradientWidth = dp(350f); @Override - protected void onDraw(Canvas canvas) { - float w = getWidth(), h = getHeight(); - - float cx = LocaleController.isRTL ? Math.max(w / 2f, w - 8f) : Math.min(w / 2f, 8f), - cy = Math.min(h / 2f, 8f), - R = (float) Math.sqrt(Math.max( - Math.max(cx*cx + cy*cy, (w-cx)*(w-cx) + cy*cy), - Math.max(cx*cx + (h-cy)*(h-cy), (w-cx)*(w-cx) + (h-cy)*(h-cy)) - )), - r = loadingT * R; - inPath.reset(); - inPath.addCircle(cx, cy, r, Path.Direction.CW); - - canvas.save(); - canvas.clipPath(inPath, Region.Op.DIFFERENCE); - - loadingPaint.setAlpha((int) ((1f - loadingT) * 255)); - float dx = gradientWidth - (((SystemClock.elapsedRealtime() - start) / 1000f * gradientWidth) % gradientWidth); - shadePath.reset(); - shadePath.addRect(0, 0, w, h, Path.Direction.CW); - - loadingPath.reset(); - rect.set(0, 0, w, h); - loadingPath.addRoundRect(rect, dp(4), dp(4), Path.Direction.CW); - canvas.clipPath(loadingPath); - canvas.translate(-dx, 0); - shadePath.offset(dx, 0f, tempPath); - canvas.drawPath(tempPath, loadingPaint); - canvas.translate(dx, 0); - canvas.restore(); - - if (showLoadingText && fromTextView != null) { - canvas.save(); - rect.set(0, 0, w, h); - canvas.clipPath(inPath, Region.Op.DIFFERENCE); - canvas.translate(paddingHorizontal, paddingVertical); - canvas.saveLayerAlpha(rect, (int) (255 * .08f), Canvas.ALL_SAVE_FLAG); - fromTextView.draw(canvas); - canvas.restore(); - canvas.restore(); - } + public void setTranslationY(float translationY) { + super.setTranslationY(translationY); - if (toTextView != null) { - canvas.save(); - canvas.clipPath(inPath); - canvas.translate(paddingHorizontal, paddingVertical); - canvas.saveLayerAlpha(rect, (int) (255 * loadingT), Canvas.ALL_SAVE_FLAG); - toTextView.draw(canvas); - if (loadingT < 1f) { - canvas.restore(); - } - canvas.restore(); + float t = MathUtils.clamp((translationY - AndroidUtilities.statusBarHeight) / dp(64), 0, 1); + if (!hasEnoughHeight()) { + t = 1; + } + t = CubicBezierInterpolator.EASE_OUT.getInterpolation(t); + + titleTextView.setScaleX(AndroidUtilities.lerp(.85f, 1f, t)); + titleTextView.setScaleY(AndroidUtilities.lerp(.85f, 1f, t)); + titleTextView.setTranslationY(AndroidUtilities.lerp(dpf2(-12), 0, t)); + if (!LocaleController.isRTL) { + titleTextView.setTranslationX(AndroidUtilities.lerp(dpf2(50), 0, t)); + subtitleView.setTranslationX(AndroidUtilities.lerp(dpf2(50), 0, t)); } + + subtitleView.setTranslationY(AndroidUtilities.lerp(dpf2(-22), 0, t)); + + backButton.setTranslationX(AndroidUtilities.lerp(0, dpf2(-25), t)); + backButton.setAlpha(1f - t); + + shadow.setTranslationY(AndroidUtilities.lerp(0, dpf2(22), t)); + shadow.setAlpha(1f - t); } @Override - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - return false; + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(dp(78), MeasureSpec.EXACTLY) + ); } } - public static class LoadingTextView2 extends ViewGroup { - - public static final int paddingHorizontal = dp(4), - paddingVertical = dp(1.5f); - - public boolean showLoadingText = true; + private class ContainerView extends FrameLayout { + public ContainerView(Context context) { + super(context); - private final TextView fromTextView; - private final TextView toTextView; + bgPaint.setColor(getThemedColor(Theme.key_dialogBackground)); + Theme.applyDefaultShadow(bgPaint); + } - private final boolean scaleFromZero; - private final ValueAnimator loadingAnimator; + private Path bgPath = new Path(); + private Paint bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - private final long start = SystemClock.elapsedRealtime(); - private float scaleT = 1f; - public LoadingTextView2(Context context, CharSequence fromText, boolean scaleFromZero, int fontSize, int textColor) { - super(context); + @Override + protected void dispatchDraw(Canvas canvas) { + + float top = getSheetTop(); + final float R = AndroidUtilities.lerp(0, dp(12), MathUtils.clamp(top / dpf2(24), 0, 1)); + headerView.setTranslationY(Math.max(AndroidUtilities.statusBarHeight, top)); + updateLightStatusBar(top <= AndroidUtilities.statusBarHeight / 2f); + + bgPath.rewind(); + AndroidUtilities.rectTmp.set(0, top, getWidth(), getHeight() + R); + bgPath.addRoundRect(AndroidUtilities.rectTmp, R, R, Path.Direction.CW); + canvas.drawPath(bgPath, bgPaint); + + super.dispatchDraw(canvas); + } + + private Boolean lightStatusBarFull; + private void updateLightStatusBar(boolean full) { + if (lightStatusBarFull == null || lightStatusBarFull != full) { + lightStatusBarFull = full; + AndroidUtilities.setLightStatusBar(getWindow(), AndroidUtilities.computePerceivedBrightness( + full ? + getThemedColor(Theme.key_dialogBackground) : + Theme.blendOver( + getThemedColor(Theme.key_actionBarDefault), + 0x33000000 + ) + ) > .721f); + } + } - setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical); - setClipChildren(false); - setWillNotDraw(false); + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY)); + } - fromTextView = new TextView(context) { - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MOST_SPEC); - } - }; - fromTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize); - fromTextView.setTextColor(textColor); - fromTextView.setText(fromText); - fromTextView.setLines(0); - fromTextView.setMaxLines(0); - fromTextView.setSingleLine(false); - fromTextView.setEllipsize(null); - addView(fromTextView); - - toTextView = new TextView(context) { + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + Bulletin.addDelegate(this, new Bulletin.Delegate() { @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MOST_SPEC); - } - }; - toTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize); - toTextView.setTextColor(textColor); - toTextView.setLines(0); - toTextView.setMaxLines(0); - toTextView.setSingleLine(false); - toTextView.setEllipsize(null); - addView(toTextView); - - int c1 = Theme.getColor(Theme.key_dialogBackground), - c2 = Theme.getColor(Theme.key_dialogBackgroundGray); - LinearGradient gradient = new LinearGradient(0, 0, gradientWidth, 0, new int[]{ c1, c2, c1 }, new float[] { 0, 0.67f, 1f }, Shader.TileMode.REPEAT); - loadingPaint.setShader(gradient); - - this.scaleFromZero = scaleFromZero; - loadingAnimator = ValueAnimator.ofFloat(0f, 1f); - if (scaleFromZero) - scaleT = 0; - loadingAnimator.addUpdateListener(a -> { - invalidate(); - if (scaleFromZero) { - boolean scaleTWasNoFull = scaleT < 1f; - scaleT = Math.min(1, (SystemClock.elapsedRealtime() - start) / 400f); - if (scaleTWasNoFull) { - updateHeight(); - } + public int getBottomOffset(int tag) { + return AndroidUtilities.dp(16 + 48 + 16); } }); - loadingAnimator.setDuration(Long.MAX_VALUE); - loadingAnimator.start(); } - public int innerHeight() { - return (int) (AndroidUtilities.lerp(fromTextView.getMeasuredHeight(), toTextView.getMeasuredHeight(), loadingT) * scaleT); - } - public int height() { - return getPaddingTop() + innerHeight() + getPaddingBottom(); + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + Bulletin.removeDelegate(this); } + } - private void updateHeight() { - ViewParent parent = getParent(); - if (parent instanceof TextBlocksLayout) { - ((TextBlocksLayout) parent).updateHeight(); - } + public static String capitalFirst(String text) { + if (text == null) { + return null; } + return text.substring(0, 1).toUpperCase() + text.substring(1); + } - public boolean loaded = false; - private float loadingT = 0f; - private ValueAnimator loadedAnimator = null; - public void loaded(CharSequence loadedText, Runnable onLoadEnd) { - loaded = true; - toTextView.setText(loadedText); - layout(); - - if (loadingAnimator.isRunning()) { - loadingAnimator.cancel(); - } - if (loadedAnimator == null) { - loadedAnimator = ValueAnimator.ofFloat(0f, 1f); - loadedAnimator.addUpdateListener(a -> { - loadingT = (float) a.getAnimatedValue(); - updateHeight(); - invalidate(); - }); - loadedAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (onLoadEnd != null) - onLoadEnd.run(); - } - }); - loadedAnimator.setDuration(350); - loadedAnimator.setInterpolator(CubicBezierInterpolator.EASE_BOTH); - loadedAnimator.start(); - } + public static String languageName(String locale) { + if (locale == null || locale.equals("und") || locale.equals("auto")) { + return null; } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int width = MeasureSpec.getSize(widthMeasureSpec), - innerWidth = width - getPaddingLeft() - getPaddingRight(); - if (fromTextView.getMeasuredWidth() <= 0 || lastWidth != innerWidth) { - measureChild(fromTextView, innerWidth); - updateLoadingPath(); + LocaleController.LocaleInfo currentLanguageInfo = LocaleController.getInstance().getCurrentLocaleInfo(); + try { + Locale[] allLocales = Locale.getAvailableLocales(); + String simplifiedLocale = locale.split("_")[0]; + if ("nb".equals(simplifiedLocale)) { + simplifiedLocale = "no"; } - if (toTextView.getMeasuredWidth() <= 0 || lastWidth != innerWidth) { - measureChild(toTextView, innerWidth); + Locale found = null; + for (int i = 0; i < allLocales.length; ++i) { + if (TextUtils.equals(simplifiedLocale, allLocales[i].getLanguage())) { + found = allLocales[i]; + break; + } } - lastWidth = innerWidth; - super.onMeasure( - MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(height(), MeasureSpec.EXACTLY) - ); - } - - int lastWidth = 0; - @Override - protected void onLayout(boolean changed, int l, int t, int r, int b) { - layout(r - l - getPaddingLeft() - getPaddingRight(), true); - } - private void layout(int width, boolean force) { - if (lastWidth != width || force) { - layout(lastWidth = width); + if (found != null) { + return found.getDisplayLanguage(Locale.getDefault()); } + } catch (Exception e) {} + if ("no".equals(locale)) { + locale = "nb"; } - private void layout(int width) { - measureChild(fromTextView, width); - layoutChild(fromTextView, width); - updateLoadingPath(); - measureChild(toTextView, width); - layoutChild(toTextView, width); - updateHeight(); + LocaleController.LocaleInfo thisLanguageInfo = LocaleController.getInstance().getBuiltinLanguageByPlural(locale); + if (thisLanguageInfo == null) { + return null; } - private void layout() { - layout(lastWidth); + boolean isCurrentLanguageEnglish = currentLanguageInfo != null && "en".equals(currentLanguageInfo.pluralLangCode); +// try { +// String lang = LocaleController.getString("PassportLanguage_" + thisLanguageInfo.pluralLangCode.toUpperCase()); +// if (lang != null && !lang.startsWith("LOC_ERR")) { +// return lang; +// } +// } catch (Exception ignore) {} + if (isCurrentLanguageEnglish) { + return thisLanguageInfo.nameEnglish; + } else { + return thisLanguageInfo.name; } - private void measureChild(View view, int width) { - view.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MOST_SPEC); + } + + @Override + public void show() { + super.show(); + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiLoaded); + } + + @Override + public void dismiss() { + super.dismiss(); + NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiLoaded); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.emojiLoaded) { + loadingTextView.invalidate(); + textView.invalidate(); } - private void layoutChild(View view, int width) { - view.layout(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + width, getPaddingTop() + view.getMeasuredHeight()); + } + + private Boolean buttonShadowShown; + private void updateButtonShadow(boolean show) { + if (buttonShadowShown == null || buttonShadowShown != show) { + buttonShadowShown = show; + buttonShadowView.animate().cancel(); + buttonShadowView.animate().alpha(show ? 1f : 0f).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).setDuration(320).start(); } + } - private RectF fetchedPathRect = new RectF(); - private void updateLoadingPath() { - if (fromTextView != null && fromTextView.getMeasuredWidth() > 0) { - loadingPath.reset(); - Layout loadingLayout = fromTextView.getLayout(); - if (loadingLayout != null) { - CharSequence text = loadingLayout.getText(); - final int lineCount = loadingLayout.getLineCount(); - for (int i = 0; i < lineCount; ++i) { - float s = loadingLayout.getLineLeft(i), - e = loadingLayout.getLineRight(i), - l = Math.min(s, e), - r = Math.max(s, e); - int start = loadingLayout.getLineStart(i), - end = loadingLayout.getLineEnd(i); - boolean hasNonEmptyChar = false; - for (int j = start; j < end; ++j) { - char c = text.charAt(j); - if (c != '\n' && c != '\t' && c != ' ') { - hasNonEmptyChar = true; - break; - } - } - if (!hasNonEmptyChar) - continue; - fetchedPathRect.set( - l - paddingHorizontal, - loadingLayout.getLineTop(i) - paddingVertical, - r + paddingHorizontal, - loadingLayout.getLineBottom(i) + paddingVertical - ); - loadingPath.addRoundRect(fetchedPathRect, dp(4), dp(4), Path.Direction.CW); - } + public static TranslateAlert2 showAlert(Context context, BaseFragment fragment, int currentAccount, TLRPC.InputPeer peer, int msgId, String fromLanguage, String toLanguage, CharSequence text, ArrayList entities, boolean noforwards, Utilities.CallbackReturn onLinkPress, Runnable onDismiss) { + TranslateAlert2 alert = new TranslateAlert2(context, fromLanguage, toLanguage, text, entities, peer, msgId, null) { + @Override + public void dismiss() { + super.dismiss(); + if (onDismiss != null) { + onDismiss.run(); } } - } - - private final RectF rect = new RectF(); - private final Path inPath = new Path(), - tempPath = new Path(), - loadingPath = new Path(), - shadePath = new Path(); - private final Paint loadingPaint = new Paint(); - private final float gradientWidth = dp(350f); - @Override - protected void onDraw(Canvas canvas) { - float w = getWidth(), h = getHeight(); - - float cx = LocaleController.isRTL ? Math.max(w / 2f, w - 8f) : Math.min(w / 2f, 8f), - cy = Math.min(h / 2f, 8f), - R = (float) Math.sqrt(Math.max( - Math.max(cx*cx + cy*cy, (w-cx)*(w-cx) + cy*cy), - Math.max(cx*cx + (h-cy)*(h-cy), (w-cx)*(w-cx) + (h-cy)*(h-cy)) - )), - r = loadingT * R; - inPath.reset(); - inPath.addCircle(cx, cy, r, Path.Direction.CW); - - canvas.save(); - canvas.clipPath(inPath, Region.Op.DIFFERENCE); - - loadingPaint.setAlpha((int) ((1f - loadingT) * 255)); - float dx = gradientWidth - (((SystemClock.elapsedRealtime() - start) / 1000f * gradientWidth) % gradientWidth); - shadePath.reset(); - shadePath.addRect(0, 0, w, h, Path.Direction.CW); - - canvas.translate(paddingHorizontal, paddingVertical); - canvas.clipPath(loadingPath); - canvas.translate(-paddingHorizontal, -paddingVertical); - canvas.translate(-dx, 0); - shadePath.offset(dx, 0f, tempPath); - canvas.drawPath(tempPath, loadingPaint); - canvas.translate(dx, 0); - canvas.restore(); - - if (showLoadingText && fromTextView != null) { - canvas.save(); - rect.set(0, 0, w, h); - canvas.clipPath(inPath, Region.Op.DIFFERENCE); - canvas.translate(paddingHorizontal, paddingVertical); - canvas.saveLayerAlpha(rect, (int) (255 * .08f), Canvas.ALL_SAVE_FLAG); - fromTextView.draw(canvas); - canvas.restore(); - canvas.restore(); + }; + alert.setNoforwards(noforwards); + alert.setFragment(fragment); + alert.setOnLinkPress(onLinkPress); + if (fragment != null) { + if (fragment.getParentActivity() != null) { + fragment.showDialog(alert); } + } else { + alert.show(); + } + return alert; + } - if (toTextView != null) { - canvas.save(); - canvas.clipPath(inPath); - canvas.translate(paddingHorizontal, paddingVertical); - canvas.saveLayerAlpha(rect, (int) (255 * loadingT), Canvas.ALL_SAVE_FLAG); - toTextView.draw(canvas); - if (loadingT < 1f) { - canvas.restore(); + public static TranslateAlert2 showAlert(Context context, BaseFragment fragment, int currentAccount, String fromLanguage, String toLanguage, CharSequence text, ArrayList entities, boolean noforwards, Utilities.CallbackReturn onLinkPress, Runnable onDismiss) { + TranslateAlert2 alert = new TranslateAlert2(context, fromLanguage, toLanguage, text, entities, null) { + @Override + public void dismiss() { + super.dismiss(); + if (onDismiss != null) { + onDismiss.run(); } - canvas.restore(); } + }; + alert.setNoforwards(noforwards); + alert.setFragment(fragment); + alert.setOnLinkPress(onLinkPress); + if (fragment != null) { + if (fragment.getParentActivity() != null) { + fragment.showDialog(alert); + } + } else { + alert.show(); } + return alert; + } - @Override - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - return false; - } + public static String getToLanguage() { + return MessagesController.getGlobalMainSettings().getString("translate_to_language", LocaleController.getInstance().getCurrentLocale().getLanguage()); + } + + public static void setToLanguage(String toLang) { + MessagesController.getGlobalMainSettings().edit().putString("translate_to_language", toLang).apply(); + } + + public static void resetToLanguage() { + MessagesController.getGlobalMainSettings().edit().remove("translate_to_language").apply(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateButton.java new file mode 100644 index 00000000000..c82ee9583b3 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateButton.java @@ -0,0 +1,262 @@ +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextUtils; +import android.text.style.DynamicDrawableSpan; +import android.text.style.ImageSpan; +import android.view.Gravity; +import android.view.WindowManager; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ScrollView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.TranslateController; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBarMenuSubItem; +import org.telegram.ui.ActionBar.ActionBarPopupWindow; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.RestrictedLanguagesSelectActivity; + +import java.util.ArrayList; + +public class TranslateButton extends FrameLayout { + + private final int currentAccount; + private final long dialogId; + private final BaseFragment fragment; + + private Theme.ResourcesProvider resourcesProvider; + + private AnimatedTextView textView; + public final SpannableString translateIcon; + + private ImageView menuView; + + public TranslateButton(Context context, ChatActivity chatActivity, Theme.ResourcesProvider resourcesProvider) { + this(context, chatActivity.getCurrentAccount(), chatActivity.getDialogId(), chatActivity, resourcesProvider); + } + + public TranslateButton(Context context, int currentAccount, long dialogId, BaseFragment fragment, Theme.ResourcesProvider resourcesProvider) { + super(context); + + this.currentAccount = currentAccount; + this.dialogId = dialogId; + this.fragment = fragment; + this.resourcesProvider = resourcesProvider; + + textView = new AnimatedTextView(context, true, true, false); + textView.setAnimationProperties(.3f, 0, 450, CubicBezierInterpolator.EASE_OUT_QUINT); + textView.setTextColor(Theme.getColor(Theme.key_chat_addContact, resourcesProvider)); + textView.setTextSize(AndroidUtilities.dp(15)); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0); + textView.setGravity(Gravity.CENTER_HORIZONTAL); + textView.setIgnoreRTL(!LocaleController.isRTL); + textView.adaptWidth = false; + textView.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_chat_addContact, resourcesProvider) & 0x19ffffff, 3)); + textView.setOnClickListener(e -> onButtonClick()); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + final Drawable translateDrawable = getContext().getResources().getDrawable(R.drawable.msg_translate).mutate(); + translateDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_addContact, resourcesProvider), PorterDuff.Mode.MULTIPLY)); + translateDrawable.setBounds(0, AndroidUtilities.dp(-8), AndroidUtilities.dp(20), AndroidUtilities.dp(20 - 8)); + translateIcon = new SpannableString("x"); + translateIcon.setSpan(new ImageSpan(translateDrawable, DynamicDrawableSpan.ALIGN_BOTTOM), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + menuView = new ImageView(context); + menuView.setScaleType(ImageView.ScaleType.CENTER); + menuView.setImageResource(R.drawable.msg_mini_customize); + menuView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_addContact, resourcesProvider), PorterDuff.Mode.MULTIPLY)); + menuView.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_chat_addContact, resourcesProvider) & 0x19ffffff, Theme.RIPPLE_MASK_ROUNDRECT_6DP)); + menuView.setOnClickListener(e -> onMenuClick()); + addView(menuView, LayoutHelper.createFrame(32, 32, Gravity.RIGHT | Gravity.CENTER_VERTICAL, 0, 0, 8, 0)); + } + + protected void onButtonClick() { + + } + + protected void onMenuClick() { + TranslateController translateController = MessagesController.getInstance(currentAccount).getTranslateController(); + + final ActionBarPopupWindow.ActionBarPopupWindowLayout popupLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getContext(), R.drawable.popup_fixed_alert2, resourcesProvider, ActionBarPopupWindow.ActionBarPopupWindowLayout.FLAG_USE_SWIPEBACK); + final ActionBarPopupWindow popupWindow = new ActionBarPopupWindow(popupLayout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT); + popupLayout.setBackgroundColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground, resourcesProvider)); + + LinearLayout swipeBack = new LinearLayout(getContext()); + swipeBack.setOrientation(LinearLayout.VERTICAL); + ScrollView swipeBackScrollView = new ScrollView(getContext()); + LinearLayout swipeBackScroll = new LinearLayout(getContext()); + swipeBackScrollView.addView(swipeBackScroll); + swipeBackScroll.setOrientation(LinearLayout.VERTICAL); + popupLayout.swipeBackGravityRight = true; + final int swipeBackIndex = popupLayout.addViewToSwipeBack(swipeBack); + + ActionBarMenuSubItem translateToButton = new ActionBarMenuSubItem(getContext(), true, false, resourcesProvider); + translateToButton.setTextAndIcon(LocaleController.getString("TranslateTo", R.string.TranslateTo), R.drawable.msg_translate); + translateToButton.setSubtext(TranslateAlert2.capitalFirst(TranslateAlert2.languageName(translateController.getDialogTranslateTo(dialogId)))); + translateToButton.setItemHeight(56); + translateToButton.setOnClickListener(e -> popupLayout.getSwipeBack().openForeground(swipeBackIndex)); + popupLayout.addView(translateToButton); + + ActionBarMenuSubItem backButton = new ActionBarMenuSubItem(getContext(), true, false, resourcesProvider); + backButton.setTextAndIcon(LocaleController.getString("Back", R.string.Back), R.drawable.ic_ab_back); + backButton.setOnClickListener(e -> popupLayout.getSwipeBack().closeForeground()); + swipeBack.addView(backButton); + + swipeBack.addView(new ActionBarPopupWindow.GapView(getContext(), resourcesProvider), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); + swipeBack.addView(swipeBackScrollView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 420)); + + String detectedLanguage = translateController.getDialogDetectedLanguage(dialogId); + String detectedLanguageName = TranslateAlert2.languageName(detectedLanguage); + String currentTranslateTo = translateController.getDialogTranslateTo(dialogId); + + ArrayList suggestedLanguages = TranslateController.getSuggestedLanguages(currentTranslateTo); + ArrayList allLanguages = TranslateController.getLanguages(); + if (currentTranslateTo != null) { + String displayName = TranslateAlert2.capitalFirst(TranslateAlert2.languageName(currentTranslateTo)); + if (displayName != null) { + ActionBarMenuSubItem button = new ActionBarMenuSubItem(getContext(), 2, false, false, resourcesProvider); + button.setChecked(true); + button.setText(displayName); + swipeBackScroll.addView(button); + } + } + for (TranslateController.Language lng : suggestedLanguages) { + final String code = lng.code; + if (TextUtils.equals(code, detectedLanguage)) { + continue; + } + + ActionBarMenuSubItem button = new ActionBarMenuSubItem(getContext(), 2, false, false, resourcesProvider); + final boolean checked = currentTranslateTo != null && currentTranslateTo.equals(code); + button.setChecked(checked); + button.setText(lng.displayName); + if (!checked) { + button.setOnClickListener(e -> { + translateController.setDialogTranslateTo(dialogId, code); + popupWindow.dismiss(); + updateText(); + }); + } + swipeBackScroll.addView(button); + } + swipeBackScroll.addView(new ActionBarPopupWindow.GapView(getContext(), resourcesProvider), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); + for (TranslateController.Language lng : allLanguages) { + final String code = lng.code; + if (TextUtils.equals(code, detectedLanguage)) { + continue; + } + + ActionBarMenuSubItem button = new ActionBarMenuSubItem(getContext(), 2, false, false, resourcesProvider); + final boolean checked = currentTranslateTo != null && currentTranslateTo.equals(code); + button.setChecked(checked); + button.setText(lng.displayName); + if (!checked) { + button.setOnClickListener(e -> { + translateController.setDialogTranslateTo(dialogId, code); + popupWindow.dismiss(); + updateText(); + }); + } + swipeBackScroll.addView(button); + } + +// if (detectedLanguage != null) { +// ActionBarMenuSubItem translateFromButton = new ActionBarMenuSubItem(getContext(), true, false, resourcesProvider); +// translateFromButton.setTextAndIcon(LocaleController.getString("DetectedLanguage", R.string.DetectedLanguage), R.drawable.msg_language); +// translateFromButton.setSubtext(TranslateAlert2.languageName(detectedLanguage)); +// translateFromButton.setItemHeight(56); +// popupLayout.addView(translateFromButton); +// } + + popupLayout.addView(new ActionBarPopupWindow.GapView(getContext(), resourcesProvider), LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); + + if (detectedLanguageName != null && detectedLanguage != null) { + ActionBarMenuSubItem dontTranslateButton = new ActionBarMenuSubItem(getContext(), true, false, resourcesProvider); + String text; + String lang = LocaleController.getString("TranslateLanguage" + detectedLanguage.toUpperCase()); + if (lang == null || lang.startsWith("LOC_ERR")) { + lang = detectedLanguageName; + text = LocaleController.formatString("DoNotTranslateLanguageOther", R.string.DoNotTranslateLanguageOther, lang); + } else { + text = LocaleController.formatString("DoNotTranslateLanguage", R.string.DoNotTranslateLanguage, lang); + } + dontTranslateButton.setTextAndIcon(text, R.drawable.msg_block2); + dontTranslateButton.setOnClickListener(e -> { + RestrictedLanguagesSelectActivity.toggleLanguage(detectedLanguage, true); + translateController.checkRestrictedLanguagesUpdate(); + translateController.setHideTranslateDialog(dialogId, true); + BulletinFactory.of(fragment).createSimpleBulletin(R.raw.msg_translate, AndroidUtilities.replaceTags(LocaleController.formatString("AddedToDoNotTranslate", R.string.AddedToDoNotTranslate, TranslateAlert2.capitalFirst(detectedLanguageName))), LocaleController.getString("Settings", R.string.Settings), () -> { + fragment.presentFragment(new RestrictedLanguagesSelectActivity()); + }).show(); + popupWindow.dismiss(); + }); + popupLayout.addView(dontTranslateButton); + } + + ActionBarMenuSubItem hideButton = new ActionBarMenuSubItem(getContext(), true, false, resourcesProvider); + hideButton.setTextAndIcon(LocaleController.getString("Hide", R.string.Hide), R.drawable.msg_cancel); + hideButton.setOnClickListener(e -> { + translateController.setHideTranslateDialog(dialogId, true); + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-dialogId); + final boolean isChannel = chat != null && ChatObject.isChannelAndNotMegaGroup(chat); + final CharSequence message = AndroidUtilities.replaceTags( + isChannel ? + LocaleController.getString("TranslationBarHiddenForChannel", R.string.TranslationBarHiddenForChannel) : + chat != null ? + LocaleController.getString("TranslationBarHiddenForGroup", R.string.TranslationBarHiddenForGroup) : + LocaleController.getString("TranslationBarHiddenForChat", R.string.TranslationBarHiddenForChat) + ); + BulletinFactory.of(fragment).createSimpleBulletin(R.raw.msg_translate, message, LocaleController.getString("Undo", R.string.Undo), () -> { + translateController.setHideTranslateDialog(dialogId, false); + }).show(); + popupWindow.dismiss(); + }); + popupLayout.addView(hideButton); + + popupWindow.setPauseNotifications(true); + popupWindow.setDismissAnimationDuration(220); + popupWindow.setOutsideTouchable(true); + popupWindow.setClippingEnabled(true); + popupWindow.setAnimationStyle(R.style.PopupContextAnimation); + popupWindow.setFocusable(true); + popupWindow.setInputMethodMode(ActionBarPopupWindow.INPUT_METHOD_NOT_NEEDED); + popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED); + popupWindow.showAsDropDown(menuView, 0, -menuView.getMeasuredHeight() - AndroidUtilities.dp(8)); + } + + public void updateText() { + TranslateController translateController = MessagesController.getInstance(currentAccount).getTranslateController(); + if (translateController.isTranslatingDialog(dialogId)) { + textView.setText(TextUtils.concat(translateIcon, " ", LocaleController.getString("ShowOriginalButton", R.string.ShowOriginalButton))); + } else { + String lng = translateController.getDialogTranslateTo(dialogId); + if (lng == null) { + lng = "en"; + } + String text; + String lang = LocaleController.getString("TranslateLanguage" + lng.toUpperCase()); + if (lang == null || lang.startsWith("LOC_ERR")) { + lang = TranslateAlert2.languageName(lng); + text = LocaleController.formatString("TranslateToButtonOther", R.string.TranslateToButtonOther, lang); + } else { + text = LocaleController.formatString("TranslateToButton", R.string.TranslateToButton, lang); + } + textView.setText(TextUtils.concat(translateIcon, " ", text)); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/VectorAvatarThumbDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/VectorAvatarThumbDrawable.java new file mode 100644 index 00000000000..af5577a7ce1 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/VectorAvatarThumbDrawable.java @@ -0,0 +1,239 @@ +package org.telegram.ui.Components; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.drawable.Drawable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.graphics.ColorUtils; + +import com.google.android.exoplayer2.util.Log; + +import org.telegram.messenger.DocumentObject; +import org.telegram.messenger.ImageLocation; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.MediaDataController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.SvgHelper; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; + +import java.util.HashSet; + +public class VectorAvatarThumbDrawable extends Drawable implements AnimatedEmojiSpan.InvalidateHolder, AttachableDrawable, NotificationCenter.NotificationCenterDelegate { + + public static final int TYPE_SMALL = 1; + public static final int TYPE_PROFILE = 2; + public static final int TYPE_STATIC = 3; + public final GradientTools gradientTools = new GradientTools(); + private final int type; + float roundRadius; + boolean isPremium; + + ImageReceiver currentParent; + HashSet parents = new HashSet<>(); + + AnimatedEmojiDrawable animatedEmojiDrawable; + ImageReceiver imageReceiver; + ImageReceiver stickerPreloadImageReceiver = new ImageReceiver(); + final int currentAccount = UserConfig.selectedAccount; + boolean imageSeted; + TLRPC.TL_videoSizeStickerMarkup sizeStickerMarkup; + + public VectorAvatarThumbDrawable(TLRPC.VideoSize vectorImageMarkup, boolean isPremiumUser, int type) { + this.type = type; + this.isPremium = isPremiumUser; + int color1 = ColorUtils.setAlphaComponent(vectorImageMarkup.background_colors.get(0), 255); + int color2 = vectorImageMarkup.background_colors.size() > 1 ? ColorUtils.setAlphaComponent(vectorImageMarkup.background_colors.get(1), 255) : 0; + int color3 = vectorImageMarkup.background_colors.size() > 2 ? ColorUtils.setAlphaComponent(vectorImageMarkup.background_colors.get(2), 255) : 0; + int color4 = vectorImageMarkup.background_colors.size() > 3 ? ColorUtils.setAlphaComponent(vectorImageMarkup.background_colors.get(3), 255) : 0; + gradientTools.setColors(color1, color2, color3, color4); + if (vectorImageMarkup instanceof TLRPC.TL_videoSizeEmojiMarkup) { + TLRPC.TL_videoSizeEmojiMarkup emojiMarkup = (TLRPC.TL_videoSizeEmojiMarkup) vectorImageMarkup; + int cacheType = AnimatedEmojiDrawable.STANDARD_LOTTIE_FRAME; + if (type == TYPE_SMALL && isPremiumUser) { + cacheType = AnimatedEmojiDrawable.CACHE_TYPE_EMOJI_STATUS; + } else if (type == TYPE_PROFILE) { + cacheType = AnimatedEmojiDrawable.CACHE_TYPE_AVATAR_CONSTRUCTOR_PREVIEW2; + } + + animatedEmojiDrawable = new AnimatedEmojiDrawable(cacheType, UserConfig.selectedAccount, emojiMarkup.emoji_id); + } else if (vectorImageMarkup instanceof TLRPC.TL_videoSizeStickerMarkup) { + sizeStickerMarkup = (TLRPC.TL_videoSizeStickerMarkup) vectorImageMarkup; + imageReceiver = new ImageReceiver() { + @Override + public void invalidate() { + VectorAvatarThumbDrawable.this.invalidate(); + } + }; + imageReceiver.setInvalidateAll(true); + if (type == TYPE_SMALL) { + imageReceiver.setAutoRepeatCount(2); + } + setImage(); + } + } + + private void setImage() { + TLRPC.TL_messages_stickerSet set = MediaDataController.getInstance(currentAccount).getStickerSet(sizeStickerMarkup.stickerset, false); + if (set != null) { + imageSeted = true; + for (int i = 0; i < set.documents.size(); i++) { + if (set.documents.get(i).id == sizeStickerMarkup.sticker_id) { + TLRPC.Document document = set.documents.get(i); + TLRPC.Document thumb = null; + String filter = "50_50_firstframe"; + String thumbFilter = null; + if (isPremium && type == TYPE_SMALL) { + filter = "50_50"; + thumbFilter = "50_50_firstframe"; + thumb = document; + } else if (type == TYPE_PROFILE) { + filter = "100_100"; + thumbFilter = "50_50_firstframe"; + thumb = document; + } + SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(document, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f); + imageReceiver.setImage(ImageLocation.getForDocument(document), filter, ImageLocation.getForDocument(thumb), thumbFilter, null, null, svgThumb, 0, "tgs", document, 0); + if (type == TYPE_STATIC) { + stickerPreloadImageReceiver.setImage(ImageLocation.getForDocument(document), "100_100", null, null, null, 0, "tgs", document, 0); + } + break; + } + } + } + } + + @Override + public void draw(@NonNull Canvas canvas) { + gradientTools.setBounds(getBounds().left, getBounds().top, getBounds().right, getBounds().bottom); + + if (currentParent != null) { + roundRadius = currentParent.getRoundRadius()[0]; + } + if (roundRadius == 0) { + canvas.drawRect(getBounds(), gradientTools.paint); + } else { + canvas.drawRoundRect(gradientTools.bounds, roundRadius, roundRadius, gradientTools.paint); + } + int cx = getBounds().centerX(); + int cy = getBounds().centerY(); + int size = (int) (getBounds().width() * AvatarConstructorFragment.STICKER_DEFAULT_SCALE) >> 1; + if (animatedEmojiDrawable != null) { + if (animatedEmojiDrawable.getImageReceiver() != null) { + animatedEmojiDrawable.getImageReceiver().setRoundRadius((int) (size * 2 * AvatarConstructorFragment.STICKER_DEFAULT_ROUND_RADIUS)); + } + animatedEmojiDrawable.setBounds(cx - size, cy - size, cx + size, cy + size); + animatedEmojiDrawable.draw(canvas); + } + if (imageReceiver != null) { + imageReceiver.setRoundRadius((int) (size * 2 * AvatarConstructorFragment.STICKER_DEFAULT_ROUND_RADIUS)); + imageReceiver.setImageCoords(cx - size, cy - size, size * 2, size * 2); + imageReceiver.draw(canvas); + } + } + + @Override + public void setAlpha(int alpha) { + gradientTools.paint.setAlpha(alpha); + if (animatedEmojiDrawable != null) { + animatedEmojiDrawable.setAlpha(alpha); + } + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + + } + + @Override + public int getOpacity() { + return 0; + } + + public void setRoundRadius(float roundRadius) { + this.roundRadius = roundRadius; + } + + @Override + public void onAttachedToWindow(ImageReceiver parent) { + if (parent == null) { + return; + } + roundRadius = parent.getRoundRadius()[0]; + if (parents.isEmpty()) { + if (animatedEmojiDrawable != null) { + animatedEmojiDrawable.addView(this); + } + if (imageReceiver != null) { + imageReceiver.onAttachedToWindow(); + } + if (stickerPreloadImageReceiver != null) { + stickerPreloadImageReceiver.onAttachedToWindow(); + } + } + parents.add(parent); + if (sizeStickerMarkup != null) { + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.groupStickersDidLoad); + } + } + + @Override + public void onDetachedFromWindow(ImageReceiver parent) { + parents.remove(parent); + if (parents.isEmpty()) { + if (animatedEmojiDrawable != null) { + animatedEmojiDrawable.removeView(this); + } + if (imageReceiver != null) { + imageReceiver.onDetachedFromWindow(); + } + if (stickerPreloadImageReceiver != null) { + stickerPreloadImageReceiver.onDetachedFromWindow(); + } + + } + if (sizeStickerMarkup != null) { + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.groupStickersDidLoad); + } + } + + @Override + public void invalidate() { + for (ImageReceiver parent : parents) { + parent.invalidate(); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + VectorAvatarThumbDrawable that = (VectorAvatarThumbDrawable) o; + if (type == that.type && gradientTools.color1 == that.gradientTools.color1 && gradientTools.color2 == that.gradientTools.color2 && gradientTools.color3 == that.gradientTools.color3 && gradientTools.color4 == that.gradientTools.color4) { + if (animatedEmojiDrawable != null && that.animatedEmojiDrawable != null) { + return animatedEmojiDrawable.getDocumentId() == that.animatedEmojiDrawable.getDocumentId(); + } + if (sizeStickerMarkup != null && that.sizeStickerMarkup != null) { + return sizeStickerMarkup.stickerset.id == that.sizeStickerMarkup.stickerset.id && sizeStickerMarkup.sticker_id == that.sizeStickerMarkup.sticker_id; + } + } + return false; + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.groupStickersDidLoad) { + if (!imageSeted) { + setImage(); + return; + } + } + } + + public void setParent(ImageReceiver imageReceiver) { + currentParent = imageReceiver; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ViewPagerFixed.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ViewPagerFixed.java index 6d85da83f2b..e44643b8c10 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ViewPagerFixed.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ViewPagerFixed.java @@ -812,6 +812,7 @@ private static class Tab { public String title; public int titleWidth; public int counter; + public float alpha = 1f; public Tab(int i, String t) { id = i; @@ -851,6 +852,7 @@ public void setTab(Tab tab, int position) { currentTab = tab; currentPosition = position; setContentDescription(tab.title); + setAlpha(tab.alpha); requestLayout(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect.java index c6b08d291e5..cd999dc34e5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/spoilers/SpoilerEffect.java @@ -5,7 +5,6 @@ import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.annotation.SuppressLint; -import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; @@ -49,7 +48,6 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Stack; @@ -60,7 +58,6 @@ public class SpoilerEffect extends Drawable { public final static int PARTICLES_PER_CHARACTER = measureParticlesPerCharacter(); private final static float VERTICAL_PADDING_DP = 2.5f; private final static int RAND_REPEAT = 14; - private final static float KEYPOINT_DELTA = 5f; private final static int FPS = 30; private final static int renderDelayMs = 1000 / FPS + 1; public final static float[] ALPHAS = { @@ -92,7 +89,6 @@ public class SpoilerEffect extends Drawable { private ValueAnimator rippleAnimator; private List spaces = new ArrayList<>(); - private List keyPoints; private int mAlpha = 0xFF; private TimeInterpolator rippleInterpolator = input -> input; @@ -248,16 +244,6 @@ public void setRippleInterpolator(@NonNull TimeInterpolator rippleInterpolator) this.rippleInterpolator = rippleInterpolator; } - /** - * Sets new keypoints - * - * @param keyPoints New keypoints - */ - public void setKeyPoints(List keyPoints) { - this.keyPoints = keyPoints; - invalidateSelf(); - } - /** * Gets ripple path */ @@ -439,15 +425,8 @@ private boolean isOutOfBounds(int left, int top, int right, int bottom, float x, } private void generateRandomLocation(Particle newParticle, int i) { - if (keyPoints != null && !keyPoints.isEmpty()) { - float rf = particleRands[i % RAND_REPEAT]; - long kp = keyPoints.get(Utilities.fastRandom.nextInt(keyPoints.size())); - newParticle.x = getBounds().left + (kp >> 16) + rf * AndroidUtilities.dp(KEYPOINT_DELTA) - AndroidUtilities.dp(KEYPOINT_DELTA / 2f); - newParticle.y = getBounds().top + (kp & 0xFFFF) + rf * AndroidUtilities.dp(KEYPOINT_DELTA) - AndroidUtilities.dp(KEYPOINT_DELTA / 2f); - } else { - newParticle.x = getBounds().left + Utilities.fastRandom.nextFloat() * getBounds().width(); - newParticle.y = getBounds().top + Utilities.fastRandom.nextFloat() * getBounds().height(); - } + newParticle.x = getBounds().left + Utilities.fastRandom.nextFloat() * getBounds().width(); + newParticle.y = getBounds().top + Utilities.fastRandom.nextFloat() * getBounds().height(); } @Override @@ -521,42 +500,6 @@ public int getOpacity() { return PixelFormat.TRANSPARENT; } - /** - * @param textLayout Text layout to measure - * @return Measured key points - */ - public static synchronized List measureKeyPoints(Layout textLayout) { - int w = textLayout.getWidth(); - int h = textLayout.getHeight(); - - if (w <= 0 || h <= 0) - return Collections.emptyList(); - - Bitmap measureBitmap = Bitmap.createBitmap(Math.round(w), Math.round(h), Bitmap.Config.ARGB_4444); // We can use 4444 as we don't need accuracy here - Canvas measureCanvas = new Canvas(measureBitmap); - textLayout.draw(measureCanvas); - - int[] pixels = new int[measureBitmap.getWidth() * measureBitmap.getHeight()]; - measureBitmap.getPixels(pixels, 0, measureBitmap.getWidth(), 0, 0, w, h); - - int sX = -1; - ArrayList keyPoints = new ArrayList<>(pixels.length); - for (int x = 0; x < w; x++) { - for (int y = 0; y < h; y++) { - int clr = pixels[y * measureBitmap.getWidth() + x]; - if (Color.alpha(clr) >= 0x80) { - if (sX == -1) { - sX = x; - } - keyPoints.add(((long) (x - sX) << 16) + y); - } - } - } - keyPoints.trimToSize(); - measureBitmap.recycle(); - return keyPoints; - } - /** * @return Max particles count */ @@ -662,8 +605,6 @@ private static void addSpoilersInternal(View v, Spanned spannable, Layout textLa spoilerEffect.setBounds((int) Math.min(ps, pe), (int) lineTop, (int) Math.max(ps, pe), (int) lineBottom); spoilerEffect.setColor(textLayout.getPaint().getColor()); spoilerEffect.setRippleInterpolator(Easings.easeInQuad); - if (!spoilerEffect.isLowDevice) - spoilerEffect.setKeyPoints(SpoilerEffect.measureKeyPoints(newLayout)); spoilerEffect.updateMaxParticles(); if (v != null) { spoilerEffect.setParentView(v); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java index 0b6b2c74e2e..bc45e4538b3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java @@ -113,13 +113,13 @@ public interface ContactAddActivityDelegate { public ContactAddActivity(Bundle args) { super(args); - imageUpdater = new ImageUpdater(true); + imageUpdater = new ImageUpdater(true, ImageUpdater.FOR_TYPE_USER, true); } public ContactAddActivity(Bundle args, Theme.ResourcesProvider resourcesProvider) { super(args); this.resourcesProvider = resourcesProvider; - imageUpdater = new ImageUpdater(true); + imageUpdater = new ImageUpdater(true, ImageUpdater.FOR_TYPE_USER, true); } @Override @@ -450,7 +450,7 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto LocaleController.formatString("ResetToOriginalPhotoMessage", R.string.ResetToOriginalPhotoMessage, user.first_name), LocaleController.getString("Reset", R.string.Reset), () -> { avatar = null; - sendPhotoChangedRequest(null, null,null, null, 0, TYPE_SET); + sendPhotoChangedRequest(null, null,null, null, null, 0, TYPE_SET); TLRPC.User user1 = getMessagesController().getUser(user_id); user1.photo.personal = false; @@ -670,7 +670,7 @@ public boolean canFinishFragment() { } @Override - public void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double videoStartTimestamp, String videoPath, TLRPC.PhotoSize bigSize, TLRPC.PhotoSize smallSize, boolean isVideo) { + public void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double videoStartTimestamp, String videoPath, TLRPC.PhotoSize bigSize, TLRPC.PhotoSize smallSize, boolean isVideo, TLRPC.VideoSize emojiMarkup) { AndroidUtilities.runOnUIThread(() -> { if (imageUpdater.isCanceled()) { return; @@ -701,7 +701,7 @@ public void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double getNotificationCenter().postNotificationName(NotificationCenter.reloadDialogPhotos); getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_AVATAR); } - sendPhotoChangedRequest(avatar, bigSize.location, photo, video, videoStartTimestamp, photoSelectedTypeFinal); + sendPhotoChangedRequest(avatar, bigSize.location, photo, video, emojiMarkup, videoStartTimestamp, photoSelectedTypeFinal); showAvatarProgress(false, true); } else { avatarImage.setImage(ImageLocation.getForLocal(avatar), "50_50", avatarDrawable, getMessagesController().getUser(user_id)); @@ -761,7 +761,7 @@ private void createServiceMessageLocal(TLRPC.PhotoSize smallSize, TLRPC.PhotoSiz getMessagesController().photoSuggestion.put(message.local_id, imageUpdater); } - private void sendPhotoChangedRequest(TLRPC.FileLocation avatar, TLRPC.FileLocation bigAvatar, TLRPC.InputFile photo, TLRPC.InputFile video, double videoStartTimestamp, int photoSelectedTypeFinal) { + private void sendPhotoChangedRequest(TLRPC.FileLocation avatar, TLRPC.FileLocation bigAvatar, TLRPC.InputFile photo, TLRPC.InputFile video, TLRPC.VideoSize emojiMarkup, double videoStartTimestamp, int photoSelectedTypeFinal) { TLRPC.TL_photos_uploadContactProfilePhoto req = new TLRPC.TL_photos_uploadContactProfilePhoto(); req.user_id = getMessagesController().getInputUser(user_id); @@ -775,6 +775,10 @@ private void sendPhotoChangedRequest(TLRPC.FileLocation avatar, TLRPC.FileLocati req.video_start_ts = videoStartTimestamp; req.flags |= 4; } + if (emojiMarkup != null) { + req.flags |= 32; + req.video_emoji_markup = emojiMarkup; + } if (photoSelectedTypeFinal == TYPE_SUGGEST) { req.suggest = true; req.flags |= 8; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java index 04a82ea1214..9d05030f92e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java @@ -620,7 +620,14 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { floatingButtonContainer = new FrameLayout(context); frameLayout.addView(floatingButtonContainer, LayoutHelper.createFrame((Build.VERSION.SDK_INT >= 21 ? 56 : 60) + 20, (Build.VERSION.SDK_INT >= 21 ? 56 : 60) + 20, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.BOTTOM, LocaleController.isRTL ? 4 : 0, 0, LocaleController.isRTL ? 0 : 4, 0)); floatingButtonContainer.setOnClickListener(v -> { - new NewContactBottomSheet(ContactsActivity.this, getContext()).show(); + AndroidUtilities.requestAdjustNothing(getParentActivity(), getClassGuid()); + new NewContactBottomSheet(ContactsActivity.this, getContext()) { + @Override + public void dismissInternal() { + super.dismissInternal(); + AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); + } + }.show(); }); floatingButton = new RLottieImageView(context); @@ -681,9 +688,9 @@ private void didSelectResult(final TLRPC.User user, boolean useAlert, String par TLRPC.Chat chat = getMessagesController().getChat(channelId); AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); if (ChatObject.canAddAdmins(chat)) { - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setTitle(LocaleController.getString("AddBotAdminAlert", R.string.AddBotAdminAlert)); builder.setMessage(LocaleController.getString("AddBotAsAdmin", R.string.AddBotAsAdmin)); - builder.setPositiveButton(LocaleController.getString("MakeAdmin", R.string.MakeAdmin), (dialogInterface, i) -> { + builder.setPositiveButton(LocaleController.getString("AddAsAdmin", R.string.AddAsAdmin), (dialogInterface, i) -> { if (delegate != null) { delegate.didSelectContact(user, param, this); delegate = null; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactsWidgetConfigActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactsWidgetConfigActivity.java index 981dd27a30b..c8b3d60dc01 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactsWidgetConfigActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactsWidgetConfigActivity.java @@ -23,7 +23,7 @@ protected boolean handleIntent(Intent intent, boolean isNew, boolean restore, bo if (creatingAppWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 10); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_WIDGET); args.putBoolean("allowSwitchAccount", true); EditWidgetActivity fragment = new EditWidgetActivity(EditWidgetActivity.TYPE_CONTACTS, creatingAppWidgetId); fragment.setDelegate(dialogs -> { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContentPreviewViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/ContentPreviewViewer.java index 22dabdb5662..08aa8d33b6f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContentPreviewViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContentPreviewViewer.java @@ -60,9 +60,14 @@ import org.telegram.ui.Cells.StickerCell; import org.telegram.ui.Cells.StickerEmojiCell; import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.AnimatedEmojiDrawable; +import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.EmojiPacksAlert; +import org.telegram.ui.Components.EmojiView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.SuggestEmojiView; import java.util.ArrayList; @@ -85,14 +90,14 @@ default boolean can() { return true; } - void sendSticker(TLRPC.Document sticker, String query, Object parent, boolean notify, int scheduleDate); - void openSet(TLRPC.InputStickerSet set, boolean clearInputField); - boolean needSend(); + boolean needSend(int contentType); + default void sendSticker(TLRPC.Document sticker, String query, Object parent, boolean notify, int scheduleDate) {} + default void sendGif(Object gif, Object parent, boolean notify, int scheduleDate) {} + default void sendEmoji(TLRPC.Document emoji) {} boolean canSchedule(); - boolean isInScheduleMode(); long getDialogId(); @@ -100,7 +105,6 @@ default boolean can() { default boolean needRemove() { return false; } - default void remove(SendMessagesHelper.ImportingSticker sticker) { } @@ -113,22 +117,34 @@ default boolean needOpen() { return true; } - default void sendGif(Object gif, Object parent, boolean notify, int scheduleDate) { + default void gifAddedOrDeleted() {} + default boolean needMenu() { + return true; } - default void gifAddedOrDeleted() { + default Boolean canSetAsStatus(TLRPC.Document document) { + return null; + } + default void setAsEmojiStatus(TLRPC.Document document, Integer until) {} + default boolean needCopy() { + return false; } + default void copyEmoji(TLRPC.Document document) {} - default boolean needMenu() { - return true; + default void resetTouch() {} + + default boolean needRemoveFromRecent(TLRPC.Document document) { + return false; } + default void removeFromRecent(TLRPC.Document document) {} } - private final static int CONTENT_TYPE_NONE = -1; - private final static int CONTENT_TYPE_STICKER = 0; - private final static int CONTENT_TYPE_GIF = 1; + public final static int CONTENT_TYPE_NONE = -1; + public final static int CONTENT_TYPE_STICKER = 0; + public final static int CONTENT_TYPE_GIF = 1; + public final static int CONTENT_TYPE_EMOJI = 2; private static TextPaint textPaint; @@ -196,12 +212,12 @@ public void run() { menuVisible = true; containerView.invalidate(); if (delegate != null) { - if (delegate.needSend() && !delegate.isInScheduleMode()) { + if (delegate.needSend(currentContentType) && !delegate.isInScheduleMode()) { items.add(LocaleController.getString("SendStickerPreview", R.string.SendStickerPreview)); icons.add(R.drawable.msg_send); actions.add(0); } - if (delegate.needSend() && !delegate.isInScheduleMode()) { + if (delegate.needSend(currentContentType) && !delegate.isInScheduleMode()) { items.add(LocaleController.getString("SendWithoutSound", R.string.SendWithoutSound)); icons.add(R.drawable.input_notify_off); actions.add(6); @@ -273,7 +289,7 @@ public void onClick(View v) { } } }; - ActionBarPopupWindow.ActionBarPopupWindowLayout previewMenu = new ActionBarPopupWindow.ActionBarPopupWindowLayout(containerView.getContext(), R.drawable.popup_fixed_alert2, resourcesProvider); + ActionBarPopupWindow.ActionBarPopupWindowLayout previewMenu = new ActionBarPopupWindow.ActionBarPopupWindowLayout(containerView.getContext(), R.drawable.popup_fixed_alert3, resourcesProvider); for (int i = 0; i < items.size(); i++) { View item = ActionBarMenuItem.addItem(previewMenu, icons.get(i), items.get(i), false, resourcesProvider); @@ -329,13 +345,144 @@ public void dismiss() { popupWindow.showAtLocation(containerView, 0, (int) ((containerView.getMeasuredWidth() - previewMenu.getMeasuredWidth()) / 2f), y); containerView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + } else if (currentContentType == CONTENT_TYPE_EMOJI && delegate != null) { + menuVisible = true; + containerView.invalidate(); + ArrayList items = new ArrayList<>(); + final ArrayList actions = new ArrayList<>(); + ArrayList icons = new ArrayList<>(); + + if (delegate.needSend(currentContentType)) { + items.add(LocaleController.getString("SendEmojiPreview", R.string.SendEmojiPreview)); + icons.add(R.drawable.msg_send); + actions.add(0); + } + Boolean canSetAsStatus = delegate.canSetAsStatus(currentDocument); + if (canSetAsStatus != null) { + if (canSetAsStatus) { + items.add(LocaleController.getString("SetAsEmojiStatus", R.string.SetAsEmojiStatus)); + icons.add(R.drawable.msg_smile_status); + actions.add(1); + } else { + items.add(LocaleController.getString("RemoveStatus", R.string.RemoveStatus)); + icons.add(R.drawable.msg_smile_status); + actions.add(2); + } + } + if (delegate.needCopy()) { + items.add(LocaleController.getString("CopyEmojiPreview", R.string.CopyEmojiPreview)); + icons.add(R.drawable.msg_copy); + actions.add(3); + } + if (delegate.needRemoveFromRecent(currentDocument)) { + items.add(LocaleController.getString("RemoveFromRecent", R.string.RemoveFromRecent)); + icons.add(R.drawable.msg_delete); + actions.add(4); + } + if (items.isEmpty()) { + return; + } + + int[] ic = new int[icons.size()]; + for (int a = 0; a < icons.size(); a++) { + ic[a] = icons.get(a); + } + + ActionBarPopupWindow.ActionBarPopupWindowLayout previewMenu = new ActionBarPopupWindow.ActionBarPopupWindowLayout(containerView.getContext(), R.drawable.popup_fixed_alert2, resourcesProvider); + + View.OnClickListener onItemClickListener = v -> { + if (parentActivity == null) { + return; + } + int which = (int) v.getTag(); + int action = actions.get(which); + if (action == 0) { + delegate.sendEmoji(currentDocument); + } else if (action == 1) { + delegate.setAsEmojiStatus(currentDocument, null); + } else if (action == 2) { + delegate.setAsEmojiStatus(null, null); + } else if (action == 3) { + delegate.copyEmoji(currentDocument); + } else if (action == 4) { + delegate.removeFromRecent(currentDocument); + } + if (popupWindow != null) { + popupWindow.dismiss(); + } + }; + + for (int i = 0; i < items.size(); i++) { + ActionBarMenuSubItem item = ActionBarMenuItem.addItem(i == 0, i == items.size() - 1, previewMenu, icons.get(i), items.get(i), false, resourcesProvider); + if (actions.get(i) == 4) { + item.setIconColor(getThemedColor(Theme.key_dialogRedIcon)); + item.setTextColor(getThemedColor(Theme.key_dialogTextRed2)); + } + item.setTag(i); + item.setOnClickListener(onItemClickListener); + } + popupWindow = new ActionBarPopupWindow(previewMenu, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT) { + @Override + public void dismiss() { + super.dismiss(); + popupWindow = null; + menuVisible = false; + if (closeOnDismiss) { + close(); + } + } + }; + popupWindow.setPauseNotifications(true); + popupWindow.setDismissAnimationDuration(150); + popupWindow.setScaleOut(true); + popupWindow.setOutsideTouchable(true); + popupWindow.setClippingEnabled(true); + popupWindow.setAnimationStyle(R.style.PopupContextAnimation); + popupWindow.setFocusable(true); + previewMenu.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), View.MeasureSpec.AT_MOST)); + popupWindow.setInputMethodMode(ActionBarPopupWindow.INPUT_METHOD_NOT_NEEDED); + popupWindow.getContentView().setFocusableInTouchMode(true); + + int insets = 0; + int top; + if (Build.VERSION.SDK_INT >= 21 && lastInsets != null) { + insets = lastInsets.getStableInsetBottom() + lastInsets.getStableInsetTop(); + top = lastInsets.getStableInsetTop(); + } else { + top = AndroidUtilities.statusBarHeight; + } + int size = Math.min(containerView.getWidth(), containerView.getHeight() - insets) - AndroidUtilities.dp(40f); + + int y = (int) (moveY + Math.max(size / 2 + top + (stickerEmojiLayout != null ? AndroidUtilities.dp(40) : 0), (containerView.getHeight() - insets - keyboardHeight) / 2) + size / 2); + y += AndroidUtilities.dp(24) - moveY; + popupWindow.showAtLocation(containerView, 0, (int) ((containerView.getMeasuredWidth() - previewMenu.getMeasuredWidth()) / 2f), y); + ActionBarPopupWindow.startAnimation(previewMenu); + + containerView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + + if (moveY != 0) { + if (finalMoveY == 0) { + finalMoveY = 0; + startMoveY = moveY; + } + ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 1f); + valueAnimator.addUpdateListener(animation -> { + currentMoveYProgress = (float) animation.getAnimatedValue(); + moveY = startMoveY + (finalMoveY - startMoveY) * currentMoveYProgress; + ContentPreviewViewer.this.containerView.invalidate(); + }); + valueAnimator.setDuration(350); + valueAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + valueAnimator.start(); + } } else if (delegate != null) { menuVisible = true; + containerView.invalidate(); ArrayList items = new ArrayList<>(); final ArrayList actions = new ArrayList<>(); ArrayList icons = new ArrayList<>(); - if (delegate.needSend() && !delegate.isInScheduleMode()) { + if (delegate.needSend(currentContentType) && !delegate.isInScheduleMode()) { items.add(LocaleController.getString("SendGifPreview", R.string.SendGifPreview)); icons.add(R.drawable.msg_send); actions.add(0); @@ -360,6 +507,9 @@ public void dismiss() { } else { canDelete = false; } + if (items.isEmpty()) { + return; + } int[] ic = new int[icons.size()]; for (int a = 0; a < icons.size(); a++) { @@ -626,10 +776,19 @@ public boolean onTouch(MotionEvent event, final RecyclerListView listView, final contentType = CONTENT_TYPE_GIF; centerImage.setRoundRadius(AndroidUtilities.dp(6)); } + } else if (view instanceof EmojiPacksAlert.EmojiImageView) { + contentType = CONTENT_TYPE_EMOJI; + centerImage.setRoundRadius(0); + } else if (view instanceof EmojiView.ImageViewEmoji && ((EmojiView.ImageViewEmoji) view).getSpan() != null) { + contentType = CONTENT_TYPE_EMOJI; + centerImage.setRoundRadius(0); } if (contentType == CONTENT_TYPE_NONE || view == currentPreviewCell) { break; } + if (delegate != null) { + delegate.resetTouch(); + } if (currentPreviewCell instanceof StickerEmojiCell) { ((StickerEmojiCell) currentPreviewCell).setScaled(false); } else if (currentPreviewCell instanceof StickerCell) { @@ -660,6 +819,38 @@ public boolean onTouch(MotionEvent event, final RecyclerListView listView, final if (contentType != CONTENT_TYPE_GIF) { contextLinkCell.setScaled(true); } + } else if (currentPreviewCell instanceof EmojiPacksAlert.EmojiImageView) { + EmojiPacksAlert.EmojiImageView imageView = (EmojiPacksAlert.EmojiImageView) currentPreviewCell; + TLRPC.Document document = imageView.getDocument(); + if (document != null) { + open(document, null, MessageObject.findAnimatedEmojiEmoticon(document, null), null, null, contentType, false, null, resourcesProvider); + } + } else if (currentPreviewCell instanceof EmojiView.ImageViewEmoji) { + EmojiView.ImageViewEmoji imageView = (EmojiView.ImageViewEmoji) currentPreviewCell; + AnimatedEmojiSpan span = imageView.getSpan(); + TLRPC.Document document = null; + if (span != null) { + document = span.document; + if (document == null) { + document = AnimatedEmojiDrawable.findDocument(currentAccount, span.getDocumentId()); + } + } + if (document != null) { + open(document, null, MessageObject.findAnimatedEmojiEmoticon(document, null), null, null, contentType, false, null, resourcesProvider); + } else { + return false; + } + } else if (currentPreviewCell instanceof SuggestEmojiView.EmojiImageView) { + SuggestEmojiView.EmojiImageView emojiImageView = (SuggestEmojiView.EmojiImageView) currentPreviewCell; + Drawable drawable = emojiImageView.drawable; + TLRPC.Document document = null; + if (drawable instanceof AnimatedEmojiDrawable) { + document = ((AnimatedEmojiDrawable) drawable).getDocument(); + } + if (document == null) { + return false; + } + open(document, null, MessageObject.findAnimatedEmojiEmoticon(document, null), null, null, contentType, false, null, resourcesProvider); } runSmoothHaptic(); @@ -744,6 +935,19 @@ public boolean onInterceptTouchEvent(MotionEvent event, final RecyclerListView l centerImage.setRoundRadius(AndroidUtilities.dp(6)); } } + } else if (view instanceof EmojiPacksAlert.EmojiImageView) { + contentType = CONTENT_TYPE_EMOJI; + centerImage.setRoundRadius(0); + } else if (view instanceof EmojiView.ImageViewEmoji && ((EmojiView.ImageViewEmoji) view).getSpan() != null) { + contentType = CONTENT_TYPE_EMOJI; + centerImage.setRoundRadius(0); + } else if (view instanceof SuggestEmojiView.EmojiImageView) { + SuggestEmojiView.EmojiImageView emojiImageView = (SuggestEmojiView.EmojiImageView) view; + Drawable drawable = emojiImageView.drawable; + if (drawable instanceof AnimatedEmojiDrawable) { + contentType = CONTENT_TYPE_EMOJI; + centerImage.setRoundRadius(0); + } } if (contentType == CONTENT_TYPE_NONE) { return false; @@ -756,6 +960,7 @@ public boolean onInterceptTouchEvent(MotionEvent event, final RecyclerListView l if (openPreviewRunnable == null) { return; } + boolean opened = false; listView.setOnItemClickListener((RecyclerListView.OnItemClickListener) null); listView.requestDisallowInterceptTouchEvent(true); openPreviewRunnable = null; @@ -765,20 +970,60 @@ public boolean onInterceptTouchEvent(MotionEvent event, final RecyclerListView l if (currentPreviewCell instanceof StickerEmojiCell) { StickerEmojiCell stickerEmojiCell = (StickerEmojiCell) currentPreviewCell; open(stickerEmojiCell.getSticker(), stickerEmojiCell.getStickerPath(), stickerEmojiCell.getEmoji(), delegate != null ? delegate.getQuery(false) : null, null, contentTypeFinal, stickerEmojiCell.isRecent(), stickerEmojiCell.getParentObject(), resourcesProvider); + opened = true; stickerEmojiCell.setScaled(true); } else if (currentPreviewCell instanceof StickerCell) { StickerCell stickerCell = (StickerCell) currentPreviewCell; open(stickerCell.getSticker(), null, null, delegate != null ? delegate.getQuery(false) : null, null, contentTypeFinal, false, stickerCell.getParentObject(), resourcesProvider); + opened = true; stickerCell.setScaled(true); clearsInputField = stickerCell.isClearsInputField(); } else if (currentPreviewCell instanceof ContextLinkCell) { ContextLinkCell contextLinkCell = (ContextLinkCell) currentPreviewCell; open(contextLinkCell.getDocument(), null, null, delegate != null ? delegate.getQuery(true) : null, contextLinkCell.getBotInlineResult(), contentTypeFinal, false, contextLinkCell.getBotInlineResult() != null ? contextLinkCell.getInlineBot() : contextLinkCell.getParentObject(), resourcesProvider); + opened = true; if (contentTypeFinal != CONTENT_TYPE_GIF) { contextLinkCell.setScaled(true); } + } else if (currentPreviewCell instanceof EmojiPacksAlert.EmojiImageView) { + EmojiPacksAlert.EmojiImageView imageView = (EmojiPacksAlert.EmojiImageView) currentPreviewCell; + TLRPC.Document document = imageView.getDocument(); + if (document != null) { + open(document, null, MessageObject.findAnimatedEmojiEmoticon(document, null), null, null, contentTypeFinal, false, null, resourcesProvider); + opened = true; + } + } else if (currentPreviewCell instanceof EmojiView.ImageViewEmoji) { + EmojiView.ImageViewEmoji imageView = (EmojiView.ImageViewEmoji) currentPreviewCell; + AnimatedEmojiSpan span = imageView.getSpan(); + TLRPC.Document document = null; + if (span != null) { + document = span.document; + if (document == null) { + document = AnimatedEmojiDrawable.findDocument(currentAccount, span.getDocumentId()); + } + } + if (document != null) { + open(document, null, MessageObject.findAnimatedEmojiEmoticon(document, null), null, null, contentTypeFinal, false, null, resourcesProvider); + opened = true; + } + } else if (currentPreviewCell instanceof SuggestEmojiView.EmojiImageView) { + SuggestEmojiView.EmojiImageView emojiImageView = (SuggestEmojiView.EmojiImageView) currentPreviewCell; + Drawable drawable = emojiImageView.drawable; + TLRPC.Document document = null; + if (drawable instanceof AnimatedEmojiDrawable) { + document = ((AnimatedEmojiDrawable) drawable).getDocument(); + } + if (document != null) { + open(document, null, MessageObject.findAnimatedEmojiEmoticon(document, null), null, null, contentTypeFinal, false, null, resourcesProvider); + opened = true; + } + } + if (opened) { + currentPreviewCell.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + if (delegate != null) { + delegate.resetTouch(); + } } - currentPreviewCell.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); }; AndroidUtilities.runOnUIThread(openPreviewRunnable, 200); return true; @@ -876,7 +1121,8 @@ public void open(TLRPC.Document document, SendMessagesHelper.ImportingSticker st stickerEmojiLayout = null; backgroundDrawable.setColor(Theme.getActiveTheme().isDark() ? 0x71000000 : 0x64E6E6E6); drawEffect = false; - if (contentType == CONTENT_TYPE_STICKER) { + centerImage.setColorFilter(null); + if (contentType == CONTENT_TYPE_STICKER || contentType == CONTENT_TYPE_EMOJI) { if (document == null && sticker == null) { return; } @@ -896,7 +1142,11 @@ public void open(TLRPC.Document document, SendMessagesHelper.ImportingSticker st break; } } - if (newSet != null && (delegate == null || delegate.needMenu())) { + if (contentType == CONTENT_TYPE_EMOJI && emojiPath != null) { + CharSequence emoji = Emoji.replaceEmoji(emojiPath, textPaint.getFontMetricsInt(), AndroidUtilities.dp(24), false); + stickerEmojiLayout = new StaticLayout(emoji, textPaint, AndroidUtilities.dp(100), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); + } + if ((newSet != null || contentType == CONTENT_TYPE_EMOJI) && (delegate == null || delegate.needMenu())) { AndroidUtilities.cancelRunOnUIThread(showSheetRunnable); AndroidUtilities.runOnUIThread(showSheetRunnable, 1300); } @@ -911,6 +1161,9 @@ public void open(TLRPC.Document document, SendMessagesHelper.ImportingSticker st effectImage.setImage(ImageLocation.getForDocument(MessageObject.getPremiumStickerAnimation(document), document), null, null, null, "tgs", currentStickerSet, 1); } } + if (MessageObject.isTextColorEmoji(document)) { + centerImage.setColorFilter(Theme.chat_animatedEmojiTextColorFilter); + } for (int a = 0; a < document.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeSticker) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CountrySelectActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CountrySelectActivity.java index f26e242e137..757160f37b6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CountrySelectActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CountrySelectActivity.java @@ -11,6 +11,7 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; +import android.os.Build; import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.style.ReplacementSpan; @@ -49,11 +50,14 @@ import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; +import java.text.Collator; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Timer; @@ -236,6 +240,7 @@ public void setCountrySelectActivityDelegate(CountrySelectActivityDelegate deleg public static class Country { public String name; + public String defaultName; public String code; public String shortname; @@ -301,10 +306,17 @@ public CountryAdapter(Context context, ArrayList exisitingCountries) { FileLog.e(e); } } - Collections.sort(sortedCountries, String::compareTo); + Comparator comparator; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + Collator collator = Collator.getInstance(LocaleController.getInstance().getCurrentLocale() != null ? LocaleController.getInstance().getCurrentLocale() : Locale.getDefault()); + comparator = collator::compare; + } else { + comparator = String::compareTo; + } + Collections.sort(sortedCountries, comparator); for (ArrayList arr : countries.values()) { - Collections.sort(arr, (country, country2) -> country.name.compareTo(country2.name)); + Collections.sort(arr, (country, country2) -> comparator.compare(country.name, country2.name)); } } @@ -411,7 +423,11 @@ public CountrySearchAdapter(Context context, HashMap> for (List list : countries.values()) { for (Country country : list) { countryList.add(country); - countrySearchMap.put(country, Arrays.asList(country.name.split(" "))); + List keys = new ArrayList<>(Arrays.asList(country.name.split(" "))); + if (country.defaultName != null) { + keys.addAll(Arrays.asList(country.defaultName.split(" "))); + } + countrySearchMap.put(country, keys); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DataSettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DataSettingsActivity.java index 45238714f06..c7ecdfdfc99 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DataSettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DataSettingsActivity.java @@ -13,6 +13,7 @@ import android.content.DialogInterface; import android.content.SharedPreferences; import android.os.Build; +import android.os.Bundle; import android.text.TextUtils; import android.view.Gravity; import android.view.View; @@ -31,7 +32,9 @@ import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; +import org.telegram.messenger.SaveToGallerySettingsHelper; import org.telegram.messenger.SharedConfig; +import org.telegram.messenger.StatsController; import org.telegram.messenger.voip.Instance; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; @@ -43,6 +46,7 @@ import org.telegram.ui.Cells.NotificationsCheckCell; import org.telegram.ui.Cells.RadioColorCell; import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.Cells.TextCell; import org.telegram.ui.Cells.TextCheckCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; @@ -103,6 +107,10 @@ public class DataSettingsActivity extends BaseFragment { private boolean updateVoipUseLessData; + private boolean updateStorageUsageAnimated; + private boolean storageUsageLoading; + private long storageUsageSize; + @Override public boolean onFragmentCreate() { super.onFragmentCreate(); @@ -163,6 +171,61 @@ public boolean onFragmentCreate() { return true; } + private void loadCacheSize() { + final Runnable fireLoading = () -> { + storageUsageLoading = true; + if (listAdapter != null && storageUsageRow >= 0) { + rebind(storageUsageRow); + } + }; + AndroidUtilities.runOnUIThread(fireLoading, 100); + + final long start = System.currentTimeMillis(); + CacheControlActivity.calculateTotalSize(size -> { + AndroidUtilities.cancelRunOnUIThread(fireLoading); + updateStorageUsageAnimated = updateStorageUsageAnimated || (System.currentTimeMillis() - start) > 120; + storageUsageSize = size; + storageUsageLoading = false; + if (listAdapter != null && storageUsageRow >= 0) { + rebind(storageUsageRow); + } + }); + + } + + private void rebind(int position) { + if (listView == null || listAdapter == null) { + return; + } + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + RecyclerView.ViewHolder holder = listView.getChildViewHolder(child); + if (holder != null && holder.getAdapterPosition() == position) { + listAdapter.onBindViewHolder(holder, position); + return; + } + } + } + + private void rebindAll() { + if (listView == null || listAdapter == null) { + return; + } + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + RecyclerView.ViewHolder holder = listView.getChildViewHolder(child); + if (holder != null) { + listAdapter.onBindViewHolder(holder, listView.getChildAdapterPosition(child)); + } + } + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + CacheControlActivity.canceled = true; + } + @Override public View createView(Context context) { actionBar.setBackButtonImage(R.drawable.ic_ab_back); @@ -201,9 +264,15 @@ public void onItemClick(int id) { } else { flag = SharedConfig.SAVE_TO_GALLERY_FLAG_PEER; } - SharedConfig.toggleSaveToGalleryFlag(flag); - TextCheckCell textCheckCell = (TextCheckCell) view; - textCheckCell.setChecked((SharedConfig.saveToGalleryFlags & flag) != 0); + if (LocaleController.isRTL && x <= AndroidUtilities.dp(76) || !LocaleController.isRTL && x >= view.getMeasuredWidth() - AndroidUtilities.dp(76)) { + SaveToGallerySettingsHelper.getSettings(flag).toggle(); + AndroidUtilities.updateVisibleRows(listView); + } else { + Bundle bundle = new Bundle(); + bundle.putInt("type", flag); + presentFragment(new SaveToGallerySettingsActivity(bundle)); + } + } else if (position == mobileRow || position == roamingRow || position == wifiRow) { if (LocaleController.isRTL && x <= AndroidUtilities.dp(76) || !LocaleController.isRTL && x >= view.getMeasuredWidth() - AndroidUtilities.dp(76)) { boolean wasEnabled = listAdapter.isRowEnabled(resetDownloadRow); @@ -365,7 +434,7 @@ public void onItemClick(int id) { setVisibleDialog(dlg); dlg.show(); } else if (position == dataUsageRow) { - presentFragment(new DataUsageActivity()); + presentFragment(new DataUsage2Activity()); } else if (position == storageNumRow) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("StoragePath", R.string.StoragePath)); @@ -461,9 +530,8 @@ protected void onDialogDismiss(Dialog dialog) { @Override public void onResume() { super.onResume(); - if (listAdapter != null) { - listAdapter.notifyDataSetChanged(); - } + loadCacheSize(); + rebindAll(); } private class ListAdapter extends RecyclerListView.SelectionAdapter { @@ -490,14 +558,38 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } break; } + case 6: { + TextCell textCell = (TextCell) holder.itemView; + if (position == storageUsageRow) { + if (storageUsageLoading) { + textCell.setTextAndValueAndColorfulIcon(LocaleController.getString("StorageUsage", R.string.StorageUsage), "", false, R.drawable.msg_filled_storageusage, getThemedColor(Theme.key_color_lightblue), true); + textCell.setDrawLoading(true, 45, updateStorageUsageAnimated); + } else { + textCell.setTextAndValueAndColorfulIcon(LocaleController.getString("StorageUsage", R.string.StorageUsage), storageUsageSize <= 0 ? "" : AndroidUtilities.formatFileSize(storageUsageSize), true, R.drawable.msg_filled_storageusage, getThemedColor(Theme.key_color_lightblue), true); + textCell.setDrawLoading(false, 45, updateStorageUsageAnimated); + } + updateStorageUsageAnimated = false; + } else if (position == dataUsageRow) { + StatsController statsController = StatsController.getInstance(currentAccount); + long size = ( + statsController.getReceivedBytesCount(0, StatsController.TYPE_TOTAL) + + statsController.getReceivedBytesCount(1, StatsController.TYPE_TOTAL) + + statsController.getReceivedBytesCount(2, StatsController.TYPE_TOTAL) + + statsController.getSentBytesCount(0, StatsController.TYPE_TOTAL) + + statsController.getSentBytesCount(1, StatsController.TYPE_TOTAL) + + statsController.getSentBytesCount(2, StatsController.TYPE_TOTAL) + ); + textCell.setTextAndValueAndColorfulIcon(LocaleController.getString("NetworkUsage", R.string.NetworkUsage), AndroidUtilities.formatFileSize(size), true, R.drawable.msg_filled_datausage, getThemedColor(Theme.key_color_green), storageNumRow != -1); + } else if (position == storageNumRow) { + textCell.setTextAndColorfulIcon(LocaleController.getString("StoragePath", R.string.StoragePath), R.drawable.msg_filled_sdcard, getThemedColor(Theme.key_color_yellow), false); + } + break; + } case 1: { TextSettingsCell textCell = (TextSettingsCell) holder.itemView; textCell.setCanDisable(false); textCell.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); - if (position == storageUsageRow) { - textCell.setIcon(R.drawable.msg_storage_usage); - textCell.setText(LocaleController.getString("StorageUsage", R.string.StorageUsage), true); - } else if (position == useLessDataForCallsRow) { + if (position == useLessDataForCallsRow) { textCell.setIcon(0); SharedPreferences preferences = MessagesController.getGlobalMainSettings(); String value = null; @@ -517,12 +609,6 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } textCell.setTextAndValue(LocaleController.getString("VoipUseLessData", R.string.VoipUseLessData), value, updateVoipUseLessData, true); updateVoipUseLessData = false; - } else if (position == dataUsageRow) { - textCell.setIcon(R.drawable.msg_data_usage); - textCell.setText(LocaleController.getString("NetworkUsage", R.string.NetworkUsage), storageNumRow != -1); - } else if (position == storageNumRow) { - textCell.setIcon(R.drawable.msg_storage_path); - textCell.setText(LocaleController.getString("StoragePath", R.string.StoragePath), false); } else if (position == proxyRow) { textCell.setIcon(0); textCell.setText(LocaleController.getString("ProxySettings", R.string.ProxySettings), false); @@ -555,7 +641,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else if (position == autoplayHeaderRow) { headerCell.setText(LocaleController.getString("AutoplayMedia", R.string.AutoplayMedia)); } else if (position == saveToGallerySectionRow) { - headerCell.setText(LocaleController.getString("SaveToGallery", R.string.SaveToGallery)); + headerCell.setText(LocaleController.getString("SaveToGallerySettings", R.string.SaveToGallerySettings)); } break; } @@ -573,12 +659,6 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { checkCell.setTextAndCheck(LocaleController.getString("AutoplayGIF", R.string.AutoplayGIF), SharedConfig.autoplayGifs, true); } else if (position == autoplayVideoRow) { checkCell.setTextAndCheck(LocaleController.getString("AutoplayVideo", R.string.AutoplayVideo), SharedConfig.autoplayVideo, false); - } else if (position == saveToGalleryPeerRow) { - checkCell.setTextAndCheck(LocaleController.getString("SaveToGalleryPrivate", R.string.SaveToGalleryPrivate), (SharedConfig.saveToGalleryFlags & SharedConfig.SAVE_TO_GALLERY_FLAG_PEER) != 0, true); - } else if (position == saveToGalleryGroupsRow) { - checkCell.setTextAndCheck(LocaleController.getString("SaveToGalleryGroups", R.string.SaveToGalleryGroups), (SharedConfig.saveToGalleryFlags & SharedConfig.SAVE_TO_GALLERY_FLAG_GROUP) != 0, true); - } else if (position == saveToGalleryChannelsRow) { - checkCell.setTextAndCheck(LocaleController.getString("SaveToGalleryChannels", R.string.SaveToGalleryChannels), (SharedConfig.saveToGalleryFlags & SharedConfig.SAVE_TO_GALLERY_FLAG_CHANNELS) != 0, false); } break; } @@ -593,10 +673,22 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { NotificationsCheckCell checkCell = (NotificationsCheckCell) holder.itemView; String text; - StringBuilder builder = new StringBuilder(); - DownloadController.Preset preset; + CharSequence description = null; + DownloadController.Preset preset = null; boolean enabled; - if (position == mobileRow) { + if (position == saveToGalleryPeerRow) { + text = LocaleController.getString("SaveToGalleryPrivate", R.string.SaveToGalleryPrivate); + description = SaveToGallerySettingsHelper.user.createDescription(currentAccount); + enabled = SaveToGallerySettingsHelper.user.enabled(); + } else if (position == saveToGalleryGroupsRow) { + text = LocaleController.getString("SaveToGalleryGroups", R.string.SaveToGalleryGroups); + description = SaveToGallerySettingsHelper.groups.createDescription(currentAccount); + enabled = SaveToGallerySettingsHelper.groups.enabled(); + } else if (position == saveToGalleryChannelsRow) { + text = LocaleController.getString("SaveToGalleryChannels", R.string.SaveToGalleryChannels); + description = SaveToGallerySettingsHelper.channels.createDescription(currentAccount); + enabled = SaveToGallerySettingsHelper.channels.enabled(); + } else if (position == mobileRow) { text = LocaleController.getString("WhenUsingMobileData", R.string.WhenUsingMobileData); enabled = DownloadController.getInstance(currentAccount).mobilePreset.enabled; preset = DownloadController.getInstance(currentAccount).getCurrentMobilePreset(); @@ -609,47 +701,55 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { enabled = DownloadController.getInstance(currentAccount).roamingPreset.enabled; preset = DownloadController.getInstance(currentAccount).getCurrentRoamingPreset(); } - - boolean photos = false; - boolean videos = false; - boolean files = false; - int count = 0; - for (int a = 0; a < preset.mask.length; a++) { - if (!photos && (preset.mask[a] & DownloadController.AUTODOWNLOAD_TYPE_PHOTO) != 0) { - photos = true; - count++; - } - if (!videos && (preset.mask[a] & DownloadController.AUTODOWNLOAD_TYPE_VIDEO) != 0) { - videos = true; - count++; - } - if (!files && (preset.mask[a] & DownloadController.AUTODOWNLOAD_TYPE_DOCUMENT) != 0) { - files = true; - count++; - } - } - if (preset.enabled && count != 0) { - if (photos) { - builder.append(LocaleController.getString("AutoDownloadPhotosOn", R.string.AutoDownloadPhotosOn)); - } - if (videos) { - if (builder.length() > 0) { - builder.append(", "); + boolean checked; + if (preset != null) { + StringBuilder builder = new StringBuilder(); + boolean photos = false; + boolean videos = false; + boolean files = false; + int count = 0; + for (int a = 0; a < preset.mask.length; a++) { + if (!photos && (preset.mask[a] & DownloadController.AUTODOWNLOAD_TYPE_PHOTO) != 0) { + photos = true; + count++; + } + if (!videos && (preset.mask[a] & DownloadController.AUTODOWNLOAD_TYPE_VIDEO) != 0) { + videos = true; + count++; + } + if (!files && (preset.mask[a] & DownloadController.AUTODOWNLOAD_TYPE_DOCUMENT) != 0) { + files = true; + count++; } - builder.append(LocaleController.getString("AutoDownloadVideosOn", R.string.AutoDownloadVideosOn)); - builder.append(String.format(" (%1$s)", AndroidUtilities.formatFileSize(preset.sizes[DownloadController.typeToIndex(DownloadController.AUTODOWNLOAD_TYPE_VIDEO)], true))); } - if (files) { - if (builder.length() > 0) { - builder.append(", "); + if (preset.enabled && count != 0) { + if (photos) { + builder.append(LocaleController.getString("AutoDownloadPhotosOn", R.string.AutoDownloadPhotosOn)); } - builder.append(LocaleController.getString("AutoDownloadFilesOn", R.string.AutoDownloadFilesOn)); - builder.append(String.format(" (%1$s)", AndroidUtilities.formatFileSize(preset.sizes[DownloadController.typeToIndex(DownloadController.AUTODOWNLOAD_TYPE_DOCUMENT)], true))); + if (videos) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append(LocaleController.getString("AutoDownloadVideosOn", R.string.AutoDownloadVideosOn)); + builder.append(String.format(" (%1$s)", AndroidUtilities.formatFileSize(preset.sizes[DownloadController.typeToIndex(DownloadController.AUTODOWNLOAD_TYPE_VIDEO)], true))); + } + if (files) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append(LocaleController.getString("AutoDownloadFilesOn", R.string.AutoDownloadFilesOn)); + builder.append(String.format(" (%1$s)", AndroidUtilities.formatFileSize(preset.sizes[DownloadController.typeToIndex(DownloadController.AUTODOWNLOAD_TYPE_DOCUMENT)], true))); + } + } else { + builder.append(LocaleController.getString("NoMediaAutoDownload", R.string.NoMediaAutoDownload)); } + checked = (photos || videos || files) && enabled; + description = builder; } else { - builder.append(LocaleController.getString("NoMediaAutoDownload", R.string.NoMediaAutoDownload)); + checked = enabled; } - checkCell.setTextAndValueAndCheck(text, builder, (photos || videos || files) && enabled, 0, true, true); + checkCell.setAnimationsEnabled(true); + checkCell.setTextAndValueAndCheck(text, description, checked, 0, true, true); break; } } @@ -706,7 +806,7 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; case 2: - view = new HeaderCell(mContext); + view = new HeaderCell(mContext, 22); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; case 3: @@ -718,10 +818,14 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType view.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); break; case 5: - default: view = new NotificationsCheckCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; + case 6: + default: + view = new TextCell(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); @@ -733,12 +837,14 @@ public int getItemViewType(int position) { return 0; } else if (position == mediaDownloadSectionRow || position == streamSectionRow || position == callsSectionRow || position == usageSectionRow || position == proxySectionRow || position == autoplayHeaderRow || position == saveToGallerySectionRow) { return 2; - } else if (position == enableCacheStreamRow || position == enableStreamRow || position == enableAllStreamRow || position == enableMkvRow || position == autoplayGifsRow || position == autoplayVideoRow || position == saveToGalleryGroupsRow || position == saveToGalleryPeerRow || position == saveToGalleryChannelsRow) { + } else if (position == enableCacheStreamRow || position == enableStreamRow || position == enableAllStreamRow || position == enableMkvRow || position == autoplayGifsRow || position == autoplayVideoRow) { return 3; } else if (position == enableAllStreamInfoRow) { return 4; - } else if (position == mobileRow || position == wifiRow || position == roamingRow) { + } else if (position == mobileRow || position == wifiRow || position == roamingRow || position == saveToGalleryGroupsRow || position == saveToGalleryPeerRow || position == saveToGalleryChannelsRow) { return 5; + } else if (position == storageUsageRow || position == dataUsageRow || position == storageNumRow) { + return 6; } else { return 1; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DataUsage2Activity.java b/TMessagesProj/src/main/java/org/telegram/ui/DataUsage2Activity.java new file mode 100644 index 00000000000..85ae7afdccd --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/DataUsage2Activity.java @@ -0,0 +1,1108 @@ +package org.telegram.ui; + +import static org.telegram.messenger.AndroidUtilities.dp; + +import android.content.Context; +import android.content.DialogInterface; +import android.content.res.Configuration; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextPaint; +import android.text.TextUtils; +import android.text.style.DynamicDrawableSpan; +import android.text.style.ImageSpan; +import android.text.style.MetricAffectingSpan; +import android.text.style.RelativeSizeSpan; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.StatsController; +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.Cells.HeaderCell; +import org.telegram.ui.Cells.TextCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.Components.CacheChart; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.ListView.AdapterWithDiffUtils; +import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.TypefaceSpan; +import org.telegram.ui.Components.ViewPagerFixed; + +import java.util.ArrayList; +import java.util.Arrays; + +public class DataUsage2Activity extends BaseFragment { + + private Theme.ResourcesProvider resourcesProvider; + + public DataUsage2Activity() { + this(null); + } + + public DataUsage2Activity(Theme.ResourcesProvider resourcesProvider) { + super(); + this.resourcesProvider = resourcesProvider; + } + + private ViewPagerFixed pager; + private ViewPagerFixed.Adapter pageAdapter; + private ViewPagerFixed.TabsView tabsView; + + @Override + public View createView(Context context) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setTitle(LocaleController.getString("NetworkUsage", R.string.NetworkUsage)); + actionBar.setBackgroundColor(getThemedColor(Theme.key_actionBarActionModeDefault)); + actionBar.setTitleColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); + actionBar.setItemsColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText), false); + actionBar.setItemsBackgroundColor(getThemedColor(Theme.key_listSelector), false); + actionBar.setCastShadows(false); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } + } + }); + + FrameLayout frameLayout = new FrameLayout(context) { + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY)); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (getParentLayout() != null && tabsView != null) { + float y = tabsView.getMeasuredHeight(); + canvas.drawLine(0, y, getWidth(), y, Theme.dividerPaint); + } + } + }; + frameLayout.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + + pager = new ViewPagerFixed(context); + pager.setAdapter(pageAdapter = new PageAdapter()); + + tabsView = pager.createTabsView(true, 8); + tabsView.setBackgroundColor(getThemedColor(Theme.key_actionBarActionModeDefault)); + frameLayout.addView(tabsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP | Gravity.FILL_HORIZONTAL)); + + frameLayout.addView(pager, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, 48, 0, 0)); + + return fragmentView = frameLayout; + } + + @Override + public Theme.ResourcesProvider getResourceProvider() { + return resourcesProvider; + } + + private class PageAdapter extends ViewPagerFixed.Adapter { + + @Override + public int getItemCount() { + return 4; + } + + @Override + public View createView(int viewType) { + return new ListView(getContext()); + } + + @Override + public void bindView(View view, int position, int viewType) { + ((ListView) view).setType(position); + ((ListView) view).scrollToPosition(0); + } + + @Override + public String getItemTitle(int position) { + switch (position) { + case ListView.TYPE_ALL: return LocaleController.getString("NetworkUsageAllTab", R.string.NetworkUsageAllTab); + case ListView.TYPE_MOBILE: return LocaleController.getString("NetworkUsageMobileTab", R.string.NetworkUsageMobileTab); + case ListView.TYPE_WIFI: return LocaleController.getString("NetworkUsageWiFiTab", R.string.NetworkUsageWiFiTab); + case ListView.TYPE_ROAMING: return LocaleController.getString("NetworkUsageRoamingTab", R.string.NetworkUsageRoamingTab); + default: return ""; + } + } + } + + private static String[] colors = { + Theme.key_statisticChartLine_blue, + Theme.key_statisticChartLine_green, + Theme.key_statisticChartLine_lightblue, + Theme.key_statisticChartLine_golden, + Theme.key_statisticChartLine_red, + Theme.key_statisticChartLine_purple, + Theme.key_statisticChartLine_cyan + }; + + private static int[] particles = { + R.drawable.msg_filled_data_videos, + R.drawable.msg_filled_data_files, + R.drawable.msg_filled_data_photos, + R.drawable.msg_filled_data_messages, + R.drawable.msg_filled_data_music, + R.drawable.msg_filled_data_voice, + R.drawable.msg_filled_data_calls + }; + + private static int[] titles = { + R.string.LocalVideoCache, + R.string.LocalDocumentCache, + R.string.LocalPhotoCache, + R.string.MessagesSettings, + R.string.LocalMusicCache, + R.string.LocalAudioCache, + R.string.CallsDataUsage + }; + + private static int[] stats = { + StatsController.TYPE_VIDEOS, + StatsController.TYPE_FILES, + StatsController.TYPE_PHOTOS, + StatsController.TYPE_MESSAGES, + StatsController.TYPE_MUSIC, + StatsController.TYPE_AUDIOS, + StatsController.TYPE_CALLS, + }; + + + class ListView extends RecyclerListView { + + public static final int TYPE_ALL = 0; + public static final int TYPE_MOBILE = 1; + public static final int TYPE_WIFI = 2; + public static final int TYPE_ROAMING = 3; + + private boolean animateChart = false; + + int currentType = TYPE_ALL; + + LinearLayoutManager layoutManager; + Adapter adapter; + + public ListView(Context context) { + super(context); + setLayoutManager(layoutManager = new LinearLayoutManager(context)); + setAdapter(adapter = new Adapter()); + setOnItemClickListener((view, position) -> { + if (view instanceof Cell && position >= 0 && position < itemInners.size()) { + ItemInner item = itemInners.get(position); + if (item != null) { + if (item.index >= 0) { + collapsed[item.index] = !collapsed[item.index]; + updateRows(true); + } else if (item.index == -2) { + presentFragment(new DataAutoDownloadActivity(currentType - 1)); + } + } + } else if (view instanceof TextCell) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("ResetStatisticsAlertTitle", R.string.ResetStatisticsAlertTitle)); + builder.setMessage(LocaleController.getString("ResetStatisticsAlert", R.string.ResetStatisticsAlert)); + builder.setPositiveButton(LocaleController.getString("Reset", R.string.Reset), (dialogInterface, j) -> { + removedSegments.clear(); + for (int i = 0; i < segments.length; ++i) { + long size = segments[i].size; + if (size > 0) { + removedSegments.add(segments[i].index); + } + } + + StatsController.getInstance(currentAccount).resetStats(0); + StatsController.getInstance(currentAccount).resetStats(1); + StatsController.getInstance(currentAccount).resetStats(2); + + animateChart = true; + setup(); + updateRows(true); + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + AlertDialog dialog = builder.create(); + showDialog(dialog); + TextView button = (TextView) dialog.getButton(DialogInterface.BUTTON_POSITIVE); + if (button != null) { + button.setTextColor(Theme.getColor(Theme.key_dialogTextRed2)); + } + } + }); + + DefaultItemAnimator itemAnimator = new DefaultItemAnimator(); + itemAnimator.setDurations(220); + itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + itemAnimator.setDelayAnimations(false); + itemAnimator.setSupportsChangeAnimations(false); + setItemAnimator(itemAnimator); + } + + public void setType(int type) { + this.currentType = type; + + removedSegments.clear(); + empty = getBytesCount(StatsController.TYPE_TOTAL) <= 0; + setup(); + updateRows(false); + } + + private void setup() { + totalSize = getBytesCount(StatsController.TYPE_TOTAL); + totalSizeIn = getReceivedBytesCount(StatsController.TYPE_TOTAL); + totalSizeOut = getSentBytesCount(StatsController.TYPE_TOTAL); + if (segments == null) { + segments = new Size[7]; + } + if (chartSegments == null) { + chartSegments = new Size[7]; + } + for (int i = 0; i < stats.length; ++i) { + long size = getBytesCount(stats[i]); + chartSegments[i] = segments[i] = new Size( + i, + size, + getReceivedBytesCount(stats[i]), + getSentBytesCount(stats[i]), + getReceivedItemsCount(stats[i]), + getSentItemsCount(stats[i]) + ); + tempSizes[i] = size / (float) totalSize; + } + Arrays.sort(segments, (a, b) -> Long.compare(b.size, a.size)); + AndroidUtilities.roundPercents(tempSizes, tempPercents); + Arrays.fill(collapsed, true); + } + + private ArrayList oldItems = new ArrayList<>(); + private ArrayList itemInners = new ArrayList<>(); + + private float[] tempSizes = new float[7]; + private int[] tempPercents = new int[7]; + + private ArrayList removedSegments = new ArrayList<>(); + private Size[] segments, chartSegments; + private boolean[] collapsed = new boolean[7]; + private long totalSize, totalSizeIn, totalSizeOut; + private boolean empty; + + private CacheChart chart; + + private String formatPercent(int percent) { + return percent <= 0 ? String.format("<%d%%", 1) : String.format("%d%%", percent); + } + + class Size extends CacheChart.SegmentSize { + + int index; + long inSize, outSize; + int inCount, outCount; + + public Size(int index, long size, long inSize, long outSize, int inCount, int outCount) { + this.index = index; + + this.size = size; + this.selected = true; + + this.inSize = inSize; + this.inCount = inCount; + this.outSize = outSize; + this.outCount = outCount; + } + } + + private void updateRows(boolean animated) { + oldItems.clear(); + oldItems.addAll(itemInners); + + itemInners.clear(); + + itemInners.add(new ItemInner(VIEW_TYPE_CHART)); + final String sinceText = totalSize > 0 ? + LocaleController.formatString("YourNetworkUsageSince", R.string.YourNetworkUsageSince, LocaleController.getInstance().formatterStats.format(getResetStatsDate())) : + LocaleController.formatString("NoNetworkUsageSince", R.string.NoNetworkUsageSince, LocaleController.getInstance().formatterStats.format(getResetStatsDate())); + itemInners.add(ItemInner.asSubtitle(sinceText)); + + ArrayList sections = new ArrayList<>(); + for (int i = 0; i < segments.length; ++i) { + long size = segments[i].size; + int index = segments[i].index; + boolean emptyButShown = empty || removedSegments.contains(index); + if (size <= 0 && !emptyButShown) { + continue; + } + SpannableString percent = new SpannableString(formatPercent(tempPercents[index])); + percent.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), 0, percent.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + percent.setSpan(new RelativeSizeSpan(.8f), 0, percent.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + percent.setSpan(new CustomCharacterSpan(.1), 0, percent.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + sections.add(ItemInner.asCell( + i, + particles[index], + getThemedColor(colors[index]), + size == 0 ? + LocaleController.getString(titles[index]) : + TextUtils.concat(LocaleController.getString(titles[index]), " ", percent), + AndroidUtilities.formatFileSize(size) + )); + } + + if (!sections.isEmpty()) { + + SpannableString sentIcon = new SpannableString("^"); + Drawable sentIconDrawable = getContext().getResources().getDrawable(R.drawable.msg_mini_upload).mutate(); + sentIconDrawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_windowBackgroundWhiteBlackText), PorterDuff.Mode.MULTIPLY)); + sentIconDrawable.setBounds(0, AndroidUtilities.dp(2), AndroidUtilities.dp(16), AndroidUtilities.dp(2 + 16)); + sentIcon.setSpan(new ImageSpan(sentIconDrawable, DynamicDrawableSpan.ALIGN_CENTER), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + SpannableString receivedIcon = new SpannableString("v"); + Drawable receivedIconDrawable = getContext().getResources().getDrawable(R.drawable.msg_mini_download).mutate(); + receivedIconDrawable.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_windowBackgroundWhiteBlackText), PorterDuff.Mode.MULTIPLY)); + receivedIconDrawable.setBounds(0, AndroidUtilities.dp(2), AndroidUtilities.dp(16), AndroidUtilities.dp(2 + 16)); + receivedIcon.setSpan(new ImageSpan(receivedIconDrawable, DynamicDrawableSpan.ALIGN_CENTER), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + for (int i = 0; i < sections.size(); ++i) { + int index = sections.get(i).index; + if (index >= 0 && !collapsed[index]) { + Size size = segments[index]; + if (stats[size.index] == StatsController.TYPE_CALLS) { + if (size.outSize > 0 || size.outCount > 0) { + sections.add(++i, ItemInner.asCell( + -1, 0, 0, + LocaleController.formatPluralStringComma("OutgoingCallsCount", size.outCount), + AndroidUtilities.formatFileSize(size.outSize) + )); + } + if (size.inSize > 0 || size.inCount > 0) { + sections.add(++i, ItemInner.asCell( + -1, 0, 0, + LocaleController.formatPluralStringComma("IncomingCallsCount", size.inCount), + AndroidUtilities.formatFileSize(size.inSize) + )); + } + } else if (stats[size.index] != StatsController.TYPE_MESSAGES) { + if (size.outSize > 0 || size.outCount > 0) { + sections.add(++i, ItemInner.asCell( + -1, 0, 0, + TextUtils.concat(sentIcon, " ", AndroidUtilities.replaceTags(LocaleController.formatPluralStringComma("FilesSentCount", size.outCount))), + AndroidUtilities.formatFileSize(size.outSize) + )); + } + if (size.inSize > 0 || size.inCount > 0) { + sections.add(++i, ItemInner.asCell( + -1, 0, 0, + TextUtils.concat(receivedIcon, " ", AndroidUtilities.replaceTags(LocaleController.formatPluralStringComma("FilesReceivedCount", size.inCount))), + AndroidUtilities.formatFileSize(size.inSize) + )); + } + } else { + if (size.outSize > 0 || size.outCount > 0) { + sections.add(++i, ItemInner.asCell( + -1, 0, 0, + TextUtils.concat(sentIcon, " ", LocaleController.getString("BytesSent", R.string.BytesSent)), + AndroidUtilities.formatFileSize(size.outSize) + )); + } + if (size.inSize > 0 || size.inCount > 0) { + sections.add(++i, ItemInner.asCell( + -1, 0, 0, + TextUtils.concat(receivedIcon, " ", LocaleController.getString("BytesReceived", R.string.BytesReceived)), + AndroidUtilities.formatFileSize(size.inSize) + )); + } + } + } + } +// itemInners.add(new ItemInner(VIEW_TYPE_ROUNDING)); + itemInners.addAll(sections); +// itemInners.add(new ItemInner(VIEW_TYPE_END)); + if (!empty) { + itemInners.add(ItemInner.asSeparator(LocaleController.getString("DataUsageSectionsInfo", R.string.DataUsageSectionsInfo))); + } + } + + if (!empty) { + itemInners.add(ItemInner.asHeader(LocaleController.getString("TotalNetworkUsage", R.string.TotalNetworkUsage))); + itemInners.add(ItemInner.asCell( + -1, + R.drawable.msg_filled_data_sent, + getThemedColor(Theme.key_statisticChartLine_lightblue), + LocaleController.getString("BytesSent", R.string.BytesSent), + AndroidUtilities.formatFileSize(totalSizeOut) + )); + itemInners.add(ItemInner.asCell( + -1, + R.drawable.msg_filled_data_received, + getThemedColor(Theme.key_statisticChartLine_green), + LocaleController.getString("BytesReceived", R.string.BytesReceived), + AndroidUtilities.formatFileSize(totalSizeIn) + )); + } + + if (!sections.isEmpty()) { + itemInners.add(ItemInner.asSeparator(sinceText)); + } + + if (currentType != TYPE_ALL) { + if (sections.isEmpty()) { + itemInners.add(ItemInner.asSeparator()); + } + itemInners.add(ItemInner.asCell( + -2, + R.drawable.msg_download_settings, + getThemedColor(Theme.key_statisticChartLine_lightblue), + LocaleController.getString("AutomaticDownloadSettings", R.string.AutomaticDownloadSettings), + null + )); + String info; + switch (currentType) { + case TYPE_MOBILE: + info = LocaleController.getString("AutomaticDownloadSettingsInfoMobile", R.string.AutomaticDownloadSettingsInfoMobile); + break; + case TYPE_ROAMING: + info = LocaleController.getString("AutomaticDownloadSettingsInfoRoaming", R.string.AutomaticDownloadSettingsInfoRoaming); + break; + default: + case TYPE_WIFI: + info = LocaleController.getString("AutomaticDownloadSettingsInfoWiFi", R.string.AutomaticDownloadSettingsInfoWiFi); + break; + } + itemInners.add(ItemInner.asSeparator(info)); + } + + if (!sections.isEmpty()) { + itemInners.add(new ItemInner(VIEW_TYPE_RESET_BUTTON, LocaleController.getString("ResetStatistics", R.string.ResetStatistics))); + } + itemInners.add(ItemInner.asSeparator()); + + if (adapter != null) { + if (animated) { + adapter.setItems(oldItems, itemInners); + } else { + adapter.notifyDataSetChanged(); + } + } + } + + private CharSequence bold(CharSequence text) { + SpannableString string = new SpannableString(text); + string.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), 0, string.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + return string; + } + + private class Adapter extends AdapterWithDiffUtils { + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view; + switch (viewType) { + case VIEW_TYPE_CHART: + chart = new CacheChart(getContext(), colors.length, colors, CacheChart.TYPE_NETWORK, particles) { + + @Override + protected int heightDp() { + return 216; + } + + @Override + protected int padInsideDp() { + return 10; + } + + @Override + protected void onSectionDown(int index, boolean down) { + if (!down) { + ListView.this.removeHighlightRow(); + return; + } + if (index < 0 || index >= segments.length) { + return; + } + int pos = -1; + for (int i = 0; i < segments.length; ++i) { + if (segments[i].index == index) { + pos = i; + break; + } + } + int position = -1; + for (int i = 0; i < itemInners.size(); ++i) { + ItemInner item2 = itemInners.get(i); + if (item2 != null && item2.viewType == VIEW_TYPE_SECTION && item2.index == pos) { + position = i; + break; + } + } + + if (position >= 0) { + final int finalPosition = position; + ListView.this.highlightRow(() -> finalPosition, 0); + } else { + ListView.this.removeHighlightRow(); + } + } + }; + chart.setInterceptTouch(false); + view = chart; + break; + case VIEW_TYPE_SUBTITLE: + view = new SubtitleCell(getContext()); + break; + case VIEW_TYPE_SEPARATOR: + view = new TextInfoPrivacyCell(getContext()); + break; + case VIEW_TYPE_HEADER: + view = new HeaderCell(getContext()); + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_RESET_BUTTON: + TextCell textCell = new TextCell(getContext()); + textCell.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteRedText5)); + textCell.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + view = textCell; + break; + case VIEW_TYPE_END: + view = new View(getContext()) { + { setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(4), MeasureSpec.EXACTLY)); + } + }; + break; + case VIEW_TYPE_ROUNDING: + view = new RoundingCell(getContext()); + break; + case VIEW_TYPE_SECTION: + default: + view = new Cell(getContext()); + break; + } + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + ItemInner item = itemInners.get(holder.getAdapterPosition()); + int viewType = holder.getItemViewType(); + if (viewType == VIEW_TYPE_CHART) { + CacheChart chart = (CacheChart) holder.itemView; + if (segments != null) { + chart.setSegments(totalSize, animateChart, chartSegments); + } + animateChart = false; + } else if (viewType == VIEW_TYPE_SUBTITLE) { + SubtitleCell subtitleCell = (SubtitleCell) holder.itemView; + subtitleCell.setText(item.text); + int bottomViewType; + boolean bottom = position + 1 < itemInners.size() && (bottomViewType = itemInners.get(position + 1).viewType) != item.viewType && bottomViewType != VIEW_TYPE_SEPARATOR && bottomViewType != VIEW_TYPE_ROUNDING; + if (bottom) { + subtitleCell.setBackground(Theme.getThemedDrawable(getContext(), R.drawable.greydivider_top, Theme.key_windowBackgroundGrayShadow)); + } else { + subtitleCell.setBackground(null); + } + } else if (viewType == VIEW_TYPE_SECTION) { + Cell cell = (Cell) holder.itemView; + cell.set(item.imageColor, item.imageResId, item.text, item.valueText, position + 1 < getItemCount() && itemInners.get(position + 1).viewType == viewType); + cell.setArrow(item.pad || item.index < 0 || item.index < segments.length && segments[item.index].size <= 0 ? null : collapsed[item.index]); + } else if (viewType == VIEW_TYPE_SEPARATOR) { + TextInfoPrivacyCell view = (TextInfoPrivacyCell) holder.itemView; + boolean top = position > 0 && item.viewType != itemInners.get(position - 1).viewType; + boolean bottom = position + 1 < itemInners.size() && itemInners.get(position + 1).viewType != item.viewType; + if (top && bottom) { + view.setBackground(Theme.getThemedDrawable(getContext(), R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); + } else if (top) { + view.setBackground(Theme.getThemedDrawable(getContext(), R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + } else if (bottom) { + view.setBackground(Theme.getThemedDrawable(getContext(), R.drawable.greydivider_top, Theme.key_windowBackgroundGrayShadow)); + } else { + view.setBackground(null); + } + view.setText(item.text); + } else if (viewType == VIEW_TYPE_HEADER) { + HeaderCell header = (HeaderCell) holder.itemView; + header.setText(item.text); + } else if (viewType == VIEW_TYPE_RESET_BUTTON) { + TextCell textCell = (TextCell) holder.itemView; + textCell.setText(item.text.toString(), false); + } else if (viewType == VIEW_TYPE_ROUNDING) { + ((RoundingCell) holder.itemView).setTop(true); + } + } + + @Override + public int getItemCount() { + return itemInners.size(); + } + + @Override + public int getItemViewType(int position) { + return itemInners.get(position).viewType; + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + ItemInner item = itemInners.get(holder.getAdapterPosition()); + return item.viewType == VIEW_TYPE_RESET_BUTTON || item.viewType == VIEW_TYPE_SECTION && item.index != -1; + } + } + + private int getSentItemsCount(int dataType) { + switch (currentType) { + case TYPE_MOBILE: + case TYPE_WIFI: + case TYPE_ROAMING: + return StatsController.getInstance(currentAccount).getSentItemsCount(currentType - 1, dataType); + case TYPE_ALL: + default: + return ( + StatsController.getInstance(currentAccount).getSentItemsCount(0, dataType) + + StatsController.getInstance(currentAccount).getSentItemsCount(1, dataType) + + StatsController.getInstance(currentAccount).getSentItemsCount(2, dataType) + ); + } + } + + private int getReceivedItemsCount(int dataType) { + switch (currentType) { + case TYPE_MOBILE: + case TYPE_WIFI: + case TYPE_ROAMING: + return StatsController.getInstance(currentAccount).getRecivedItemsCount(currentType - 1, dataType); + case TYPE_ALL: + default: + return ( + StatsController.getInstance(currentAccount).getRecivedItemsCount(0, dataType) + + StatsController.getInstance(currentAccount).getRecivedItemsCount(1, dataType) + + StatsController.getInstance(currentAccount).getRecivedItemsCount(2, dataType) + ); + } + } + + private long getBytesCount(int dataType) { + return getSentBytesCount(dataType) + getReceivedBytesCount(dataType); + } + + private long getSentBytesCount(int dataType) { + switch (currentType) { + case TYPE_MOBILE: + case TYPE_WIFI: + case TYPE_ROAMING: + return StatsController.getInstance(currentAccount).getSentBytesCount(currentType - 1, dataType); + case TYPE_ALL: + default: + return ( + StatsController.getInstance(currentAccount).getSentBytesCount(0, dataType) + + StatsController.getInstance(currentAccount).getSentBytesCount(1, dataType) + + StatsController.getInstance(currentAccount).getSentBytesCount(2, dataType) + ); + } + } + + private long getReceivedBytesCount(int dataType) { + switch (currentType) { + case TYPE_MOBILE: + case TYPE_WIFI: + case TYPE_ROAMING: + return StatsController.getInstance(currentAccount).getReceivedBytesCount(currentType - 1, dataType); + case TYPE_ALL: + default: + return ( + StatsController.getInstance(currentAccount).getReceivedBytesCount(0, dataType) + + StatsController.getInstance(currentAccount).getReceivedBytesCount(1, dataType) + + StatsController.getInstance(currentAccount).getReceivedBytesCount(2, dataType) + ); + } + } + + private long getResetStatsDate() { + switch (currentType) { + case TYPE_MOBILE: + case TYPE_WIFI: + case TYPE_ROAMING: + return StatsController.getInstance(currentAccount).getResetStatsDate(currentType - 1); + case TYPE_ALL: + default: + return min( + StatsController.getInstance(currentAccount).getResetStatsDate(0), + StatsController.getInstance(currentAccount).getResetStatsDate(1), + StatsController.getInstance(currentAccount).getResetStatsDate(2) + ); + } + } + + private long min(long... numbers) { + long min = Long.MAX_VALUE; + for (int i = 0; i < numbers.length; ++i) { + if (min > numbers[i]) + min = numbers[i]; + } + return min; + } + + @Override + protected void onMeasure(int widthSpec, int heightSpec) { + super.onMeasure(widthSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightSpec), MeasureSpec.EXACTLY)); + } + } + + private static final int VIEW_TYPE_CHART = 0; + private static final int VIEW_TYPE_SUBTITLE = 1; + private static final int VIEW_TYPE_SECTION = 2; + private static final int VIEW_TYPE_SEPARATOR = 3; + private static final int VIEW_TYPE_HEADER = 4; + private static final int VIEW_TYPE_RESET_BUTTON = 5; + private static final int VIEW_TYPE_ROUNDING = 6; + private static final int VIEW_TYPE_END = 7; + + private static class ItemInner extends AdapterWithDiffUtils.Item { + + public int imageResId; + public int imageColor; + public CharSequence text; + public CharSequence valueText; + + public int index; + public boolean pad; + + public int key; + + public ItemInner(int viewType) { + super(viewType, false); + } + + public ItemInner(int viewType, int key) { + super(viewType, false); + this.key = key; + } + + private ItemInner(int viewType, CharSequence text) { + super(viewType, false); + this.text = text; + } + + private ItemInner(int viewType, CharSequence text, CharSequence valueText) { + super(viewType, false); + this.text = text; + this.valueText = valueText; + } + + private ItemInner(int viewType, int index, CharSequence text, CharSequence valueText) { + super(viewType, false); + this.index = index; + this.text = text; + this.valueText = valueText; + } + + private ItemInner(int viewType, int index, int imageResId, int imageColor, CharSequence text, CharSequence valueText) { + super(viewType, false); + this.index = index; + this.imageResId = imageResId; + this.imageColor = imageColor; + this.text = text; + this.valueText = valueText; + } + + public static ItemInner asSeparator() { + return new ItemInner(VIEW_TYPE_SEPARATOR); + } + + public static ItemInner asSeparator(String hint) { + return new ItemInner(VIEW_TYPE_SEPARATOR, hint); + } + + public static ItemInner asHeader(String text) { + return new ItemInner(VIEW_TYPE_HEADER, text); + } + + public static ItemInner asSubtitle(String text) { + return new ItemInner(VIEW_TYPE_SUBTITLE, text); + } + + public static ItemInner asCell(int index, int imageResId, int imageColor, CharSequence text, CharSequence valueText) { + return new ItemInner(VIEW_TYPE_SECTION, index, imageResId, imageColor, text, valueText); + } + + public static ItemInner asCell(String text, CharSequence valueText) { + return new ItemInner(VIEW_TYPE_SECTION, text, valueText); + } + + @Override + public boolean equals(Object object) { + if (!(object instanceof ItemInner)) { + return false; + } + ItemInner item = (ItemInner) object; + if (item.viewType != viewType) { + return false; + } + if (viewType == VIEW_TYPE_SUBTITLE || viewType == VIEW_TYPE_HEADER || viewType == VIEW_TYPE_SEPARATOR || viewType == VIEW_TYPE_RESET_BUTTON) { + return TextUtils.equals(text, item.text); + } + if (viewType == VIEW_TYPE_SECTION) { + return item.index == index && TextUtils.equals(text, item.text) && item.imageColor == imageColor && item.imageResId == imageResId; + } + return item.key == key; + } + } + + class SubtitleCell extends FrameLayout { + + TextView textView; + + public SubtitleCell(Context context) { + super(context); + + textView = new TextView(context); + textView.setGravity(Gravity.CENTER); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + textView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteGrayText)); + + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.FILL, 24, 0, 24, 14)); + } + + public void setText(CharSequence text) { + textView.setText(text); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), heightMeasureSpec); + } + } + + public static class RoundingCell extends View { + Path path = new Path(); + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + + public RoundingCell(Context context) { + super(context); + paint.setShadowLayer(dp(1), 0, dp(-0.66f), 0x0f000000); + paint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + } + + private boolean top = true; + + public void setTop(boolean top) { + path.rewind(); + float r; + if (this.top = top) { + r = AndroidUtilities.dp(14); + AndroidUtilities.rectTmp.set(0, AndroidUtilities.dp(4), getMeasuredWidth(), AndroidUtilities.dp(4) + getMeasuredHeight() * 2); + path.addRoundRect(AndroidUtilities.rectTmp, r, r, Path.Direction.CW); + } else { + r = AndroidUtilities.dp(8); + AndroidUtilities.rectTmp.set(0, -getMeasuredHeight() * 2 - AndroidUtilities.dp(4), getMeasuredWidth(), getMeasuredHeight() - AndroidUtilities.dp(4)); + path.addRoundRect(AndroidUtilities.rectTmp, r, r, Path.Direction.CW); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + canvas.drawPath(path, paint); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(13), MeasureSpec.EXACTLY)); + setTop(this.top); + } + + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + requestLayout(); + } + } + + class Cell extends FrameLayout { + + ImageView imageView; + LinearLayout linearLayout, linearLayout2; + TextView textView; + ImageView arrowView; + TextView valueTextView; + boolean divider; + + public Cell(Context context) { + super(context); + + setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.CENTER); +// imageView.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY)); + addView(imageView, LayoutHelper.createFrame(28, 28, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 18, 0, 18, 0)); + + linearLayout = new LinearLayout(context); + linearLayout.setOrientation(LinearLayout.HORIZONTAL); + linearLayout.setWeightSum(2); + addView(linearLayout, LayoutHelper.createFrameRelatively(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 64, 0, 20, 0)); + + linearLayout2 = new LinearLayout(context); + linearLayout2.setOrientation(LinearLayout.HORIZONTAL); + if (LocaleController.isRTL) { + linearLayout2.setGravity(Gravity.RIGHT); + } + linearLayout2.setWeightSum(2); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + textView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlackText)); + textView.setEllipsize(TextUtils.TruncateAt.END); + textView.setSingleLine(); + textView.setLines(1); + + arrowView = new ImageView(context); + arrowView.setScaleType(ImageView.ScaleType.FIT_CENTER); + arrowView.setImageResource(R.drawable.arrow_more); + arrowView.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_windowBackgroundWhiteBlackText), PorterDuff.Mode.MULTIPLY)); + arrowView.setTranslationY(AndroidUtilities.dp(1)); + arrowView.setVisibility(View.GONE); + + if (LocaleController.isRTL) { + linearLayout2.addView(arrowView, LayoutHelper.createLinear(16, 16, Gravity.CENTER_VERTICAL | Gravity.RIGHT, 3, 0, 0, 0)); + linearLayout2.addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.RIGHT)); + } else { + linearLayout2.addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); + linearLayout2.addView(arrowView, LayoutHelper.createLinear(16, 16, Gravity.CENTER_VERTICAL, 3, 0, 0, 0)); + } + + valueTextView = new TextView(context); + valueTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + valueTextView.setTextColor(getThemedColor(Theme.key_windowBackgroundWhiteBlueText2)); + valueTextView.setGravity(LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT); + + if (LocaleController.isRTL) { + linearLayout.addView(valueTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.LEFT)); + linearLayout.addView(linearLayout2, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 2, Gravity.CENTER_VERTICAL | Gravity.RIGHT)); + } else { + linearLayout.addView(linearLayout2, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 2, Gravity.CENTER_VERTICAL)); + linearLayout.addView(valueTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.RIGHT)); + } + } + + public void set( + int imageColor, + int imageResId, + CharSequence title, + CharSequence value, + boolean divider + ) { + if (imageResId == 0) { + imageView.setVisibility(View.GONE); + } else { + imageView.setVisibility(View.VISIBLE); + imageView.setBackground(Theme.createRoundRectDrawable(AndroidUtilities.dp(9), imageColor)); + imageView.setImageResource(imageResId); + } + + textView.setText(title); + valueTextView.setText(value); + + setWillNotDraw(!(this.divider = divider)); + } + + public void setArrow(Boolean value) { + if (value == null) { + arrowView.setVisibility(View.GONE); + } else { + arrowView.setVisibility(View.VISIBLE); + arrowView.animate().rotation(value ? 0 : 180).setDuration(360).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (divider) { + canvas.drawLine(LocaleController.isRTL ? 0 : AndroidUtilities.dp(64), getMeasuredHeight() - 1, getMeasuredWidth() - (LocaleController.isRTL ? AndroidUtilities.dp(64) : 0), getMeasuredHeight() - 1, Theme.dividerPaint); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure( + MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(48), MeasureSpec.EXACTLY) + ); + } + } + + public class CustomCharacterSpan extends MetricAffectingSpan { + double ratio = 0.5; + + public CustomCharacterSpan() { + } + + public CustomCharacterSpan(double ratio) { + this.ratio = ratio; + } + + @Override + public void updateDrawState(TextPaint paint) { + paint.baselineShift += (int) (paint.ascent() * ratio); + } + + @Override + public void updateMeasureState(TextPaint paint) { + paint.baselineShift += (int) (paint.ascent() * ratio); + } + } + + private boolean changeStatusBar; + + @Override + public void onTransitionAnimationProgress(boolean isOpen, float progress) { + if (progress > .5f && !changeStatusBar) { + changeStatusBar = true; + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.needCheckSystemBarColors); + } + super.onTransitionAnimationProgress(isOpen, progress); + } + + @Override + public boolean isLightStatusBar() { + if (!changeStatusBar) { + return super.isLightStatusBar(); + } + return AndroidUtilities.computePerceivedBrightness(Theme.getColor(Theme.key_actionBarActionModeDefault)) > 0.721f; + } + + @Override + public boolean isSwipeBackEnabled(MotionEvent event) { + if (event.getY() <= ActionBar.getCurrentActionBarHeight() + AndroidUtilities.dp(48)) { + return true; + } + return pager.getCurrentPosition() == 0; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DataUsageActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DataUsageActivity.java index a80f046c864..92752bf2511 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DataUsageActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DataUsageActivity.java @@ -27,6 +27,9 @@ import android.widget.FrameLayout; import android.widget.TextView; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; @@ -46,9 +49,6 @@ import java.util.ArrayList; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - public class DataUsageActivity extends BaseFragment { private class ViewPage extends FrameLayout { @@ -806,7 +806,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } case 3: { TextInfoPrivacyCell cell = (TextInfoPrivacyCell) holder.itemView; - cell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + cell.setBackground(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); cell.setText(LocaleController.formatString("NetworkUsageSince", R.string.NetworkUsageSince, LocaleController.getInstance().formatterStats.format(StatsController.getInstance(currentAccount).getResetStatsDate(currentType)))); break; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogOrContactPickerActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogOrContactPickerActivity.java index 11301655a94..4fdd14c0ccb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogOrContactPickerActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogOrContactPickerActivity.java @@ -87,18 +87,19 @@ public DialogOrContactPickerActivity() { args.putBoolean("onlySelect", true); args.putBoolean("checkCanWrite", false); args.putBoolean("resetDelegate", false); - args.putInt("dialogsType", 9); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_BLOCK); dialogsActivity = new DialogsActivity(args); dialogsActivity.setDelegate((fragment, dids, message, param) -> { if (dids.isEmpty()) { - return; + return true; } long did = dids.get(0).dialogId; if (!DialogObject.isUserDialog(did)) { - return; + return true; } TLRPC.User user = getMessagesController().getUser(did); showBlockAlert(user); + return true; }); dialogsActivity.onFragmentCreate(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java index 822d1c4ee9c..253b85884b6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -110,6 +110,7 @@ import org.telegram.messenger.Utilities; import org.telegram.messenger.XiaomiUtilities; import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.SerializedData; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; @@ -134,6 +135,7 @@ import org.telegram.ui.Cells.ArchiveHintInnerCell; import org.telegram.ui.Cells.DialogCell; import org.telegram.ui.Cells.DialogsEmptyCell; +import org.telegram.ui.Cells.DialogsHintCell; import org.telegram.ui.Cells.DividerCell; import org.telegram.ui.Cells.DrawerActionCell; import org.telegram.ui.Cells.DrawerAddCell; @@ -145,6 +147,7 @@ import org.telegram.ui.Cells.HintDialogCell; import org.telegram.ui.Cells.LoadingCell; import org.telegram.ui.Cells.ProfileSearchCell; +import org.telegram.ui.Cells.RequestPeerRequirementsCell; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; @@ -199,9 +202,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; public class DialogsActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, FloatingDebugProvider { - public final static int DIALOGS_TYPE_START_ATTACH_BOT = 14; + public final static boolean DISPLAY_SPEEDOMETER_IN_DOWNLOADS_SEARCH = true; private boolean canShowFilterTabsView; @@ -213,6 +217,9 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. private boolean rightFragmentTransitionInProgress; private boolean allowGlobalSearch = true; + private TLRPC.RequestPeerType requestPeerType; + private long requestPeerBotId; + public MessagesStorage.TopicKey getOpenedDialogId() { return openedDialogId; } @@ -242,12 +249,12 @@ public ViewPage(Context context) { } public boolean isDefaultDialogType() { - return dialogsType == 0 || dialogsType == 7 || dialogsType == 8; + return dialogsType == DIALOGS_TYPE_DEFAULT || dialogsType == 7 || dialogsType == 8; } boolean updating; Runnable updateListRunnable = () -> { - dialogsAdapter.updateList(listView, dialogsType == 0 && hasHiddenArchive() && archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN, actionBar.getTranslationY()); + dialogsAdapter.updateList(listView, dialogsType == DIALOGS_TYPE_DEFAULT && hasHiddenArchive() && archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN, actionBar.getTranslationY()); listView.updateDialogsOnNextDraw = true; updating = false; }; @@ -378,6 +385,8 @@ public void updateList(boolean animated) { private FragmentContextView fragmentLocationContextView; private FragmentContextView fragmentContextView; + private DialogsHintCell dialogsHintCell; + private Long cacheSize, deviceSize; private ArrayList frozenDialogsList; private boolean dialogsListFrozen; @@ -506,6 +515,8 @@ public void updateList(boolean animated) { private int debugLastUpdateAction = -1; private boolean slowedReloadAfterDialogClick; + private boolean isPremiumHintUpgrade; + private AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable statusDrawable; private DrawerProfileCell.AnimatedStatusView animatedStatusView; public RightSlidingDialogContainer rightSlidingDialogContainer; @@ -629,7 +640,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { return true; } boolean result; - if (child == viewPages[0] || (viewPages.length > 1 && child == viewPages[1]) || child == fragmentContextView || child == fragmentLocationContextView) { + if (child == viewPages[0] || (viewPages.length > 1 && child == viewPages[1]) || child == fragmentContextView || child == fragmentLocationContextView || child == dialogsHintCell) { canvas.save(); canvas.clipRect(0, -getY() + actionBar.getY() + getActionBarFullHeight(), getMeasuredWidth(), getMeasuredHeight()); if (slideFragmentProgress != 1f) { @@ -876,12 +887,12 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int contentWidthSpec = View.MeasureSpec.makeMeasureSpec(widthSize, View.MeasureSpec.EXACTLY); int h; if (filterTabsView != null && filterTabsView.getVisibility() == VISIBLE) { - h = heightSize - inputFieldHeight + AndroidUtilities.dp(2) - AndroidUtilities.dp(44) - topPadding; + h = heightSize - inputFieldHeight + AndroidUtilities.dp(2) - AndroidUtilities.dp(44) - topPadding - (dialogsHintCell != null ? dialogsHintCell.height() : 0); if (rightSlidingDialogContainer.hasFragment()) { h += AndroidUtilities.dp(44); } } else { - h = heightSize - inputFieldHeight + AndroidUtilities.dp(2) - (onlySelect ? 0 : actionBar.getMeasuredHeight()) - topPadding; + h = heightSize - inputFieldHeight + AndroidUtilities.dp(2) - (onlySelect ? 0 : actionBar.getMeasuredHeight()) - topPadding - (dialogsHintCell != null ? dialogsHintCell.height() : 0); } if (filtersTabAnimator != null && filterTabsView != null && filterTabsView.getVisibility() == VISIBLE) { h += filterTabsMoveFrom; @@ -1017,6 +1028,11 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { } } childTop += topPadding; + if (dialogsHintCell != null) { + childTop += dialogsHintCell.height(); + } + } else if (child instanceof DialogsHintCell) { + childTop += actionBar.getMeasuredHeight() + (filterTabsView != null && filterTabsView.getVisibility() == View.VISIBLE ? filterTabsView.getMeasuredHeight() : 0); } else if (child instanceof FragmentContextView) { childTop += actionBar.getMeasuredHeight(); } else if (child == floatingButtonContainer && selectAnimatedEmojiDialog != null) { @@ -1642,7 +1658,7 @@ protected void onMeasure(int widthSpec, int heightSpec) { RecyclerView.ViewHolder holder = parentPage.listView.findViewHolderForAdapterPosition(pos); if (holder != null) { int top = holder.itemView.getTop(); - if (parentPage.dialogsType == 0 && hasHiddenArchive() && parentPage.archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN) { + if (parentPage.dialogsType == DIALOGS_TYPE_DEFAULT && hasHiddenArchive() && parentPage.archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN) { pos = Math.max(1, pos); } ignoreLayout = true; @@ -1664,7 +1680,7 @@ protected void onMeasure(int widthSpec, int heightSpec) { } if (firstLayout && getMessagesController().dialogsLoaded) { - if (parentPage.dialogsType == 0 && hasHiddenArchive()) { + if (parentPage.dialogsType == DIALOGS_TYPE_DEFAULT && hasHiddenArchive()) { ignoreLayout = true; LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager(); layoutManager.scrollToPositionWithOffset(1, 0); @@ -1788,7 +1804,7 @@ public boolean onTouchEvent(MotionEvent e) { } } boolean result = super.onTouchEvent(e); - if (parentPage.dialogsType == 0 && (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) && parentPage.archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN && hasHiddenArchive()) { + if (parentPage.dialogsType == DIALOGS_TYPE_DEFAULT && (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) && parentPage.archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN && hasHiddenArchive()) { LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager(); int currentPosition = layoutManager.findFirstVisibleItemPosition(); if (currentPosition == 0) { @@ -1901,7 +1917,7 @@ public void setAnimationSupportView(RecyclerListView animationSupportListView, f int p = adapter.findDialogPosition(anchorView.getDialogId()); int offset = (int) (anchorView.getTop() - anchorListView.getPaddingTop() + scrollOffset); if (p >= 0) { - ((LinearLayoutManager) animationSupportListView.getLayoutManager()).scrollToPositionWithOffset(p, adapter.fixScrollGap(this, p, offset, parentPage.dialogsType == 0 && parentPage.archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN && hasHiddenArchive(), opened)); + ((LinearLayoutManager) animationSupportListView.getLayoutManager()).scrollToPositionWithOffset(p, adapter.fixScrollGap(this, p, offset, parentPage.dialogsType == DIALOGS_TYPE_DEFAULT && parentPage.archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN && hasHiddenArchive(), opened)); } } } @@ -2185,7 +2201,7 @@ public float getSwipeVelocityThreshold(float defaultValue) { } public interface DialogsActivityDelegate { - void didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param); + boolean didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param); } public DialogsActivity(Bundle args) { @@ -2196,11 +2212,11 @@ public DialogsActivity(Bundle args) { public boolean onFragmentCreate() { super.onFragmentCreate(); - if (getArguments() != null) { + if (arguments != null) { onlySelect = arguments.getBoolean("onlySelect", false); - canSelectTopics = arguments.getBoolean("canSelectTopics", false); + canSelectTopics = arguments.getBoolean("canSelectTopics", false); cantSendToChannels = arguments.getBoolean("cantSendToChannels", false); - initialDialogsType = arguments.getInt("dialogsType", 0); + initialDialogsType = arguments.getInt("dialogsType", DIALOGS_TYPE_DEFAULT); selectAlertString = arguments.getString("selectAlertString"); selectAlertStringGroup = arguments.getString("selectAlertStringGroup"); addToGroupAlertString = arguments.getString("addToGroupAlertString"); @@ -2220,9 +2236,19 @@ public boolean onFragmentCreate() { allowBots = arguments.getBoolean("allowBots", true); closeFragment = arguments.getBoolean("closeFragment", true); allowGlobalSearch = arguments.getBoolean("allowGlobalSearch", true); + + byte[] requestPeerTypeBytes = arguments.getByteArray("requestPeerType"); + if (requestPeerTypeBytes != null) { + try { + SerializedData buffer = new SerializedData(requestPeerTypeBytes); + requestPeerType = TLRPC.RequestPeerType.TLdeserialize(buffer, buffer.readInt32(true), true); + buffer.cleanup(); + } catch (Exception e) {} + } + requestPeerBotId = arguments.getLong("requestPeerBotId", 0); } - if (initialDialogsType == 0) { + if (initialDialogsType == DIALOGS_TYPE_DEFAULT) { askAboutContacts = MessagesController.getGlobalNotificationsSettings().getBoolean("askAboutContacts", true); SharedConfig.loadProxyList(); } @@ -2308,12 +2334,9 @@ public void updateStatus(TLRPC.User user, boolean animated) { if (statusDrawable == null || actionBar == null) { return; } - if (user != null && user.emoji_status instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) user.emoji_status).until > (int) (System.currentTimeMillis() / 1000)) { - statusDrawable.set(((TLRPC.TL_emojiStatusUntil) user.emoji_status).document_id, animated); - actionBar.setRightDrawableOnClick(e -> showSelectStatusDialog()); - SelectAnimatedEmojiDialog.preload(currentAccount); - } else if (user != null && user.emoji_status instanceof TLRPC.TL_emojiStatus) { - statusDrawable.set(((TLRPC.TL_emojiStatus) user.emoji_status).document_id, animated); + Long emojiStatusId = UserObject.getEmojiStatusDocumentId(user); + if (emojiStatusId != null) { + statusDrawable.set(emojiStatusId, animated); actionBar.setRightDrawableOnClick(e -> showSelectStatusDialog()); SelectAnimatedEmojiDialog.preload(currentAccount); } else if (user != null && MessagesController.getInstance(currentAccount).isPremiumUser(user)) { @@ -2632,17 +2655,31 @@ public boolean canToggleSearch() { } }); - if (initialDialogsType == 2 || initialDialogsType == DIALOGS_TYPE_START_ATTACH_BOT) { + if (initialDialogsType == DIALOGS_TYPE_ADD_USERS_TO || initialDialogsType == DIALOGS_TYPE_START_ATTACH_BOT) { searchItem.setVisibility(View.GONE); } searchItem.setSearchFieldHint(LocaleController.getString("Search", R.string.Search)); searchItem.setContentDescription(LocaleController.getString("Search", R.string.Search)); if (onlySelect) { actionBar.setBackButtonImage(R.drawable.ic_ab_back); - if (initialDialogsType == 3 && selectAlertString == null) { + if (initialDialogsType == DIALOGS_TYPE_FORWARD && selectAlertString == null) { actionBar.setTitle(LocaleController.getString("ForwardTo", R.string.ForwardTo)); - } else if (initialDialogsType == 10) { + } else if (initialDialogsType == DIALOGS_TYPE_WIDGET) { actionBar.setTitle(LocaleController.getString("SelectChats", R.string.SelectChats)); + } else if (requestPeerType instanceof TLRPC.TL_requestPeerTypeUser) { + if (((TLRPC.TL_requestPeerTypeUser) requestPeerType).bot != null) { + if (((TLRPC.TL_requestPeerTypeUser) requestPeerType).bot) { + actionBar.setTitle(LocaleController.getString("ChooseBot", R.string.ChooseBot)); + } else { + actionBar.setTitle(LocaleController.getString("ChooseUser", R.string.ChooseUser)); + } + } else { + actionBar.setTitle(LocaleController.getString("ChooseUser", R.string.ChooseUser)); + } + } else if (requestPeerType instanceof TLRPC.TL_requestPeerTypeBroadcast) { + actionBar.setTitle(LocaleController.getString("ChooseChannel", R.string.ChooseChannel)); + } else if (requestPeerType instanceof TLRPC.TL_requestPeerTypeChat) { + actionBar.setTitle(LocaleController.getString("ChooseGroup", R.string.ChooseGroup)); } else { actionBar.setTitle(LocaleController.getString("SelectChat", R.string.SelectChat)); } @@ -2683,7 +2720,7 @@ public boolean canToggleSearch() { scrollToTop(); }); - if (initialDialogsType == 0 && folderId == 0 && !onlySelect && TextUtils.isEmpty(searchString)) { + if (initialDialogsType == DIALOGS_TYPE_DEFAULT && folderId == 0 && !onlySelect && TextUtils.isEmpty(searchString)) { scrimPaint = new Paint() { @Override public void setAlpha(int a) { @@ -3083,7 +3120,7 @@ public void onDeletePressed(int id) { ContentView contentView = new ContentView(context); fragmentView = contentView; - int pagesCount = folderId == 0 && initialDialogsType == 0 && !onlySelect ? 2 : 1; + int pagesCount = folderId == 0 && initialDialogsType == DIALOGS_TYPE_DEFAULT && !onlySelect ? 2 : 1; viewPages = new ViewPage[pagesCount]; for (int a = 0; a < pagesCount; a++) { final ViewPage viewPage = new ViewPage(context) { @@ -3116,6 +3153,9 @@ public void setTranslationX(float translationX) { viewPage.listView.setAnimateEmptyView(true, RecyclerListView.EMPTY_VIEW_ANIMATION_TYPE_ALPHA); viewPage.listView.setClipToPadding(false); viewPage.listView.setPivotY(0); + if (initialDialogsType == DIALOGS_TYPE_BOT_REQUEST_PEER) { + viewPage.listView.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundGray)); + } viewPage.dialogsItemAnimator = new DialogsItemAnimator(viewPage.listView) { @Override public void onRemoveStarting(RecyclerView.ViewHolder item) { @@ -3175,7 +3215,7 @@ public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerVi int measuredDy = dy; int pTop = viewPage.listView.getPaddingTop(); - if (viewPage.dialogsType == 0 && !onlySelect && folderId == 0 && dy < 0 && getMessagesController().hasHiddenArchive() && viewPage.archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN) { + if (viewPage.dialogsType == DIALOGS_TYPE_DEFAULT && !onlySelect && folderId == 0 && dy < 0 && getMessagesController().hasHiddenArchive() && viewPage.archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN) { viewPage.listView.setOverScrollMode(View.OVER_SCROLL_ALWAYS); int currentPosition = viewPage.layoutManager.findFirstVisibleItemPosition(); if (currentPosition == 0) { @@ -3223,7 +3263,7 @@ public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerVi viewPage.listView.setViewsOffset(ty); } - if (viewPage.dialogsType == 0 && viewPage.archivePullViewState != ARCHIVE_ITEM_STATE_PINNED && hasHiddenArchive()) { + if (viewPage.dialogsType == DIALOGS_TYPE_DEFAULT && viewPage.archivePullViewState != ARCHIVE_ITEM_STATE_PINNED && hasHiddenArchive()) { int usedDy = super.scrollVerticallyBy(measuredDy, recycler, state); if (viewPage.pullForegroundDrawable != null) { viewPage.pullForegroundDrawable.scrollDy = usedDy; @@ -3309,10 +3349,13 @@ public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State viewPage.listView.setVerticalScrollbarPosition(LocaleController.isRTL ? RecyclerListView.SCROLLBAR_POSITION_LEFT : RecyclerListView.SCROLLBAR_POSITION_RIGHT); viewPage.addView(viewPage.listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); viewPage.listView.setOnItemClickListener((view, position) -> { - if (initialDialogsType == 10) { + if (initialDialogsType == DIALOGS_TYPE_BOT_REQUEST_PEER && view instanceof TextCell) { + viewPage.dialogsAdapter.onCreateGroupForThisClick(); + return; + } else if (initialDialogsType == DIALOGS_TYPE_WIDGET) { onItemLongClick(viewPage.listView, view, position, 0, 0, viewPage.dialogsType, viewPage.dialogsAdapter); return; - } else if ((initialDialogsType == 11 || initialDialogsType == 13) && position == 1) { + } else if ((initialDialogsType == DIALOGS_TYPE_IMPORT_HISTORY_GROUPS || initialDialogsType == DIALOGS_TYPE_IMPORT_HISTORY) && position == 1) { Bundle args = new Bundle(); args.putBoolean("forImport", true); long[] array = new long[]{getUserConfig().getClientUserId()}; @@ -3410,7 +3453,9 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { int actionBarHeight = ActionBar.getCurrentActionBarHeight(); if (scrollY != 0 && scrollY != actionBarHeight) { if (scrollY < actionBarHeight / 2) { - recyclerView.smoothScrollBy(0, -scrollY); + if (viewPages[0].listView.canScrollVertically(-1)) { + recyclerView.smoothScrollBy(0, -scrollY); + } } else if (viewPages[0].listView.canScrollVertically(1)) { recyclerView.smoothScrollBy(0, actionBarHeight - scrollY); } @@ -3451,7 +3496,7 @@ public void onScrolled(RecyclerView recyclerView, int dx, int dy) { } } if (filterTabsView != null && filterTabsView.getVisibility() == View.VISIBLE && recyclerView == viewPages[0].listView && !searching && !actionBar.isActionModeShowed() && !disableActionBarScrolling && filterTabsViewIsVisible && !rightSlidingDialogContainer.hasFragment()) { - if (dy > 0 && hasHiddenArchive() && viewPages[0].dialogsType == 0) { + if (dy > 0 && hasHiddenArchive() && viewPages[0].dialogsType == DIALOGS_TYPE_DEFAULT) { View child = recyclerView.getChildAt(0); if (child != null) { RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder(child); @@ -3504,7 +3549,7 @@ protected float getViewOffset() { viewPage.pullForegroundDrawable.setWillDraw(viewPage.archivePullViewState != ARCHIVE_ITEM_STATE_PINNED); } - viewPage.dialogsAdapter = new DialogsAdapter(this, context, viewPage.dialogsType, folderId, onlySelect, selectedDialogs, currentAccount) { + viewPage.dialogsAdapter = new DialogsAdapter(this, context, viewPage.dialogsType, folderId, onlySelect, selectedDialogs, currentAccount, requestPeerType) { @Override public void notifyDataSetChanged() { viewPage.lastItemsCount = getItemCount(); @@ -3513,6 +3558,9 @@ public void notifyDataSetChanged() { } catch (Exception e) { FileLog.e(e); } + if (initialDialogsType == DIALOGS_TYPE_BOT_REQUEST_PEER) { + searchItem.setVisibility(isEmpty ? View.GONE : View.VISIBLE); + } } @Override @@ -3533,6 +3581,11 @@ public void onButtonClicked(DialogCell dialogCell) { public void onButtonLongPress(DialogCell dialogCell) { onItemLongClick(viewPage.listView, dialogCell, viewPage.listView.getChildAdapterPosition(dialogCell), 0, 0, viewPage.dialogsType, viewPage.dialogsAdapter); } + + @Override + public void onCreateGroupForThisClick() { + createGroupForThis(); + } }; viewPage.dialogsAdapter.setRecyclerListView(viewPage.listView); viewPage.dialogsAdapter.setForceShowEmptyCell(afterSignup); @@ -3743,7 +3796,7 @@ public long getSearchForumDialogId() { }); searchViewPager.searchListView.setOnItemClickListener((view, position) -> { - if (initialDialogsType == 10) { + if (initialDialogsType == DIALOGS_TYPE_WIDGET) { onItemLongClick(searchViewPager.searchListView, view, position, 0, 0, -1, searchViewPager.dialogsSearchAdapter); return; } @@ -3789,7 +3842,7 @@ public void onLongClickRelease() { finishPreviewFragment(); return; } - if (initialDialogsType == 10) { + if (initialDialogsType == DIALOGS_TYPE_WIDGET) { if (delegate == null || selectedDialogs.isEmpty()) { return; } @@ -3812,7 +3865,7 @@ public void onLongClickRelease() { floatingButton = new RLottieImageView(context); floatingButton.setScaleType(ImageView.ScaleType.CENTER); floatingButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chats_actionIcon), PorterDuff.Mode.MULTIPLY)); - if (initialDialogsType == 10) { + if (initialDialogsType == DIALOGS_TYPE_WIDGET) { floatingButton.setImageResource(R.drawable.floating_check); floatingButtonContainer.setContentDescription(LocaleController.getString("Done", R.string.Done)); } else { @@ -3872,7 +3925,19 @@ protected void playbackSpeedChanged(float value) { fragmentContextView.setAdditionalContextView(fragmentLocationContextView); fragmentLocationContextView.setAdditionalContextView(fragmentContextView); - } else if (initialDialogsType == 3) { + + dialogsHintCell = new DialogsHintCell(context); + updateDialogsHint(); + CacheControlActivity.calculateTotalSize(size -> { + cacheSize = size; + updateDialogsHint(); + }); + CacheControlActivity.getDeviceTotalSize((totalSize, totalFreeSize) -> { + deviceSize = totalSize; + updateDialogsHint(); + }); + contentView.addView(dialogsHintCell); + } else if (initialDialogsType == DIALOGS_TYPE_FORWARD) { if (commentView != null) { commentView.onDestroy(); } @@ -4154,7 +4219,7 @@ public void getOutline(View view, Outline outline) { contentView.addView(animatedStatusView, LayoutHelper.createFrame(20, 20, Gravity.LEFT | Gravity.TOP)); } - if (searchString == null && initialDialogsType == 0) { + if (searchString == null && initialDialogsType == DIALOGS_TYPE_DEFAULT) { updateLayout = new FrameLayout(context) { private Paint paint = new Paint(); @@ -4301,7 +4366,7 @@ protected void onRemoveDialogAction(long currentDialogId, int action) { actionBar.setSearchTextColor(Theme.getColor(Theme.key_actionBarDefaultArchivedSearchPlaceholder), true); } - if (!onlySelect && initialDialogsType == 0) { + if (!onlySelect && initialDialogsType == DIALOGS_TYPE_DEFAULT) { blurredView = new View(context) { @Override public void setAlpha(float alpha) { @@ -4421,7 +4486,7 @@ public boolean onTouchEvent(MotionEvent e) { LinearLayoutManager layoutManager = new LinearLayoutManager(context); layoutManager.setNeedFixEndGap(false); transitionPage.animationSupportListView.setLayoutManager(layoutManager); - transitionPage.animationSupportDialogsAdapter = new DialogsAdapter(DialogsActivity.this, context, transitionPage.dialogsType, folderId, onlySelect, selectedDialogs, currentAccount); + transitionPage.animationSupportDialogsAdapter = new DialogsAdapter(DialogsActivity.this, context, transitionPage.dialogsType, folderId, onlySelect, selectedDialogs, currentAccount, requestPeerType); transitionPage.animationSupportDialogsAdapter.setIsTransitionSupport(); transitionPage.animationSupportListView.setAdapter(transitionPage.animationSupportDialogsAdapter); transitionPage.addView(transitionPage.animationSupportListView); @@ -4461,7 +4526,7 @@ public void openAnimationFinished() { rightFragmentTransitionInProgress = false; actionBar.setAllowOverlayTitle(!hasFragment()); contentView.requestLayout(); - transitionPage.layoutManager.setNeedFixEndGap(!hasFragment()); + // transitionPage.layoutManager.setNeedFixEndGap(!hasFragment()); DialogsActivity.this.setScrollY(0); searchViewPager.updateTabs(); updateDrawerSwipeEnabled(); @@ -4526,6 +4591,46 @@ void setOpenProgress(float progress) { return fragmentView; } + public boolean isPremiumHintVisible() { + if (!MessagesController.getInstance(currentAccount).premiumLocked && folderId == 0) { + if (MessagesController.getInstance(currentAccount).pendingSuggestions.contains("PREMIUM_UPGRADE") && getUserConfig().isPremium() || MessagesController.getInstance(currentAccount).pendingSuggestions.contains("PREMIUM_ANNUAL") && !getUserConfig().isPremium()) { + if (UserConfig.getInstance(currentAccount).isPremium() ? !BuildVars.useInvoiceBilling() && MediaDataController.getInstance(currentAccount).getPremiumHintAnnualDiscount(true) != null : MediaDataController.getInstance(currentAccount).getPremiumHintAnnualDiscount(false) != null) { + isPremiumHintUpgrade = MessagesController.getInstance(currentAccount).pendingSuggestions.contains("PREMIUM_UPGRADE"); + return true; + } + } + } + return false; + } + + private boolean isCacheHintVisible() { + if (cacheSize == null || deviceSize == null) { + return false; + } + if ((cacheSize / (float) deviceSize) < 0.30F) { + clearCacheHintVisible(); + return false; + } + SharedPreferences prefs = MessagesController.getGlobalMainSettings(); + return System.currentTimeMillis() > prefs.getLong("cache_hint_showafter", 0L); + } + + private void resetCacheHintVisible() { + SharedPreferences prefs = MessagesController.getGlobalMainSettings(); + final long week = 1000L * 60L * 60L * 24L * 7L; + final long month = 1000L * 60L * 60L * 24L * 30L; + long period = prefs.getLong("cache_hint_period", week); + if (period <= week) { + period = month; + } + long showafter = System.currentTimeMillis() + period; + prefs.edit().putLong("cache_hint_showafter", showafter).putLong("cache_hint_period", period).apply(); + } + + private void clearCacheHintVisible() { + MessagesController.getGlobalMainSettings().edit().remove("cache_hint_showafter").remove("cache_hint_period").apply(); + } + // @Override // public ActionBar getActionBar() { // return rightSlidingDialogContainer != null && rightSlidingDialogContainer.currentActionBarView != null && rightSlidingDialogContainer.isOpenned ? rightSlidingDialogContainer.currentActionBarView : super.getActionBar(); @@ -4554,31 +4659,21 @@ public void showSelectStatusDialog() { SelectAnimatedEmojiDialog popupLayout = new SelectAnimatedEmojiDialog(this, getContext(), true, xoff, SelectAnimatedEmojiDialog.TYPE_EMOJI_STATUS, getResourceProvider()) { @Override protected void onEmojiSelected(View emojiView, Long documentId, TLRPC.Document document, Integer until) { - TLRPC.TL_account_updateEmojiStatus req = new TLRPC.TL_account_updateEmojiStatus(); + TLRPC.EmojiStatus emojiStatus; if (documentId == null) { - req.emoji_status = new TLRPC.TL_emojiStatusEmpty(); + emojiStatus = new TLRPC.TL_emojiStatusEmpty(); } else if (until != null) { - req.emoji_status = new TLRPC.TL_emojiStatusUntil(); - ((TLRPC.TL_emojiStatusUntil) req.emoji_status).document_id = documentId; - ((TLRPC.TL_emojiStatusUntil) req.emoji_status).until = until; + emojiStatus = new TLRPC.TL_emojiStatusUntil(); + ((TLRPC.TL_emojiStatusUntil) emojiStatus).document_id = documentId; + ((TLRPC.TL_emojiStatusUntil) emojiStatus).until = until; } else { - req.emoji_status = new TLRPC.TL_emojiStatus(); - ((TLRPC.TL_emojiStatus) req.emoji_status).document_id = documentId; - } - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); - if (user != null) { - user.emoji_status = req.emoji_status; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userEmojiStatusUpdated, user); - getMessagesController().updateEmojiStatusUntilUpdate(user.id, user.emoji_status); + emojiStatus = new TLRPC.TL_emojiStatus(); + ((TLRPC.TL_emojiStatus) emojiStatus).document_id = documentId; } + getMessagesController().updateEmojiStatus(emojiStatus); if (documentId != null) { animatedStatusView.animateChange(ReactionsLayoutInBubble.VisibleReaction.fromCustomEmoji(documentId)); } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> { - if (!(res instanceof TLRPC.TL_boolTrue)) { - // TODO: reject - } - }); if (popup[0] != null) { selectAnimatedEmojiDialog = null; popup[0].dismiss(); @@ -4631,6 +4726,225 @@ private void updateCommentView() { commentViewPreviousTop = top; } + private void updateDialogsHint() { + if (dialogsHintCell == null) { + return; + } + if (isPremiumHintVisible()) { + dialogsHintCell.setVisibility(View.VISIBLE); + dialogsHintCell.setOnClickListener(v -> { + presentFragment(new PremiumPreviewFragment("dialogs_hint").setSelectAnnualByDefault()); + AndroidUtilities.runOnUIThread(() -> { + MessagesController.getInstance(currentAccount).removeSuggestion(0, isPremiumHintUpgrade ? "PREMIUM_UPGRADE" : "PREMIUM_ANNUAL"); + updateDialogsHint(); + }, 250); + }); + dialogsHintCell.setText( + AndroidUtilities.replaceSingleTag( + LocaleController.formatString(isPremiumHintUpgrade ? R.string.SaveOnAnnualPremiumTitle : R.string.UpgradePremiumTitle, MediaDataController.getInstance(currentAccount).getPremiumHintAnnualDiscount(false)), + Theme.key_windowBackgroundWhiteValueText, + 0, + null + ), + LocaleController.getString(isPremiumHintUpgrade ? R.string.UpgradePremiumMessage : R.string.SaveOnAnnualPremiumMessage) + ); + } else if (isCacheHintVisible()) { + dialogsHintCell.setVisibility(View.VISIBLE); + dialogsHintCell.setOnClickListener(v -> { + presentFragment(new CacheControlActivity()); + AndroidUtilities.runOnUIThread(() -> { + resetCacheHintVisible(); + updateDialogsHint(); + }, 250); + }); + dialogsHintCell.setText( + AndroidUtilities.replaceSingleTag( + LocaleController.formatString(R.string.ClearStorageHintTitle, AndroidUtilities.formatFileSize(cacheSize)), + Theme.key_windowBackgroundWhiteValueText, + 0, + null + ), + LocaleController.getString(R.string.ClearStorageHintMessage) + ); + } else { + dialogsHintCell.setVisibility(View.GONE); + } + } + + private void createGroupForThis() { + AlertDialog progress = new AlertDialog(getContext(), AlertDialog.ALERT_TYPE_SPINNER); + if (requestPeerType instanceof TLRPC.TL_requestPeerTypeBroadcast) { + Bundle args = new Bundle(); + args.putInt("step", 0); + if (requestPeerType.has_username != null) { + args.putBoolean("forcePublic", requestPeerType.has_username); + } + ChannelCreateActivity fragment = new ChannelCreateActivity(args); + fragment.setOnFinishListener((fragment2, chatId) -> { + Utilities.doCallbacks( + next -> { + TLRPC.Chat chat = getMessagesController().getChat(chatId); + showSendToBotAlert(chat, next, () -> { + DialogsActivity.this.removeSelfFromStack(); + fragment.removeSelfFromStack(); + fragment2.finishFragment(); + }); + }, + next -> { + progress.showDelayed(150); + if (requestPeerType.bot_participant != null && requestPeerType.bot_participant) { + TLRPC.User bot = getMessagesController().getUser(requestPeerBotId); + getMessagesController().addUserToChat(chatId, bot, 0, null, DialogsActivity.this, false, next, err -> { + next.run(); + return true; + }); + } else { + next.run(); + } + }, + next -> { + if (requestPeerType.bot_admin_rights != null) { + TLRPC.User bot = getMessagesController().getUser(requestPeerBotId); + getMessagesController().setUserAdminRole(chatId, bot, requestPeerType.bot_admin_rights, null, false, DialogsActivity.this, !(requestPeerType.bot_participant != null && requestPeerType.bot_participant), true, null, next, err -> { + next.run(); + return true; + }); + } else { + next.run(); + } + }, + next -> { + if (requestPeerType.user_admin_rights != null) { + TLRPC.Chat chat = getMessagesController().getChat(chatId); + getMessagesController().setUserAdminRole(chatId, getAccountInstance().getUserConfig().getCurrentUser(), ChatRightsEditActivity.rightsOR(chat.admin_rights, requestPeerType.user_admin_rights), null, true, DialogsActivity.this, false, true, null, next, err -> { + next.run(); + return true; + }); + } else { + next.run(); + } + }, + next -> { + progress.dismiss(); + getMessagesController().loadChannelParticipants(chatId); + DialogsActivityDelegate delegate = DialogsActivity.this.delegate; + DialogsActivity.this.removeSelfFromStack(); + fragment.removeSelfFromStack(); + fragment2.finishFragment(); + if (delegate != null) { + ArrayList keys = new ArrayList<>(); + keys.add(MessagesStorage.TopicKey.of(-chatId, 0)); + delegate.didSelectDialogs(DialogsActivity.this, keys, null, false); + } + } + ); + }); + presentFragment(fragment); + } else if (requestPeerType instanceof TLRPC.TL_requestPeerTypeChat) { + Bundle args = new Bundle(); + long[] array; + if (requestPeerType.bot_participant != null && requestPeerType.bot_participant) { + array = new long[]{ getUserConfig().getClientUserId(), requestPeerBotId }; + } else { + array = new long[]{ getUserConfig().getClientUserId() }; + } + args.putLongArray("result", array); + args.putInt("chatType", requestPeerType.forum != null && requestPeerType.forum ? ChatObject.CHAT_TYPE_FORUM : ChatObject.CHAT_TYPE_MEGAGROUP); + args.putBoolean("canToggleTopics", false); + GroupCreateFinalActivity activity = new GroupCreateFinalActivity(args); + activity.setDelegate(new GroupCreateFinalActivity.GroupCreateFinalActivityDelegate() { + @Override + public void didStartChatCreation() {} + @Override + public void didFailChatCreation() {} + @Override + public void didFinishChatCreation(GroupCreateFinalActivity fragment, long chatId) { + BaseFragment[] lastFragments = new BaseFragment[] { fragment, null }; + Utilities.doCallbacks( + next -> { + if (requestPeerType.has_username != null && requestPeerType.has_username) { + Bundle args = new Bundle(); + args.putInt("step", 1); + args.putLong("chat_id", chatId); + args.putBoolean("forcePublic", requestPeerType.has_username); + ChannelCreateActivity fragment2 = new ChannelCreateActivity(args); + fragment2.setOnFinishListener((_fragment, _chatId) -> next.run()); + presentFragment(fragment2); + lastFragments[1] = fragment2; + } else { + next.run(); + } + }, + next -> { + TLRPC.Chat chat = getMessagesController().getChat(chatId); + showSendToBotAlert(chat, next, () -> { + DialogsActivity.this.removeSelfFromStack(); + if (lastFragments[1] != null) { + lastFragments[0].removeSelfFromStack(); + lastFragments[1].finishFragment(); + } else { + lastFragments[0].finishFragment(); + } + }); + }, + next -> { + progress.showDelayed(150); + if (requestPeerType.bot_participant != null && requestPeerType.bot_participant) { + TLRPC.User bot = getMessagesController().getUser(requestPeerBotId); + getMessagesController().addUserToChat(chatId, bot, 0, null, DialogsActivity.this, false, next, err -> { + next.run(); + return true; + }); + } else { + next.run(); + } + }, + next -> { + if (requestPeerType.bot_admin_rights != null) { + TLRPC.User bot = getMessagesController().getUser(requestPeerBotId); + getMessagesController().setUserAdminRole(chatId, bot, requestPeerType.bot_admin_rights, null, false, DialogsActivity.this, !(requestPeerType.bot_participant != null && requestPeerType.bot_participant), true, null, next, err -> { + next.run(); + return true; + }); + } else { + next.run(); + } + }, + next -> { + if (requestPeerType.user_admin_rights != null) { + TLRPC.Chat chat = getMessagesController().getChat(chatId); + getMessagesController().setUserAdminRole(chatId, getAccountInstance().getUserConfig().getCurrentUser(), ChatRightsEditActivity.rightsOR(chat.admin_rights, requestPeerType.user_admin_rights), null, false, DialogsActivity.this, false, true, null, next, err -> { + next.run(); + return true; + }); + } else { + next.run(); + } + }, + next -> { + progress.dismiss(); + getMessagesController().loadChannelParticipants(chatId); + DialogsActivityDelegate delegate = DialogsActivity.this.delegate; + DialogsActivity.this.removeSelfFromStack(); + if (lastFragments[1] != null) { + lastFragments[0].removeSelfFromStack(); + lastFragments[1].finishFragment(); + } else { + lastFragments[0].finishFragment(); + } + if (delegate != null) { + ArrayList keys = new ArrayList<>(); + keys.add(MessagesStorage.TopicKey.of(-chatId, 0)); + delegate.didSelectDialogs(DialogsActivity.this, keys, null, false); + } + } + ); + } + }); + presentFragment(activity); + } + } + private void updateAppUpdateViews(boolean animated) { if (updateLayout == null) { return; @@ -5065,7 +5379,7 @@ private void switchToCurrentSelectedMode(boolean animated) { viewPages[1].isLocked = filter.locked; viewPages[a].dialogsAdapter.setDialogsType(viewPages[a].dialogsType); - viewPages[a].layoutManager.scrollToPositionWithOffset(viewPages[a].dialogsType == 0 && hasHiddenArchive() && viewPages[a].archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN ? 1 : 0, (int) actionBar.getTranslationY()); + viewPages[a].layoutManager.scrollToPositionWithOffset(viewPages[a].dialogsType == DIALOGS_TYPE_DEFAULT && hasHiddenArchive() && viewPages[a].archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN ? 1 : 0, (int) actionBar.getTranslationY()); checkListLoad(viewPages[a]); } @@ -5171,7 +5485,7 @@ private void updateFilterTabs(boolean force, boolean animated) { canShowFilterTabsView = false; updateFilterTabsVisibility(animated); for (int a = 0; a < viewPages.length; a++) { - if (viewPages[a].dialogsType == 0 && viewPages[a].archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN && hasHiddenArchive()) { + if (viewPages[a].dialogsType == DIALOGS_TYPE_DEFAULT && viewPages[a].archivePullViewState == ARCHIVE_ITEM_STATE_HIDDEN && hasHiddenArchive()) { int p = viewPages[a].layoutManager.findFirstVisibleItemPosition(); if (p == 0 || p == 1) { viewPages[a].layoutManager.scrollToPositionWithOffset(1, (int) actionBar.getTranslationY()); @@ -5358,7 +5672,7 @@ public void onShow(Bulletin bulletin) { @Override public int getTopOffset(int tag) { - return (actionBar != null ? actionBar.getMeasuredHeight() + (int) actionBar.getTranslationY() : 0) + (filterTabsView != null && filterTabsView.getVisibility() == View.VISIBLE ? filterTabsView.getMeasuredHeight() : 0) + (fragmentContextView != null && fragmentContextView.isCallTypeVisible() ? AndroidUtilities.dp(fragmentContextView.getStyleHeight()) : 0); + return (actionBar != null ? actionBar.getMeasuredHeight() + (int) actionBar.getTranslationY() : 0) + (filterTabsView != null && filterTabsView.getVisibility() == View.VISIBLE ? filterTabsView.getMeasuredHeight() : 0) + (fragmentContextView != null && fragmentContextView.isCallTypeVisible() ? AndroidUtilities.dp(fragmentContextView.getStyleHeight()) : 0) + (dialogsHintCell.getVisibility() == View.VISIBLE ? dialogsHintCell.getHeight() : 0); } }); if (searchIsShowed) { @@ -6270,7 +6584,7 @@ private void onItemClick(View view, int position, RecyclerListView.Adapter adapt if (!validateSlowModeDialog(dialogId)) { return; } - if (!getMessagesController().isForum(dialogId) && (!selectedDialogs.isEmpty() || (initialDialogsType == 3 && selectAlertString != null))) { + if (!getMessagesController().isForum(dialogId) && (!selectedDialogs.isEmpty() || (initialDialogsType == DIALOGS_TYPE_FORWARD && selectAlertString != null))) { if (!selectedDialogs.contains(dialogId) && !checkCanWrite(dialogId)) { return; } @@ -6913,6 +7227,9 @@ private void setScrollY(float value) { if (filterTabsView != null) { filterTabsView.setTranslationY(value); } + if (dialogsHintCell != null) { + dialogsHintCell.setTranslationY(value); + } if (animatedStatusView != null) { animatedStatusView.translateY2((int) value); animatedStatusView.setAlpha(1f - -value / ActionBar.getCurrentActionBarHeight()); @@ -6944,7 +7261,9 @@ private void prepareBlurBitmap() { @Override public void onTransitionAnimationProgress(boolean isOpen, float progress) { - if (blurredView != null && blurredView.getVisibility() == View.VISIBLE) { + if (rightSlidingDialogContainer != null && rightSlidingDialogContainer.hasFragment()) { + rightSlidingDialogContainer.getFragment().onTransitionAnimationProgress(isOpen, progress); + } else if (blurredView != null && blurredView.getVisibility() == View.VISIBLE) { if (isOpen) { blurredView.setAlpha(1.0f - progress); } else { @@ -6955,16 +7274,21 @@ public void onTransitionAnimationProgress(boolean isOpen, float progress) { @Override public void onTransitionAnimationEnd(boolean isOpen, boolean backward) { - if (isOpen && blurredView != null && blurredView.getVisibility() == View.VISIBLE) { - blurredView.setVisibility(View.GONE); - blurredView.setBackground(null); - } - if (isOpen && afterSignup) { - try { - fragmentView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); - } catch (Exception ignored) {} - if (getParentActivity() instanceof LaunchActivity) { - ((LaunchActivity) getParentActivity()).getFireworksOverlay().start(); + if (rightSlidingDialogContainer != null && rightSlidingDialogContainer.hasFragment()) { + rightSlidingDialogContainer.getFragment().onTransitionAnimationEnd(isOpen, backward); + } else { + if (isOpen && blurredView != null && blurredView.getVisibility() == View.VISIBLE) { + blurredView.setVisibility(View.GONE); + blurredView.setBackground(null); + } + if (isOpen && afterSignup) { + try { + fragmentView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignored) { + } + if (getParentActivity() instanceof LaunchActivity) { + ((LaunchActivity) getParentActivity()).getFireworksOverlay().start(); + } } } } @@ -8148,7 +8472,7 @@ public void onAnimationEnd(Animator animation) { } actionBar.setTitle(LocaleController.formatPluralString("Recipient", selectedDialogs.size())); } - } else if (initialDialogsType == 10) { + } else if (initialDialogsType == DIALOGS_TYPE_WIDGET) { hideFloatingButton(selectedDialogs.isEmpty()); } @@ -8491,6 +8815,7 @@ public void didReceivedNotification(int id, int account, Object... args) { showFiltersHint(); } else if (id == NotificationCenter.newSuggestionsAvailable) { showNextSupportedSuggestion(); + updateDialogsHint(); } else if (id == NotificationCenter.forceImportContactsStart) { setFloatingProgressVisible(true, true); for (ViewPage page : viewPages) { @@ -8673,17 +8998,34 @@ public DialogsHeader(int type) { } } + public static final int DIALOGS_TYPE_DEFAULT = 0; + public static final int DIALOGS_TYPE_BOT_SHARE = 1; // selecting group to write with inline bot query, including sharing a game + public static final int DIALOGS_TYPE_ADD_USERS_TO = 2; // Chats + My channels + My groups + public static final int DIALOGS_TYPE_FORWARD = 3; + public static final int DIALOGS_TYPE_USERS_ONLY = 4; + public static final int DIALOGS_TYPE_CHANNELS_ONLY = 5; + public static final int DIALOGS_TYPE_GROUPS_ONLY = 6; + public static final int DIALOGS_TYPE_7 = 7; + public static final int DIALOGS_TYPE_8 = 8; + public static final int DIALOGS_TYPE_BLOCK = 9; + public static final int DIALOGS_TYPE_WIDGET = 10; + public static final int DIALOGS_TYPE_IMPORT_HISTORY_GROUPS = 11; // groups only + public static final int DIALOGS_TYPE_IMPORT_HISTORY_USERS = 12; // users only + public static final int DIALOGS_TYPE_IMPORT_HISTORY = 13; + public static final int DIALOGS_TYPE_START_ATTACH_BOT = 14; + public static final int DIALOGS_TYPE_BOT_REQUEST_PEER = 15; + @NonNull public ArrayList getDialogsArray(int currentAccount, int dialogsType, int folderId, boolean frozen) { if (frozen && frozenDialogsList != null) { return frozenDialogsList; } MessagesController messagesController = AccountInstance.getInstance(currentAccount).getMessagesController(); - if (dialogsType == 0) { + if (dialogsType == DIALOGS_TYPE_DEFAULT) { return messagesController.getDialogs(folderId); - } else if (dialogsType == 1 || dialogsType == 10 || dialogsType == 13) { + } else if (dialogsType == DIALOGS_TYPE_BOT_SHARE || dialogsType == DIALOGS_TYPE_WIDGET || dialogsType == DIALOGS_TYPE_IMPORT_HISTORY) { return messagesController.dialogsServerOnly; - } else if (dialogsType == 2) { + } else if (dialogsType == DIALOGS_TYPE_ADD_USERS_TO) { ArrayList dialogs = new ArrayList<>(messagesController.dialogsCanAddUsers.size() + messagesController.dialogsMyChannels.size() + messagesController.dialogsMyGroups.size() + 2); if (messagesController.dialogsMyChannels.size() > 0 && allowChannels) { dialogs.add(new DialogsHeader(DialogsHeader.HEADER_TYPE_MY_CHANNELS)); @@ -8709,13 +9051,13 @@ public ArrayList getDialogsArray(int currentAccount, int dialogsTy } } return dialogs; - } else if (dialogsType == 3) { + } else if (dialogsType == DIALOGS_TYPE_FORWARD) { return messagesController.dialogsForward; - } else if (dialogsType == 4 || dialogsType == 12) { + } else if (dialogsType == DIALOGS_TYPE_USERS_ONLY || dialogsType == DIALOGS_TYPE_IMPORT_HISTORY_USERS) { return messagesController.dialogsUsersOnly; - } else if (dialogsType == 5) { + } else if (dialogsType == DIALOGS_TYPE_CHANNELS_ONLY) { return messagesController.dialogsChannelsOnly; - } else if (dialogsType == 6 || dialogsType == 11) { + } else if (dialogsType == DIALOGS_TYPE_GROUPS_ONLY || dialogsType == DIALOGS_TYPE_IMPORT_HISTORY_GROUPS) { return messagesController.dialogsGroupsOnly; } else if (dialogsType == 7 || dialogsType == 8) { MessagesController.DialogFilter dialogFilter = messagesController.selectedDialogFilter[dialogsType == 7 ? 0 : 1]; @@ -8724,13 +9066,14 @@ public ArrayList getDialogsArray(int currentAccount, int dialogsTy } else { return dialogFilter.dialogs; } - } else if (dialogsType == 9) { + } else if (dialogsType == DIALOGS_TYPE_BLOCK) { return messagesController.dialogsForBlock; } else if (dialogsType == DIALOGS_TYPE_START_ATTACH_BOT) { ArrayList dialogs = new ArrayList<>(); if (allowUsers || allowBots) { for (TLRPC.Dialog d : messagesController.dialogsUsersOnly) { - if (messagesController.getUser(d.id).bot ? allowBots : allowUsers) { + TLRPC.User user = messagesController.getUser(d.id); + if (user != null && !UserObject.isUserSelf(user) && (user.bot ? allowBots : allowUsers)) { dialogs.add(d); } } @@ -8742,10 +9085,79 @@ public ArrayList getDialogsArray(int currentAccount, int dialogsTy dialogs.addAll(messagesController.dialogsChannelsOnly); } return dialogs; + } else if (dialogsType == DIALOGS_TYPE_BOT_REQUEST_PEER) { + ArrayList dialogs = new ArrayList<>(); + TLRPC.User bot = messagesController.getUser(requestPeerBotId); + if (requestPeerType instanceof TLRPC.TL_requestPeerTypeUser) { + ConcurrentHashMap users = messagesController.getUsers(); + for (TLRPC.Dialog dialog : messagesController.dialogsUsersOnly) { + TLRPC.User user = getMessagesController().getUser(dialog.id); + if (meetRequestPeerRequirements(user)) { + dialogs.add(dialog); + } + } + for (TLRPC.User user : users.values()) { + if (user != null && !messagesController.dialogs_dict.containsKey(user.id) && meetRequestPeerRequirements(user)) { + TLRPC.Dialog d = new TLRPC.TL_dialog(); + d.peer = new TLRPC.TL_peerUser(); + d.peer.user_id = user.id; + d.id = user.id; + dialogs.add(d); + } + } + } else if (requestPeerType instanceof TLRPC.TL_requestPeerTypeChat || requestPeerType instanceof TLRPC.TL_requestPeerTypeBroadcast) { + ConcurrentHashMap chats = messagesController.getChats(); + ArrayList sourceDialogs = requestPeerType instanceof TLRPC.TL_requestPeerTypeChat ? messagesController.dialogsGroupsOnly : messagesController.dialogsChannelsOnly; + for (TLRPC.Dialog dialog : sourceDialogs) { + TLRPC.Chat chat = getMessagesController().getChat(-dialog.id); + if (meetRequestPeerRequirements(bot, chat)) { + dialogs.add(dialog); + } + } + for (TLRPC.Chat chat : chats.values()) { + if (chat != null && !messagesController.dialogs_dict.containsKey(-chat.id) && meetRequestPeerRequirements(bot, chat)) { + TLRPC.Dialog d = new TLRPC.TL_dialog(); + if (ChatObject.isChannel(chat)) { + d.peer = new TLRPC.TL_peerChannel(); + d.peer.channel_id = chat.id; + } else { + d.peer = new TLRPC.TL_peerChat(); + d.peer.chat_id = chat.id; + } + d.id = -chat.id; + dialogs.add(d); + } + } + } + return dialogs; } return new ArrayList<>(); } + private boolean meetRequestPeerRequirements(TLRPC.User user) { + TLRPC.TL_requestPeerTypeUser type = (TLRPC.TL_requestPeerTypeUser) requestPeerType; + return ( + user != null && + !UserObject.isReplyUser(user) && + !UserObject.isDeleted(user) && + (type.bot == null || type.bot == user.bot) && + (type.premium == null || type.premium == user.premium) + ); + } + + private boolean meetRequestPeerRequirements(TLRPC.User bot, TLRPC.Chat chat) { + return ( + chat != null && + ChatObject.isChannelAndNotMegaGroup(chat) == requestPeerType instanceof TLRPC.TL_requestPeerTypeBroadcast && + (requestPeerType.creator == null || !requestPeerType.creator || chat.creator) && + (requestPeerType.bot_participant == null || !requestPeerType.bot_participant || getMessagesController().isInChatCached(chat, bot) || ChatObject.canAddBotsToChat(chat)) && + (requestPeerType.has_username == null || requestPeerType.has_username == (ChatObject.getPublicUsername(chat) != null)) && + (requestPeerType.forum == null || requestPeerType.forum == ChatObject.isForum(chat)) && + (requestPeerType.user_admin_rights == null || getMessagesController().matchesAdminRights(chat, getUserConfig().getCurrentUser(), requestPeerType.user_admin_rights)) && + (requestPeerType.bot_admin_rights == null || getMessagesController().matchesAdminRights(chat, bot, requestPeerType.bot_admin_rights) || ChatObject.canAddAdmins(chat)) + ); + } + public void setSideMenu(RecyclerView recyclerView) { sideMenu = recyclerView; sideMenu.setBackgroundColor(Theme.getColor(Theme.key_chats_menuBackground)); @@ -9062,7 +9474,7 @@ public void setInitialSearchType(int type) { } private boolean checkCanWrite(final long dialogId) { - if (addToGroupAlertString == null && checkCanWrite) { + if (addToGroupAlertString == null && initialDialogsType != DIALOGS_TYPE_BOT_REQUEST_PEER && checkCanWrite) { if (DialogObject.isChatDialog(dialogId)) { TLRPC.Chat chat = getMessagesController().getChat(-dialogId); if (ChatObject.isChannel(chat) && !chat.megagroup && ((cantSendToChannels || !ChatObject.isCanWriteToChannel(-dialogId, currentAccount)) || hasPoll == 2)) { @@ -9097,7 +9509,7 @@ public void didSelectResult(final long dialogId, int topicId, boolean useAlert, if (!checkCanWrite(dialogId)) { return; } - if (initialDialogsType == 11 || initialDialogsType == 12 || initialDialogsType == 13) { + if (initialDialogsType == DIALOGS_TYPE_IMPORT_HISTORY_GROUPS || initialDialogsType == DIALOGS_TYPE_IMPORT_HISTORY_USERS || initialDialogsType == DIALOGS_TYPE_IMPORT_HISTORY) { if (checkingImportDialog) { return; } @@ -9205,12 +9617,41 @@ public void didSelectResult(final long dialogId, int topicId, boolean useAlert, builder.setPositiveButton(buttonText, (dialogInterface, i) -> didSelectResult(dialogId, topicId,false, false)); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); + } else if (initialDialogsType == DIALOGS_TYPE_BOT_REQUEST_PEER) { + Runnable send = () -> { + if (delegate != null) { + ArrayList dids = new ArrayList<>(); + dids.add(MessagesStorage.TopicKey.of(dialogId, topicId)); + delegate.didSelectDialogs(DialogsActivity.this, dids, null, param); + if (resetDelegate) { + delegate = null; + } + } else { + finishFragment(); + } + }; + Runnable checkBotRightsAndSend = () -> { + if (requestPeerType.bot_admin_rights != null) { + TLRPC.User bot = getMessagesController().getUser(requestPeerBotId); + getMessagesController().setUserAdminRole(-dialogId, bot, requestPeerType.bot_admin_rights, null, false, DialogsActivity.this, true, true, null, send, err -> { + send.run(); + return true; + }); + } else { + send.run(); + } + }; + if (dialogId < 0) { + showSendToBotAlert(getMessagesController().getChat(-dialogId), checkBotRightsAndSend, null); + } else { + showSendToBotAlert(getMessagesController().getUser(dialogId), checkBotRightsAndSend, null); + } } else { if (delegate != null) { ArrayList dids = new ArrayList<>(); dids.add(MessagesStorage.TopicKey.of(dialogId, topicId)); - delegate.didSelectDialogs(DialogsActivity.this, dids, null, param); - if (resetDelegate) { + boolean res = delegate.didSelectDialogs(DialogsActivity.this, dids, null, param); + if (res && resetDelegate) { delegate = null; } } else { @@ -9219,6 +9660,52 @@ public void didSelectResult(final long dialogId, int topicId, boolean useAlert, } } + private void showSendToBotAlert(TLRPC.User user, Runnable ok, Runnable cancel) { + TLRPC.User bot = getMessagesController().getUser(requestPeerBotId); + + showDialog( + new AlertDialog.Builder(getContext()) + .setTitle(LocaleController.formatString(R.string.AreYouSureSendChatToBotTitle, UserObject.getFirstName(user), UserObject.getFirstName(bot))) + .setMessage(TextUtils.concat( + AndroidUtilities.replaceTags(LocaleController.formatString(R.string.AreYouSureSendChatToBotMessage, UserObject.getFirstName(user), UserObject.getFirstName(bot))) + )) + .setPositiveButton(LocaleController.formatString("Send", R.string.Send), (di, p) -> ok.run()) + .setNegativeButton(LocaleController.formatString("Cancel", R.string.Cancel), (di, p) -> { + if (cancel != null) { + cancel.run(); + } + }).create() + ); + } + + private void showSendToBotAlert(TLRPC.Chat chat, Runnable ok, Runnable cancel) { + final TLRPC.User bot = getMessagesController().getUser(requestPeerBotId); + final boolean isChannel = ChatObject.isChannelAndNotMegaGroup(chat); + + showDialog( + new AlertDialog.Builder(getContext()) + .setTitle(LocaleController.formatString(R.string.AreYouSureSendChatToBotTitle, chat.title, UserObject.getFirstName(bot))) + .setMessage(TextUtils.concat( + AndroidUtilities.replaceTags(LocaleController.formatString(R.string.AreYouSureSendChatToBotMessage, chat.title, UserObject.getFirstName(bot))), + ( + requestPeerType.bot_participant != null && requestPeerType.bot_participant && !getMessagesController().isInChatCached(chat, bot) || + requestPeerType.bot_admin_rights != null + ) ? + TextUtils.concat("\n\n", AndroidUtilities.replaceTags( + (requestPeerType.bot_admin_rights == null) ? + LocaleController.formatString(R.string.AreYouSureSendChatToBotAdd, UserObject.getFirstName(bot), chat.title) : + LocaleController.formatString(R.string.AreYouSureSendChatToBotAddRights, UserObject.getFirstName(bot), chat.title, RequestPeerRequirementsCell.rightsToString(requestPeerType.bot_admin_rights, isChannel)) + )) : "" + )) + .setPositiveButton(LocaleController.formatString("Send", R.string.Send), (di, p) -> ok.run()) + .setNegativeButton(LocaleController.formatString("Cancel", R.string.Cancel), (di, p) -> { + if (cancel != null) { + cancel.run(); + } + }).create() + ); + } + public RLottieImageView getFloatingButton() { return floatingButton; } @@ -9585,6 +10072,7 @@ public ArrayList getThemeDescriptions() { arrayList.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundPink)); arrayList.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundSaved)); arrayList.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundRed)); + arrayList.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_background2Red)); arrayList.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_background2Orange)); arrayList.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_background2Violet)); arrayList.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_background2Green)); @@ -9849,6 +10337,10 @@ public ArrayList getThemeDescriptions() { }, Theme.key_actionBarActionModeDefaultIcon, Theme.key_actionBarActionModeDefaultSelector)); } + if (dialogsHintCell != null) { + SimpleThemeDescription.add(arrayList, dialogsHintCell::updateColors, Theme.key_windowBackgroundWhite, Theme.key_windowBackgroundWhiteBlackText, Theme.key_windowBackgroundWhiteGrayText); + } + return arrayList; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ExternalActionActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ExternalActionActivity.java index 8ebe4690737..76cb37b90e0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ExternalActionActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ExternalActionActivity.java @@ -215,7 +215,7 @@ private void showPasscodeActivity() { passcodeView.onShow(true, false); SharedConfig.isWaitingForPasscodeEnter = true; drawerLayoutContainer.setAllowOpenDrawer(false, false); - passcodeView.setDelegate(() -> { + passcodeView.setDelegate(view -> { SharedConfig.isWaitingForPasscodeEnter = false; if (passcodeSaveIntent != null) { handleIntent(passcodeSaveIntent, passcodeSaveIntentIsNew, passcodeSaveIntentIsRestore, true, passcodeSaveIntentAccount, passcodeSaveIntentState); @@ -226,6 +226,8 @@ private void showPasscodeActivity() { if (AndroidUtilities.isTablet()) { layersActionBarLayout.showLastFragment(); } + + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.passcodeDismissed, view); }); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/FeedWidgetConfigActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/FeedWidgetConfigActivity.java index 3556a038c5a..ef48da26f56 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/FeedWidgetConfigActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/FeedWidgetConfigActivity.java @@ -27,7 +27,7 @@ protected boolean handleIntent(Intent intent, boolean isNew, boolean restore, bo if (creatingAppWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 5); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_CHANNELS_ONLY); args.putBoolean("allowSwitchAccount", true); args.putBoolean("checkCanWrite", false); DialogsActivity fragment = new DialogsActivity(args); @@ -47,6 +47,7 @@ protected boolean handleIntent(Intent intent, boolean isNew, boolean restore, bo resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, creatingAppWidgetId); setResult(RESULT_OK, resultValue); finish(); + return true; }); if (AndroidUtilities.isTablet()) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java b/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java index 32174bb20c5..de0cec26b81 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java @@ -554,7 +554,7 @@ public void search(long dialogId, long minDate, long maxDate, FiltersView.MediaF resultArray = new ArrayList<>(); ArrayList resultArrayNames = new ArrayList<>(); ArrayList encUsers = new ArrayList<>(); - MessagesStorage.getInstance(currentAccount).localSearch(0, query, resultArray, resultArrayNames, encUsers, includeFolder ? 1 : 0); + MessagesStorage.getInstance(currentAccount).localSearch(0, query, resultArray, resultArrayNames, encUsers, null, includeFolder ? 1 : 0); } final TLRPC.TL_messages_searchGlobal req = new TLRPC.TL_messages_searchGlobal(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCallActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCallActivity.java index 0e24b2b137f..b587e67c5ba 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCallActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCallActivity.java @@ -6922,7 +6922,6 @@ public static void onLeaveClick(Context context, Runnable onLeave, boolean fromO cells[num].setChecked(!cells[num].isChecked(), true); }); - builder.setCustomViewOffset(12); builder.setView(linearLayout); builder.setDialogButtonColorKey(Theme.key_voipgroup_listeningText); builder.setPositiveButton(LocaleController.getString("VoipGroupLeave", R.string.VoipGroupLeave), (dialogInterface, position) -> processOnLeave(call, cells[0].isChecked(), selfId, onLeave)); @@ -7101,7 +7100,9 @@ private void processSelectedOption(TLRPC.TL_groupCallParticipant participant, lo if (currentAvatarUpdater != null && currentAvatarUpdater.isUploadingImage()) { return; } - currentAvatarUpdater = new ImageUpdater(true); + TLRPC.User user = accountInstance.getUserConfig().getCurrentUser(); + + currentAvatarUpdater = new ImageUpdater(true, ImageUpdater.FOR_TYPE_USER, true); currentAvatarUpdater.setOpenWithFrontfaceCamera(true); currentAvatarUpdater.setForceDarkTheme(true); currentAvatarUpdater.setSearchAvailable(true, true); @@ -7109,7 +7110,7 @@ private void processSelectedOption(TLRPC.TL_groupCallParticipant participant, lo currentAvatarUpdater.parentFragment = parentActivity.getActionBarLayout().getLastFragment(); currentAvatarUpdater.setDelegate(avatarUpdaterDelegate = new AvatarUpdaterDelegate(peerId)); - TLRPC.User user = accountInstance.getUserConfig().getCurrentUser(); + currentAvatarUpdater.openMenu(user.photo != null && user.photo.photo_big != null && !(user.photo instanceof TLRPC.TL_userProfilePhotoEmpty), () -> accountInstance.getMessagesController().deleteUserPhoto(null), dialog -> { }, 0); @@ -7454,7 +7455,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { avatarsViewPager.setHasActiveVideo(hasAttachedRenderer); avatarsViewPager.setData(peerId, true); avatarsViewPager.setCreateThumbFromParent(true); - avatarsViewPager.initIfEmpty(imageLocation, thumbLocation, true); + avatarsViewPager.initIfEmpty(null, imageLocation, thumbLocation, true); if (scrimRenderer != null) { scrimRenderer.setShowingAsScrimView(true, true); } @@ -8355,9 +8356,9 @@ private AvatarUpdaterDelegate(long peerId) { } @Override - public void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double videoStartTimestamp, String videoPath, TLRPC.PhotoSize bigSize, TLRPC.PhotoSize smallSize, boolean isVideo) { + public void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double videoStartTimestamp, String videoPath, TLRPC.PhotoSize bigSize, TLRPC.PhotoSize smallSize, boolean isVideo, TLRPC.VideoSize emojiMarkup) { AndroidUtilities.runOnUIThread(() -> { - if (photo != null || video != null) { + if (photo != null || video != null || emojiMarkup != null) { if (peerId > 0) { TLRPC.TL_photos_uploadProfilePhoto req = new TLRPC.TL_photos_uploadProfilePhoto(); if (photo != null) { @@ -8370,6 +8371,10 @@ public void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double req.video_start_ts = videoStartTimestamp; req.flags |= 4; } + if (emojiMarkup != null) { + req.video_emoji_markup = emojiMarkup; + req.flags |= 16; + } accountInstance.getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (uploadingImageLocation != null) { @@ -8439,7 +8444,7 @@ public void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double thumb = thumbLocation; } avatarsViewPager.setCreateThumbFromParent(false); - avatarsViewPager.initIfEmpty(imageLocation, thumb, true); + avatarsViewPager.initIfEmpty(null, imageLocation, thumb, true); avatar = null; avatarBig = null; AndroidUtilities.updateVisibleRows(listView); @@ -8451,7 +8456,7 @@ public void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double accountInstance.getUserConfig().saveConfig(true); })); } else { - accountInstance.getMessagesController().changeChatAvatar(-peerId, null, photo, video, videoStartTimestamp, videoPath, smallSize.location, bigSize.location, () -> { + accountInstance.getMessagesController().changeChatAvatar(-peerId, null, photo, video, emojiMarkup, videoStartTimestamp, videoPath, smallSize.location, bigSize.location, () -> { if (uploadingImageLocation != null) { avatarsViewPager.removeUploadingImage(uploadingImageLocation); uploadingImageLocation = null; @@ -8467,7 +8472,7 @@ public void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double thumb = thumbLocation; } avatarsViewPager.setCreateThumbFromParent(false); - avatarsViewPager.initIfEmpty(imageLocation, thumb, true); + avatarsViewPager.initIfEmpty(null, imageLocation, thumb, true); avatar = null; avatarBig = null; AndroidUtilities.updateVisibleRows(listView); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java index f1b4b119e94..e86de5f4494 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java @@ -727,9 +727,9 @@ public void afterTextChanged(Editable editable) { TLRPC.Chat chat = getMessagesController().getChat(channelId); AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); if (ChatObject.canAddAdmins(chat)) { - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setTitle(LocaleController.getString("AddBotAdminAlert", R.string.AddBotAdminAlert)); builder.setMessage(LocaleController.getString("AddBotAsAdmin", R.string.AddBotAsAdmin)); - builder.setPositiveButton(LocaleController.getString("MakeAdmin", R.string.MakeAdmin), (dialogInterface, i) -> { + builder.setPositiveButton(LocaleController.getString("AddAsAdmin", R.string.AddAsAdmin), (dialogInterface, i) -> { delegate2.needAddBot(user); if (editText.length() > 0) { editText.setText(null); @@ -1013,7 +1013,6 @@ private boolean onDonePressed(boolean alert) { linearLayout.addView(cells[0], LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); cells[0].setOnClickListener(v -> cells[0].setChecked(!cells[0].isChecked(), true)); - builder.setCustomViewOffset(12); builder.setView(linearLayout); } builder.setPositiveButton(LocaleController.getString("Add", R.string.Add), (dialogInterface, i) -> onAddToGroupDone(cells[0] != null && cells[0].isChecked() ? 100 : 0)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java index d4f2780e512..7dfdc44d6b8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java @@ -105,6 +105,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati private TLRPC.FileLocation avatarBig; private TLRPC.InputFile inputPhoto; private TLRPC.InputFile inputVideo; + private TLRPC.VideoSize inputEmojiMarkup; private String inputVideoPath; private double videoTimestamp; private ArrayList selectedContacts; @@ -113,6 +114,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati private ImageUpdater imageUpdater; private String nameToSet; private int chatType; + private boolean canToggleTopics; private RLottieDrawable cameraDrawable; @@ -142,6 +144,7 @@ public GroupCreateFinalActivity(Bundle args) { currentGroupCreateLocation = args.getParcelable("location"); forImport = args.getBoolean("forImport", false); nameToSet = args.getString("title", null); + canToggleTopics = args.getBoolean("canToggleTopics", true); } @Override @@ -149,7 +152,7 @@ public boolean onFragmentCreate() { NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.updateInterfaces); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.chatDidCreated); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.chatDidFailCreate); - imageUpdater = new ImageUpdater(true); + imageUpdater = new ImageUpdater(true, ImageUpdater.FOR_TYPE_GROUP, true); imageUpdater.parentFragment = this; imageUpdater.setDelegate(this); long[] contacts = getArguments().getLongArray("result"); @@ -442,7 +445,7 @@ public void invalidate(int l, int t, int r, int b) { super.invalidate(l, t, r, b); } }; - avatarImage.setRoundRadius(AndroidUtilities.dp(32)); + avatarImage.setRoundRadius(AndroidUtilities.dp(chatType == ChatObject.CHAT_TYPE_FORUM ? 16 : 32)); avatarDrawable.setInfo(5, null, null); avatarImage.setImageDrawable(avatarDrawable); avatarImage.setContentDescription(LocaleController.getString("ChoosePhoto", R.string.ChoosePhoto)); @@ -454,7 +457,7 @@ public void invalidate(int l, int t, int r, int b) { avatarOverlay = new View(context) { @Override protected void onDraw(Canvas canvas) { - if (avatarImage != null && avatarProgressView.getVisibility() == VISIBLE) { + if (avatarImage != null && avatarProgressView.getVisibility() == VISIBLE && avatarImage.getImageReceiver().hasNotThumb()) { paint.setAlpha((int) (0x55 * avatarImage.getImageReceiver().getCurrentAlpha() * avatarProgressView.getAlpha())); canvas.drawCircle(getMeasuredWidth() / 2.0f, getMeasuredHeight() / 2.0f, getMeasuredWidth() / 2.0f, paint); } @@ -468,6 +471,7 @@ protected void onDraw(Canvas canvas) { inputPhoto = null; inputVideo = null; inputVideoPath = null; + inputEmojiMarkup = null; videoTimestamp = 0; showAvatarProgress(false, true); avatarImage.setImage(null, null, avatarDrawable, null); @@ -523,7 +527,7 @@ public void setAlpha(float alpha) { showAvatarProgress(false, false); editText = new EditTextEmoji(context, sizeNotifierFrameLayout, this, EditTextEmoji.STYLE_FRAGMENT, false); - editText.setHint(chatType == ChatObject.CHAT_TYPE_CHAT || chatType == ChatObject.CHAT_TYPE_MEGAGROUP ? LocaleController.getString("EnterGroupNamePlaceholder", R.string.EnterGroupNamePlaceholder) : LocaleController.getString("EnterListName", R.string.EnterListName)); + editText.setHint(chatType == ChatObject.CHAT_TYPE_CHAT || chatType == ChatObject.CHAT_TYPE_MEGAGROUP || chatType == ChatObject.CHAT_TYPE_FORUM ? LocaleController.getString("EnterGroupNamePlaceholder", R.string.EnterGroupNamePlaceholder) : LocaleController.getString("EnterListName", R.string.EnterListName)); if (nameToSet != null) { editText.setText(nameToSet); nameToSet = null; @@ -563,7 +567,7 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { }); presentFragment(fragment); } - if (view instanceof TextCell) { + if (view instanceof TextCell && chatType != ChatObject.CHAT_TYPE_FORUM) { if (popupWindow != null && popupWindow.isShowing()) { return; } @@ -682,11 +686,12 @@ public void didStartUpload(boolean isVideo) { } @Override - public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile video, double videoStartTimestamp, String videoPath, final TLRPC.PhotoSize bigSize, final TLRPC.PhotoSize smallSize, boolean isVideo) { + public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile video, double videoStartTimestamp, String videoPath, final TLRPC.PhotoSize bigSize, final TLRPC.PhotoSize smallSize, boolean isVideo, TLRPC.VideoSize emojiMarkup) { AndroidUtilities.runOnUIThread(() -> { - if (photo != null || video != null) { + if (photo != null || video != null || emojiMarkup != null) { inputPhoto = photo; inputVideo = video; + inputEmojiMarkup = emojiMarkup; inputVideoPath = videoPath; videoTimestamp = videoStartTimestamp; if (createAfterUpload) { @@ -850,8 +855,8 @@ public void didReceivedNotification(int id, int account, Object... args) { args2.putBoolean("just_created_chat", true); presentFragment(new ChatActivity(args2), true); } - if (inputPhoto != null || inputVideo != null) { - getMessagesController().changeChatAvatar(chatId, null, inputPhoto, inputVideo, videoTimestamp, inputVideoPath, avatar, avatarBig, null); + if (inputPhoto != null || inputVideo != null || inputEmojiMarkup != null) { + getMessagesController().changeChatAvatar(chatId, null, inputPhoto, inputVideo, inputEmojiMarkup, videoTimestamp, inputVideoPath, avatar, avatarBig, null); } } } @@ -919,6 +924,7 @@ public class GroupCreateAdapter extends RecyclerListView.SelectionAdapter { private final static int VIEW_TYPE_TEXT_SETTINGS = 3; private final static int VIEW_TYPE_AUTO_DELETE = 4; private final static int VIEW_TYPE_TEXT_INFO_CELL = 5; + private final static int VIEW_TYPE_TOPICS = 6; ArrayList items = new ArrayList<>(); @@ -930,8 +936,13 @@ public GroupCreateAdapter(Context ctx) { public void notifyDataSetChanged() { items.clear(); items.add(new InnerItem(VIEW_TYPE_SHADOW_SECTION_CELL)); - items.add(new InnerItem(VIEW_TYPE_AUTO_DELETE)); - items.add(new InnerItem(VIEW_TYPE_TEXT_INFO_CELL, LocaleController.getString("GroupCreateAutodeleteDescription", R.string.GroupCreateAutodeleteDescription))); + if (chatType == ChatObject.CHAT_TYPE_FORUM) { + items.add(new InnerItem(VIEW_TYPE_TOPICS)); + items.add(new InnerItem(VIEW_TYPE_TEXT_INFO_CELL, LocaleController.getString("ForumToggleDescription", R.string.ForumToggleDescription))); + } else { + items.add(new InnerItem(VIEW_TYPE_AUTO_DELETE)); + items.add(new InnerItem(VIEW_TYPE_TEXT_INFO_CELL, LocaleController.getString("GroupCreateAutodeleteDescription", R.string.GroupCreateAutodeleteDescription))); + } if (currentGroupCreateAddress != null) { items.add(new InnerItem(VIEW_TYPE_HEADER_CELL)); items.add(new InnerItem(VIEW_TYPE_TEXT_SETTINGS)); @@ -953,7 +964,7 @@ public int getItemCount() { @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { - return holder.getItemViewType() == VIEW_TYPE_TEXT_SETTINGS || holder.getItemViewType() == VIEW_TYPE_AUTO_DELETE; + return holder.getItemViewType() == VIEW_TYPE_TEXT_SETTINGS || holder.getItemViewType() == VIEW_TYPE_AUTO_DELETE || holder.getItemViewType() == VIEW_TYPE_TOPICS && canToggleTopics; } @Override @@ -986,6 +997,9 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType combinedDrawable.setFullsize(true); view.setBackgroundDrawable(combinedDrawable); break; + case VIEW_TYPE_TOPICS: + view = new TextCell(context, 23, false, true, getResourceProvider()); + break; case 3: default: view = new TextSettingsCell(context); @@ -1029,6 +1043,12 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { textCell.setTextAndValueAndIcon(LocaleController.getString("AutoDeleteMessages", R.string.AutoDeleteMessages), value, fragmentBeginToShow, R.drawable.msg_autodelete, false); break; } + case VIEW_TYPE_TOPICS: { + TextCell textCell = (TextCell) holder.itemView; + textCell.setTextAndCheckAndIcon(LocaleController.getString("ChannelTopics", R.string.ChannelTopics), true, R.drawable.msg_topics, false); + textCell.getCheckBox().setAlpha(.75f); + break; + } case VIEW_TYPE_TEXT_INFO_CELL: TextInfoPrivacyCell textInfoPrivacyCell = (TextInfoPrivacyCell) holder.itemView; textInfoPrivacyCell.setText(items.get(position).string); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/KeepMediaPopupView.java b/TMessagesProj/src/main/java/org/telegram/ui/KeepMediaPopupView.java index 2abe5c21d50..adf114f6c3e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/KeepMediaPopupView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/KeepMediaPopupView.java @@ -90,11 +90,11 @@ public KeepMediaPopupView(BaseFragment baseFragment, Context context) { args.putBoolean("onlySelect", true); args.putBoolean("checkCanWrite", false); if (currentType == CacheControlActivity.KEEP_MEDIA_TYPE_GROUP) { - args.putInt("dialogsType", 6); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_GROUPS_ONLY); } else if (currentType == CacheControlActivity.KEEP_MEDIA_TYPE_CHANNEL) { - args.putInt("dialogsType", 5); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_CHANNELS_ONLY); } else { - args.putInt("dialogsType", 4); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_USERS_ONLY); } args.putBoolean("allowGlobalSearch", false); DialogsActivity activity = new DialogsActivity(args); @@ -120,6 +120,7 @@ public void onTransitionAnimationEnd(boolean isOpen, boolean backward) { cacheChatsExceptionsFragment.setExceptions(exceptions); parentFragment.presentFragment(cacheChatsExceptionsFragment); AndroidUtilities.runOnUIThread(() -> cacheChatsExceptionsFragment.showPopupFor(finalNewException), 150); + return true; }); baseFragment.presentFragment(activity); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java index ef62e44d969..30acc549bc7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java @@ -16,6 +16,7 @@ import android.content.SharedPreferences; import android.content.res.Configuration; import android.graphics.Canvas; +import android.graphics.drawable.Drawable; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; @@ -35,6 +36,7 @@ import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.TranslateController; import org.telegram.messenger.Utilities; import org.telegram.tgnet.ConnectionsManager; import org.telegram.ui.ActionBar.ActionBar; @@ -54,12 +56,15 @@ import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.EmptyTextProgressView; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.TranslateAlert2; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; +import java.util.Iterator; import java.util.Timer; public class LanguageSelectActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { @@ -188,18 +193,50 @@ protected void onMoveAnimationUpdate(RecyclerView.ViewHolder holder) { } }; itemAnimator.setDurations(400); + itemAnimator.setDelayAnimations(false); itemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); listView.setItemAnimator(itemAnimator); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); listView.setOnItemClickListener((view, position) -> { try { + if (view instanceof TextCheckCell) { + final boolean prevFullValue = getContextValue() || getChatValue(); + if (position == 1) { + boolean value = !getContextValue(); + getMessagesController().getTranslateController().setContextTranslateEnabled(value); + ((TextCheckCell) view).setChecked(value); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateSearchSettings); + } else if (position == 2) { + boolean value = !getChatValue(); + if (value && !getUserConfig().isPremium()) { + showDialog(new PremiumFeatureBottomSheet(LanguageSelectActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_TRANSLATIONS, false)); + return; + } + MessagesController.getMainSettings(currentAccount).edit().putBoolean("translate_chat_button", value).apply(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateSearchSettings); + ((TextCheckCell) view).setChecked(value); + } + final boolean currentFullValue = getContextValue() || getChatValue(); + if (currentFullValue != prevFullValue) { + listAdapter.notifyItemChanged(2); + if (currentFullValue) { + listAdapter.notifyItemInserted(3); + } else { + listAdapter.notifyItemRemoved(3); + } + } + return; + } else if (view instanceof TextSettingsCell) { + presentFragment(new RestrictedLanguagesSelectActivity()); + return; + } if (getParentActivity() == null || parentLayout == null || !(view instanceof TextRadioCell)) { return; } boolean search = listView.getAdapter() == searchListViewAdapter; if (!search) { - position -= 2; + position -= (getChatValue() || getContextValue()) ? 7 : 6; } LocaleController.LocaleInfo localeInfo; if (search) { @@ -236,16 +273,19 @@ protected void onMoveAnimationUpdate(RecyclerView.ViewHolder holder) { HashSet selectedLanguages = RestrictedLanguagesSelectActivity.getRestrictedLanguages(); HashSet newSelectedLanguages = new HashSet(selectedLanguages); - if (selectedLanguages.contains(langCode)) { - newSelectedLanguages.removeIf(s -> s != null && s.equals(langCode)); - if (!selectedLanguages.contains(prevLangCode)) - newSelectedLanguages.add(prevLangCode); + if (selectedLanguages.contains(prevLangCode) && !selectedLanguages.contains(langCode)) { + newSelectedLanguages.removeIf(s -> s != null && s.equals(prevLangCode)); + newSelectedLanguages.add(langCode); } preferences.edit().putStringSet("translate_button_restricted_languages", newSelectedLanguages).apply(); + MessagesController.getInstance(currentAccount).getTranslateController().checkRestrictedLanguagesUpdate(); + MessagesController.getInstance(currentAccount).getTranslateController().cleanup(); if (!sameLang) { progressDialog.showDelayed(500); } + + TranslateController.invalidateSuggestedLanguageCodes(); } } catch (Exception e) { FileLog.e(e); @@ -259,7 +299,7 @@ protected void onMoveAnimationUpdate(RecyclerView.ViewHolder holder) { } boolean search = listView.getAdapter() == searchListViewAdapter; if (!search) { - position -= 2; + position -= (getChatValue() || getContextValue()) ? 7 : 6; } LocaleController.LocaleInfo localeInfo; if (search) { @@ -459,24 +499,28 @@ private class TranslateSettings extends LinearLayout { private HeaderCell header; private TextCheckCell showButtonCheck; + private TextCheckCell showChatButtonCheck; private TextSettingsCell doNotTranslateCell; private TextInfoPrivacyCell info; private TextInfoPrivacyCell info2; private ValueAnimator doNotTranslateCellAnimation = null; // private HeaderCell header2; - private SharedPreferences.OnSharedPreferenceChangeListener listener; - // private float HEIGHT_OPEN = 243; // private float HEIGHT_CLOSED = HEIGHT_OPEN - 50; + private Drawable topShadow, bottomShadow; + public TranslateSettings(Context context) { super(context); setFocusable(false); setOrientation(VERTICAL); - preferences = MessagesController.getGlobalMainSettings(); + topShadow = Theme.getThemedDrawable(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow); + bottomShadow = Theme.getThemedDrawable(context, R.drawable.greydivider_top, Theme.key_windowBackgroundGrayShadow); + + preferences = MessagesController.getMainSettings(currentAccount); header = new HeaderCell(context); header.setFocusable(true); @@ -485,20 +529,41 @@ public TranslateSettings(Context context) { header.setContentDescription(LocaleController.getString("TranslateMessages", R.string.TranslateMessages)); addView(header, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - boolean value = getValue(); + final boolean value = getValue(); + showButtonCheck = new TextCheckCell(context); showButtonCheck.setBackground(Theme.createSelectorWithBackgroundDrawable(Theme.getColor(Theme.key_windowBackgroundWhite), Theme.getColor(Theme.key_listSelector))); showButtonCheck.setTextAndCheck( LocaleController.getString("ShowTranslateButton", R.string.ShowTranslateButton), - value, - value + getContextValue(), + true ); showButtonCheck.setOnClickListener(e -> { - preferences.edit().putBoolean("translate_button", !getValue()).apply(); + getMessagesController().getTranslateController().setContextTranslateEnabled(!getContextValue()); NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateSearchSettings); + update(); }); addView(showButtonCheck, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + showChatButtonCheck = new TextCheckCell(context); + showChatButtonCheck.setBackground(Theme.createSelectorWithBackgroundDrawable(Theme.getColor(Theme.key_windowBackgroundWhite), Theme.getColor(Theme.key_listSelector))); + showChatButtonCheck.setTextAndCheck( + LocaleController.getString("ShowTranslateChatButton", R.string.ShowTranslateChatButton), + getChatValue(), + value + ); + showChatButtonCheck.setOnClickListener(e -> { + if (!getUserConfig().isPremium()) { + showDialog(new PremiumFeatureBottomSheet(LanguageSelectActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_TRANSLATIONS, false)); + return; + } + MessagesController.getMainSettings(currentAccount).edit().putBoolean("translate_chat_button", !getChatValue()).apply(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateSearchSettings); + update(); + }); + showChatButtonCheck.setCheckBoxIcon(!getUserConfig().isPremium() ? R.drawable.permission_locked : 0); + addView(showChatButtonCheck, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + doNotTranslateCell = new TextSettingsCell(context); doNotTranslateCell.setBackground(Theme.createSelectorWithBackgroundDrawable(Theme.getColor(Theme.key_windowBackgroundWhite), Theme.getColor(Theme.key_listSelector))); doNotTranslateCell.setOnClickListener(e -> { @@ -537,11 +602,28 @@ public TranslateSettings(Context context) { update(); } + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + + float topShadowY = Math.max(showChatButtonCheck.getY() + showChatButtonCheck.getHeight(), doNotTranslateCell.getY() + doNotTranslateCell.getHeight() * doNotTranslateCell.getAlpha()); + topShadow.setBounds(0, (int) topShadowY, getWidth(), (int) (topShadowY + AndroidUtilities.dp(12))); + topShadow.draw(canvas); + + float bottomShadowY = getHeight(); + bottomShadow.setBounds(0, (int) (bottomShadowY - AndroidUtilities.dp(12)), getWidth(), (int) bottomShadowY); + bottomShadow.draw(canvas); + } + public void updateTranslations() { header.setText(LocaleController.getString("TranslateMessages", R.string.TranslateMessages)); showButtonCheck.setTextAndCheck( - LocaleController.getString("ShowTranslateButton", R.string.ShowTranslateButton), getValue(), getValue() + LocaleController.getString("ShowTranslateButton", R.string.ShowTranslateButton), getContextValue(), true ); + showChatButtonCheck.setTextAndCheck( + LocaleController.getString("ShowTranslateChatButton", R.string.ShowTranslateChatButton), getChatValue(), getValue() + ); + showChatButtonCheck.setCheckBoxIcon(!getUserConfig().isPremium() ? R.drawable.permission_locked : 0); showButtonCheck.updateRTL(); doNotTranslateCell.updateRTL(); info.setText(LocaleController.getString("TranslateMessagesInfo1", R.string.TranslateMessagesInfo1)); @@ -553,36 +635,48 @@ public void updateTranslations() { } private boolean getValue() { - return preferences.getBoolean("translate_button", false); - } - private ArrayList getRestrictedLanguages() { - String currentLang = LocaleController.getInstance().getCurrentLocaleInfo().pluralLangCode; - ArrayList langCodes = new ArrayList<>(RestrictedLanguagesSelectActivity.getRestrictedLanguages()); - if (!langCodes.contains(currentLang)) - langCodes.add(currentLang); - return langCodes; + return getContextValue() || getChatValue(); } public void update() { boolean value = getValue() && LanguageDetector.hasSupport(); - showButtonCheck.setChecked(getValue()); + showButtonCheck.setChecked(getContextValue()); + showChatButtonCheck.setChecked(getChatValue()); if (doNotTranslateCellAnimation != null) { doNotTranslateCellAnimation.cancel(); } - showButtonCheck.setDivider(value); - ArrayList langCodes = getRestrictedLanguages(); + showChatButtonCheck.setDivider(value); + HashSet langCodes = RestrictedLanguagesSelectActivity.getRestrictedLanguages(); + final String doNotTranslateCellName = LocaleController.getString("DoNotTranslate", R.string.DoNotTranslate); String doNotTranslateCellValue = null; - if (langCodes.size() == 1) { - try { - doNotTranslateCellValue = LocaleController.getInstance().getLanguageFromDict(langCodes.get(0)).name; - } catch (Exception e) {} - } + try { + if (langCodes.size() == 1) { + doNotTranslateCellValue = TranslateAlert2.capitalFirst(TranslateAlert2.languageName(langCodes.iterator().next())); + } else { + Iterator iterator = langCodes.iterator(); + boolean first = true; + StringBuilder string = new StringBuilder(); + while (iterator.hasNext()) { + String lang = iterator.next(); + if (!first) { + string.append(", "); + } + string.append(TranslateAlert2.capitalFirst(TranslateAlert2.languageName(lang))); + first = false; + } + doNotTranslateCellValue = string.toString(); + if (doNotTranslateCell.getValueTextView().getPaint().measureText(doNotTranslateCellValue) > + Math.min((AndroidUtilities.displaySize.x - AndroidUtilities.dp(34)) / 2f, AndroidUtilities.displaySize.x - AndroidUtilities.dp(21 * 4) - doNotTranslateCell.getTextView().getPaint().measureText(doNotTranslateCellName))) { + doNotTranslateCellValue = null; + } + } + } catch (Exception ignore) {} if (doNotTranslateCellValue == null) - doNotTranslateCellValue = String.format(LocaleController.getPluralString("Languages", getRestrictedLanguages().size()), getRestrictedLanguages().size()); - doNotTranslateCell.setTextAndValue(LocaleController.getString("DoNotTranslate", R.string.DoNotTranslate), doNotTranslateCellValue, false); + doNotTranslateCellValue = String.format(LocaleController.getPluralString("Languages", langCodes.size()), langCodes.size()); + doNotTranslateCell.setTextAndValue(doNotTranslateCellName, doNotTranslateCellValue, false, false); doNotTranslateCell.setClickable(value); info2.setVisibility(View.VISIBLE); @@ -593,10 +687,12 @@ public void update() { doNotTranslateCell.setAlpha(t); doNotTranslateCell.setTranslationY(-AndroidUtilities.dp(8) * (1f - t)); info.setTranslationY(-doNotTranslateCell.getHeight() * (1f - t)); + t = 1f; info2.setAlpha(1f - t); info2.setTranslationY(-doNotTranslateCell.getHeight() * (1f - t)); translateSettingsBackgroundHeight = header.getMeasuredHeight() + showButtonCheck.getMeasuredHeight() + (int) (doNotTranslateCell.getAlpha() * doNotTranslateCell.getMeasuredHeight()); + invalidate(); }); doNotTranslateCellAnimation.addListener(new AnimatorListenerAdapter() { @Override @@ -609,6 +705,7 @@ public void onAnimationEnd(Animator animation) { } translateSettingsBackgroundHeight = header.getMeasuredHeight() + showButtonCheck.getMeasuredHeight() + (int) (doNotTranslateCell.getAlpha() * doNotTranslateCell.getMeasuredHeight()); + invalidate(); } }); doNotTranslateCellAnimation.setDuration((long) (Math.abs(doNotTranslateCell.getAlpha() - (value ? 1f : 0f)) * 200)); @@ -631,6 +728,7 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { void updateHeight() { header.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x, MeasureSpec.EXACTLY), MeasureSpec.UNSPECIFIED); showButtonCheck.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x, MeasureSpec.EXACTLY), MeasureSpec.UNSPECIFIED); + showChatButtonCheck.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x, MeasureSpec.EXACTLY), MeasureSpec.UNSPECIFIED); doNotTranslateCell.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x, MeasureSpec.EXACTLY), MeasureSpec.UNSPECIFIED); info.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x, MeasureSpec.EXACTLY), MeasureSpec.UNSPECIFIED); info2.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x, MeasureSpec.EXACTLY), MeasureSpec.UNSPECIFIED); @@ -643,11 +741,13 @@ void updateHeight() { lp.height = newHeight; setLayoutParams(lp); } + invalidate(); } int height() { return Math.max(AndroidUtilities.dp(40), header.getMeasuredHeight()) + Math.max(AndroidUtilities.dp(50), showButtonCheck.getMeasuredHeight()) + + Math.max(AndroidUtilities.dp(50), showChatButtonCheck.getMeasuredHeight()) + Math.max(Math.max(AndroidUtilities.dp(50), doNotTranslateCell.getMeasuredHeight()), (info2.getMeasuredHeight() <= 0 ? AndroidUtilities.dp(51) : info2.getMeasuredHeight())) + (info.getMeasuredHeight() <= 0 ? AndroidUtilities.dp(62) : info.getMeasuredHeight());/* + header2.getHeight()*/ } @@ -662,23 +762,25 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { protected void onAttachedToWindow() { super.onAttachedToWindow(); update(); - preferences.registerOnSharedPreferenceChangeListener(listener = new SharedPreferences.OnSharedPreferenceChangeListener() { - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { - preferences = sharedPreferences; - update(); - } - }); updateHeight(); } + } - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - preferences.unregisterOnSharedPreferenceChangeListener(listener); - } + private boolean getContextValue() { + return getMessagesController().getTranslateController().isContextTranslateEnabled(); + } + + private boolean getChatValue() { + return getMessagesController().getTranslateController().isFeatureAvailable(); } + public static final int VIEW_TYPE_LANGUAGE = 0; + public static final int VIEW_TYPE_SHADOW = 1; + public static final int VIEW_TYPE_SWITCH = 2; + public static final int VIEW_TYPE_HEADER = 3; + public static final int VIEW_TYPE_SETTINGS = 4; + public static final int VIEW_TYPE_INFO = 5; + private class ListAdapter extends RecyclerListView.SelectionAdapter { private Context mContext; @@ -691,7 +793,8 @@ public ListAdapter(Context context, boolean isSearch) { @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { - return holder.getItemViewType() == 0; + final int viewType = holder.getItemViewType(); + return viewType == VIEW_TYPE_LANGUAGE || viewType == VIEW_TYPE_SETTINGS || viewType == VIEW_TYPE_SWITCH; } @Override @@ -709,7 +812,7 @@ public int getItemCount() { if (!unofficialLanguages.isEmpty()) { count += unofficialLanguages.size() + 1; } - return 2 + count; + return 5 + (getChatValue() || getContextValue() ? 1 : 0) + 1 + count; } } @@ -717,22 +820,31 @@ public int getItemCount() { public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view; switch (viewType) { - case 0: { -// view = new LanguageCell(mContext, false); + case VIEW_TYPE_LANGUAGE: { view = new TextRadioCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; } - case 2: - TranslateSettings translateSettings = new TranslateSettings(mContext); - view = translateSettings; + case VIEW_TYPE_SWITCH: + TextCheckCell switchCell = new TextCheckCell(mContext); + switchCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + view = switchCell; + break; + case VIEW_TYPE_SETTINGS: + TextSettingsCell settingsCell = new TextSettingsCell(mContext); + settingsCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + view = settingsCell; break; - case 3: + case VIEW_TYPE_HEADER: HeaderCell header = new HeaderCell(mContext); header.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); view = header; break; - case 1: + case VIEW_TYPE_INFO: + TextInfoPrivacyCell infoCell = new TextInfoPrivacyCell(mContext); + view = infoCell; + break; + case VIEW_TYPE_SHADOW: default: { view = new ShadowSectionCell(mContext); break; @@ -744,9 +856,9 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { - case 0: { + case VIEW_TYPE_LANGUAGE: { if (!search) { - position -= 2; + position -= (getChatValue() || getContextValue()) ? 7 : 6; } TextRadioCell textSettingsCell = (TextRadioCell) holder.itemView; LocaleController.LocaleInfo localeInfo = null; @@ -778,7 +890,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { textSettingsCell.setChecked(localeInfo == LocaleController.getInstance().getCurrentLocaleInfo()); break; } - case 1: { + case VIEW_TYPE_SHADOW: { if (!search) position--; ShadowSectionCell sectionCell = (ShadowSectionCell) holder.itemView; @@ -789,15 +901,66 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } break; } - case 2: { - TranslateSettings translateSettings = (TranslateSettings) holder.itemView; - translateSettings.setVisibility(searching ? View.GONE : View.VISIBLE); - translateSettings.updateTranslations(); + case VIEW_TYPE_SETTINGS: { + TextSettingsCell settingsCell = (TextSettingsCell) holder.itemView; + HashSet langCodes = RestrictedLanguagesSelectActivity.getRestrictedLanguages(); + final String doNotTranslateCellName = LocaleController.getString("DoNotTranslate", R.string.DoNotTranslate); + String doNotTranslateCellValue = null; + try { + if (langCodes.size() == 1) { + doNotTranslateCellValue = TranslateAlert2.capitalFirst(TranslateAlert2.languageName(langCodes.iterator().next())); + } else { + Iterator iterator = langCodes.iterator(); + boolean first = true; + StringBuilder string = new StringBuilder(); + while (iterator.hasNext()) { + String lang = iterator.next(); + if (!first) { + string.append(", "); + } + string.append(TranslateAlert2.capitalFirst(TranslateAlert2.languageName(lang))); + first = false; + } + doNotTranslateCellValue = string.toString(); + if (settingsCell.getValueTextView().getPaint().measureText(doNotTranslateCellValue) > Math.min((AndroidUtilities.displaySize.x - AndroidUtilities.dp(34)) / 2f, AndroidUtilities.displaySize.x - AndroidUtilities.dp(21 * 4) - settingsCell.getTextView().getPaint().measureText(doNotTranslateCellName))) { + doNotTranslateCellValue = null; + } + } + } catch (Exception ignore) {} + if (doNotTranslateCellValue == null) { + doNotTranslateCellValue = String.format(LocaleController.getPluralString("Languages", langCodes.size()), langCodes.size()); + } + settingsCell.setTextAndValue(doNotTranslateCellName, doNotTranslateCellValue, true, false); + break; + } + case VIEW_TYPE_SWITCH: { + TextCheckCell cell = (TextCheckCell) holder.itemView; + if (position == 1) { + cell.setTextAndCheck(LocaleController.getString("ShowTranslateButton", R.string.ShowTranslateButton), getContextValue(), true); + } else if (position == 2) { + cell.setTextAndCheck(LocaleController.getString("ShowTranslateChatButton", R.string.ShowTranslateChatButton), getChatValue(), getContextValue() || getChatValue()); + cell.setCheckBoxIcon(!getUserConfig().isPremium() ? R.drawable.permission_locked : 0); + } break; } - case 3: { + case VIEW_TYPE_INFO: { + TextInfoPrivacyCell infoCell = (TextInfoPrivacyCell) holder.itemView; + if (position == (getContextValue() || getChatValue() ? 4 : 3)) { + infoCell.setText(LocaleController.getString("TranslateMessagesInfo1", R.string.TranslateMessagesInfo1)); + infoCell.setBackground(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + infoCell.setTopPadding(11); + infoCell.setBottomPadding(16); + } else { + infoCell.setTopPadding(0); + infoCell.setBottomPadding(16); + infoCell.setText(LocaleController.getString("TranslateMessagesInfo2", R.string.TranslateMessagesInfo2)); + infoCell.setBackground(Theme.getThemedDrawable(mContext, R.drawable.greydivider_top, Theme.key_windowBackgroundGrayShadow)); + } + break; + } + case VIEW_TYPE_HEADER: { HeaderCell header = (HeaderCell) holder.itemView; - header.setText(LocaleController.getString("Language", R.string.Language)); + header.setText(position == 0 ? LocaleController.getString("TranslateMessages", R.string.TranslateMessages) : LocaleController.getString("Language", R.string.Language)); break; } } @@ -805,19 +968,23 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { @Override public int getItemViewType(int i) { - if (!search) - i -= 2; - if (i == -2) - return 2; - if (i == -1) - return 3; if (search) { - return 0; - } - if (!unofficialLanguages.isEmpty() && (i == unofficialLanguages.size() || i == unofficialLanguages.size() + sortedLanguages.size() + 1) || unofficialLanguages.isEmpty() && i == sortedLanguages.size()) { - return 1; + return VIEW_TYPE_LANGUAGE; + } else { + if (i-- == 0) return VIEW_TYPE_HEADER; + if (i-- == 0) return VIEW_TYPE_SWITCH; + if (i-- == 0) return VIEW_TYPE_SWITCH; + if (getChatValue() || getContextValue()) { + if (i-- == 0) return VIEW_TYPE_SETTINGS; + } + if (i-- == 0) return VIEW_TYPE_INFO; + if (i-- == 0) return VIEW_TYPE_INFO; + if (i-- == 0) return VIEW_TYPE_HEADER; + if (!unofficialLanguages.isEmpty() && (i == unofficialLanguages.size() || i == unofficialLanguages.size() + 1 + sortedLanguages.size() + 1) || unofficialLanguages.isEmpty() && i == sortedLanguages.size()) { + return VIEW_TYPE_SHADOW; + } + return VIEW_TYPE_LANGUAGE; } - return 0; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index 842e2bcf9a0..4f5294557d6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -44,8 +44,13 @@ import android.os.SystemClock; import android.provider.ContactsContract; import android.provider.Settings; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.TextPaint; import android.text.TextUtils; +import android.text.style.ClickableSpan; import android.util.Base64; +import android.util.Log; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.TypedValue; @@ -83,6 +88,7 @@ import com.google.firebase.appindexing.FirebaseUserActions; import com.google.firebase.appindexing.builders.AssistActionBuilder; +import org.telegram.messenger.BackupAgent; import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; @@ -238,6 +244,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati public DrawerLayoutContainer drawerLayoutContainer; private DrawerLayoutAdapter drawerLayoutAdapter; private PasscodeView passcodeView; + private List overlayPasscodeViews = new ArrayList<>(); private TermsOfServiceView termsOfServiceView; private BlockingUpdateView blockingUpdateView; private AlertDialog visibleDialog; @@ -294,6 +301,8 @@ public void accept(Boolean aBoolean) { } }; + public static LaunchActivity instance; + @Override protected void onCreate(Bundle savedInstanceState) { if (BuildVars.DEBUG_VERSION) { @@ -301,6 +310,7 @@ protected void onCreate(Bundle savedInstanceState) { .detectLeakedClosableObjects() .build()); } + instance = this; ApplicationLoader.postInitApplication(); AndroidUtilities.checkDisplaySize(this, getResources().getConfiguration()); currentAccount = UserConfig.selectedAccount; @@ -860,7 +870,7 @@ public void onPreviewOpenAnimationEnd() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); - if (am.isBackgroundRestricted() && System.currentTimeMillis() - SharedConfig.BackgroundActivityPrefs.getLastCheckedBackgroundActivity() >= 86400000L) { + if (am.isBackgroundRestricted() && System.currentTimeMillis() - SharedConfig.BackgroundActivityPrefs.getLastCheckedBackgroundActivity() >= 86400000L && SharedConfig.BackgroundActivityPrefs.getDismissedCount() < 3) { AlertsCreator.createBackgroundActivityDialog(this).show(); SharedConfig.BackgroundActivityPrefs.setLastCheckedBackgroundActivity(System.currentTimeMillis()); } @@ -879,6 +889,9 @@ public void onViewDetachedFromWindow(View v) { } }); } + BackupAgent.requestBackup(this); + + RestrictedLanguagesSelectActivity.checkRestrictedLanguages(false); } @Override @@ -1112,22 +1125,20 @@ public void onSettings() { @Override protected void onEmojiSelected(View emojiView, Long documentId, TLRPC.Document document, Integer until) { - TLRPC.TL_account_updateEmojiStatus req = new TLRPC.TL_account_updateEmojiStatus(); + TLRPC.EmojiStatus emojiStatus; if (documentId == null) { - req.emoji_status = new TLRPC.TL_emojiStatusEmpty(); + emojiStatus = new TLRPC.TL_emojiStatusEmpty(); } else if (until != null) { - req.emoji_status = new TLRPC.TL_emojiStatusUntil(); - ((TLRPC.TL_emojiStatusUntil) req.emoji_status).document_id = documentId; - ((TLRPC.TL_emojiStatusUntil) req.emoji_status).until = until; + emojiStatus = new TLRPC.TL_emojiStatusUntil(); + ((TLRPC.TL_emojiStatusUntil) emojiStatus).document_id = documentId; + ((TLRPC.TL_emojiStatusUntil) emojiStatus).until = until; } else { - req.emoji_status = new TLRPC.TL_emojiStatus(); - ((TLRPC.TL_emojiStatus) req.emoji_status).document_id = documentId; + emojiStatus = new TLRPC.TL_emojiStatus(); + ((TLRPC.TL_emojiStatus) emojiStatus).document_id = documentId; } - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); + MessagesController.getInstance(currentAccount).updateEmojiStatus(emojiStatus); + TLRPC.User user = UserConfig.getInstance(currentAccount).getCurrentUser(); if (user != null) { - user.emoji_status = req.emoji_status; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userEmojiStatusUpdated, user); - MessagesController.getInstance(currentAccount).updateEmojiStatusUntilUpdate(user.id, user.emoji_status); for (int i = 0; i < sideMenu.getChildCount(); ++i) { View child = sideMenu.getChildAt(i); if (child instanceof DrawerUserCell) { @@ -1154,11 +1165,6 @@ protected void onEmojiSelected(View emojiView, Long documentId, TLRPC.Document d } } } - ConnectionsManager.getInstance(currentAccount).sendRequest(req, (res, err) -> { - if (!(res instanceof TLRPC.TL_boolTrue)) { - // TODO: reject - } - }); if (popup[0] != null) { selectAnimatedEmojiDialog = null; popup[0].dismiss(); @@ -1318,6 +1324,7 @@ private void switchToAvailableAccountOrLogout() { if (drawerLayoutAdapter != null) { drawerLayoutAdapter.notifyDataSetChanged(); } + RestrictedLanguagesSelectActivity.checkRestrictedLanguages(true); clearFragments(); actionBarLayout.rebuildLogout(); if (AndroidUtilities.isTablet()) { @@ -1519,7 +1526,7 @@ public void showPasscodeActivity(boolean fingerprint, boolean animated, int x, i if (messageObject != null && messageObject.isRoundVideo()) { MediaController.getInstance().cleanupPlayer(true, true); } - passcodeView.onShow(fingerprint, animated, x, y, () -> { + passcodeView.onShow(overlayPasscodeViews.isEmpty() && fingerprint, animated, x, y, () -> { actionBarLayout.getView().setVisibility(View.INVISIBLE); if (AndroidUtilities.isTablet()) { if (layersActionBarLayout != null && layersActionBarLayout.getView() != null && layersActionBarLayout.getView().getVisibility() == View.VISIBLE) { @@ -1533,9 +1540,13 @@ public void showPasscodeActivity(boolean fingerprint, boolean animated, int x, i onShow.run(); } }, onStart); + for (int i = 0; i < overlayPasscodeViews.size(); i++) { + PasscodeView overlay = overlayPasscodeViews.get(i); + overlay.onShow(fingerprint && i == overlayPasscodeViews.size() - 1, animated, x, y, null, null); + } SharedConfig.isWaitingForPasscodeEnter = true; drawerLayoutContainer.setAllowOpenDrawer(false, false); - passcodeView.setDelegate(() -> { + PasscodeView.PasscodeViewDelegate delegate = view -> { SharedConfig.isWaitingForPasscodeEnter = false; if (passcodeSaveIntent != null) { handleIntent(passcodeSaveIntent, passcodeSaveIntentIsNew, passcodeSaveIntentIsRestore, true); @@ -1552,7 +1563,16 @@ public void showPasscodeActivity(boolean fingerprint, boolean animated, int x, i } rightActionBarLayout.getView().setVisibility(View.VISIBLE); } - }); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.passcodeDismissed, view); + }; + passcodeView.setDelegate(delegate); + for (PasscodeView overlay : overlayPasscodeViews) { + overlay.setDelegate(delegate); + } + } + + public boolean allowShowFingerprintDialog(PasscodeView passcodeView) { + return overlayPasscodeViews.isEmpty() ? passcodeView == this.passcodeView : overlayPasscodeViews.get(overlayPasscodeViews.size() - 1) == passcodeView; } private boolean handleIntent(Intent intent, boolean isNew, boolean restore, boolean fromPassword) { @@ -2522,7 +2542,7 @@ private boolean handleIntent(Intent intent, boolean isNew, boolean restore, bool req.hash = phoneHash; req.settings = new TLRPC.TL_codeSettings(); req.settings.allow_flashcall = false; - req.settings.allow_app_hash = PushListenerController.GooglePushListenerServiceProvider.INSTANCE.hasServices(); + req.settings.allow_app_hash = req.settings.allow_firebase = PushListenerController.GooglePushListenerServiceProvider.INSTANCE.hasServices(); SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); if (req.settings.allow_app_hash) { preferences.edit().putString("sms_hash", BuildVars.SMS_HASH).apply(); @@ -2671,12 +2691,19 @@ private boolean handleIntent(Intent intent, boolean isNew, boolean restore, bool if (push_topic_id > 0) { TLRPC.TL_forumTopic topic = MessagesController.getInstance(currentAccount).getTopicsController().findTopic(push_chat_id, push_topic_id); + FileLog.d(push_chat_id + " " + push_topic_id + " TL_forumTopic " + topic); if (topic != null) { TLRPC.Message message = topic.topicStartMessage; ArrayList messageObjects = new ArrayList<>(); TLRPC.Chat chatLocal = MessagesController.getInstance(currentAccount).getChat(push_chat_id); messageObjects.add(new MessageObject(currentAccount, message, false, false)); fragment.setThreadMessages(messageObjects, chatLocal, topic.id, topic.read_inbox_max_id, topic.read_outbox_max_id, topic); + } else { + boolean finalIsNew = isNew; + MessagesController.getInstance(currentAccount).getTopicsController().loadTopic(push_chat_id, push_topic_id, () -> { + handleIntent(intent, finalIsNew, restore, fromPassword, progress); + }); + return true; } } if (actionBarLayout.presentFragment(new INavigationLayout.NavigationParams(fragment).setNoAnimation(true))) { @@ -2990,7 +3017,7 @@ private void openDialogsToSend(boolean animated) { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); args.putBoolean("canSelectTopics", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); args.putBoolean("allowSwitchAccount", true); if (contactsToSend != null) { if (contactsToSend.size() != 1) { @@ -3198,16 +3225,16 @@ private void runImportRequest(final Uri importUri, args.putBoolean("allowSwitchAccount", true); if (res.pm) { - args.putInt("dialogsType", 12); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_USERS); } else if (res.group) { - args.putInt("dialogsType", 11); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_GROUPS); } else { String uri = importUri.toString(); Set uris = MessagesController.getInstance(intentAccount).exportPrivateUri; boolean ok = false; for (String u : uris) { if (uri.contains(u)) { - args.putInt("dialogsType", 12); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_USERS); ok = true; break; } @@ -3216,13 +3243,13 @@ private void runImportRequest(final Uri importUri, uris = MessagesController.getInstance(intentAccount).exportGroupUri; for (String u : uris) { if (uri.contains(u)) { - args.putInt("dialogsType", 11); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY_GROUPS); ok = true; break; } } if (!ok) { - args.putInt("dialogsType", 13); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_IMPORT_HISTORY); } } } @@ -3498,6 +3525,7 @@ private void runLinkRequest(final int intentAccount, NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); actionBarLayout.presentFragment(new ChatActivity(args1), true, false, true, false); } + return true; }); } else { dialogsActivity = null; @@ -3560,7 +3588,6 @@ private void runLinkRequest(final int intentAccount, allowWrite.set(allow); }); - builder.setCustomViewOffset(12); builder.setView(cell); } builder.show(); @@ -3584,7 +3611,7 @@ private void runLinkRequest(final int intentAccount, Bundle args = new Bundle(); args.putBoolean("onlySelect", true); args.putBoolean("cantSendToChannels", true); - args.putInt("dialogsType", 1); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_BOT_SHARE); args.putString("selectAlertString", LocaleController.getString("SendGameToText", R.string.SendGameToText)); args.putString("selectAlertStringGroup", LocaleController.getString("SendGameToGroupText", R.string.SendGameToGroupText)); DialogsActivity fragment = new DialogsActivity(args); @@ -3609,6 +3636,7 @@ private void runLinkRequest(final int intentAccount, NotificationCenter.getInstance(intentAccount).postNotificationName(NotificationCenter.closeChats); actionBarLayout.presentFragment(new ChatActivity(args1), true, false, true, false); } + return true; }); boolean removeLast; if (AndroidUtilities.isTablet()) { @@ -3648,7 +3676,7 @@ private void runLinkRequest(final int intentAccount, } Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 2); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO); args.putBoolean("resetDelegate", false); args.putBoolean("closeFragment", false); args.putBoolean("allowGroups", botChat != null); @@ -3779,6 +3807,7 @@ public void didChangeOwner(TLRPC.User user) { }); builder.show(); } + return true; }); presentFragment(fragment); } else { @@ -4132,7 +4161,7 @@ public void onError() { } else if (message != null) { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate((fragment13, dids, m, param) -> { long did = dids.get(0).dialogId; @@ -4151,6 +4180,7 @@ public void onError() { MediaDataController.getInstance(intentAccount).saveDraft(did, 0, message, null, null, false); actionBarLayout.presentFragment(new ChatActivity(args13), true, false, true, false); } + return true; }); presentFragment(fragment, false, true); } else if (auth != null) { @@ -4891,7 +4921,7 @@ public void onNewIntent(Intent intent, Browser.Progress progress) { } @Override - public void didSelectDialogs(DialogsActivity dialogsFragment, ArrayList dids, CharSequence message, boolean param) { + public boolean didSelectDialogs(DialogsActivity dialogsFragment, ArrayList dids, CharSequence message, boolean param) { final int account = dialogsFragment != null ? dialogsFragment.getCurrentAccount() : currentAccount; if (exportingChatUri != null) { @@ -4951,7 +4981,7 @@ public void didSelectDialogs(DialogsActivity dialogsFragment, ArrayList 1)) { - return; + return false; } } @@ -5082,6 +5112,7 @@ public void didSelectDialogs(DialogsActivity dialogsFragment, ArrayList MessagesController.getInstance(currentAccount).performLogout(2)); @@ -6465,6 +6523,14 @@ public void run() { SharedConfig.saveConfig(); } + public void addOverlayPasscodeView(PasscodeView overlay) { + overlayPasscodeViews.add(overlay); + } + + public void removeOverlayPasscodeView(PasscodeView overlay) { + overlayPasscodeViews.remove(overlay); + } + private void onPasscodeResume() { if (lockRunnable != null) { if (BuildVars.LOGS_ENABLED) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java index 55664a5a4de..94f4dd9006b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java @@ -40,13 +40,16 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.os.Looper; import android.telephony.PhoneNumberUtils; import android.telephony.TelephonyManager; import android.text.Editable; import android.text.InputType; +import android.text.Layout; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.Spanned; +import android.text.SpannedString; import android.text.TextPaint; import android.text.TextUtils; import android.text.TextWatcher; @@ -89,10 +92,14 @@ import com.google.android.gms.auth.api.signin.GoogleSignInClient; import com.google.android.gms.auth.api.signin.GoogleSignInOptions; import com.google.android.gms.common.api.ApiException; +import com.google.android.gms.safetynet.SafetyNet; +import org.json.JSONException; +import org.json.JSONObject; import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.AuthTokensHelper; import org.telegram.messenger.BuildVars; import org.telegram.messenger.ContactsController; import org.telegram.messenger.Emoji; @@ -134,6 +141,8 @@ import org.telegram.ui.Components.EditTextBoldCursor; import org.telegram.ui.Components.ImageUpdater; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.LinkPath; +import org.telegram.ui.Components.LoadingDrawable; import org.telegram.ui.Components.LoginOrView; import org.telegram.ui.Components.OutlineTextContainerView; import org.telegram.ui.Components.RLottieDrawable; @@ -153,6 +162,7 @@ import java.io.InputStreamReader; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -321,6 +331,8 @@ public class LoginActivity extends BaseFragment { private Runnable[] editDoneCallback = new Runnable[2]; private boolean[] postedEditDoneCallback = new boolean[2]; + private boolean forceDisableSafetyNet; + private static class ProgressView extends View { private final Path path = new Path(); @@ -1259,6 +1271,10 @@ private void showEditDoneProgress(boolean show, boolean animated, boolean fromCa if (animated && doneProgressVisible[currentDoneType] == show && !fromCallback) { return; } + if (Looper.myLooper() != Looper.getMainLooper()) { + AndroidUtilities.runOnUIThread(() -> showEditDoneProgress(show, animated, fromCallback)); + return; + } boolean floating = currentDoneType == DONE_TYPE_FLOATING; if (!fromCallback && !floating) { @@ -1550,6 +1566,7 @@ private void needFinishActivity(boolean afterSignup, boolean showSetPasswordConf NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.mainUserInfoChanged); LocaleController.getInstance().loadRemoteLanguages(currentAccount); + RestrictedLanguagesSelectActivity.checkRestrictedLanguages(true); } } else if (getParentActivity() instanceof ExternalActionActivity) { ((ExternalActionActivity) getParentActivity()).onFinishLogin(); @@ -1577,6 +1594,12 @@ private void onAuthSuccess(TLRPC.TL_auth_authorization res, boolean afterSignup) MessagesController.getInstance(currentAccount).checkPromoInfo(true); ConnectionsManager.getInstance(currentAccount).updateDcSettings(); + if (res.future_auth_token != null) { + AuthTokensHelper.saveLogInToken(res); + } else { + FileLog.d("onAuthSuccess future_auth_token is empty"); + } + if (afterSignup) { MessagesController.getInstance(currentAccount).putDialogsEndReachedAfterRegistration(); } @@ -1591,11 +1614,106 @@ private void fillNextCodeParams(Bundle params, TLRPC.TL_account_sentEmailCode re setPage(VIEW_CODE_EMAIL_SETUP, true, params, false); } - private void fillNextCodeParams(Bundle params, TLRPC.TL_auth_sentCode res) { + private void fillNextCodeParams(Bundle params, TLRPC.auth_SentCode res) { fillNextCodeParams(params, res, true); } - private void fillNextCodeParams(Bundle params, TLRPC.TL_auth_sentCode res, boolean animate) { + private void resendCodeFromSafetyNet(Bundle params, TLRPC.auth_SentCode res) { + needHideProgress(false); + isRequestingFirebaseSms = false; + + TLRPC.TL_auth_resendCode req = new TLRPC.TL_auth_resendCode(); + req.phone_number = params.getString("phoneFormated"); + req.phone_code_hash = res.phone_code_hash; + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + if (response != null) { + AndroidUtilities.runOnUIThread(() -> fillNextCodeParams(params, (TLRPC.auth_SentCode) response)); + } else { + AndroidUtilities.runOnUIThread(() -> { + if (getParentActivity() == null || getParentActivity().isFinishing() || getContext() == null) { + return; + } + new AlertDialog.Builder(getContext()) + .setTitle(LocaleController.getString(R.string.RestorePasswordNoEmailTitle)) + .setMessage(LocaleController.getString(R.string.SafetyNetErrorOccurred)) + .setPositiveButton(LocaleController.getString(R.string.OK), (dialog, which) -> { + forceDisableSafetyNet = true; + if (currentViewNum != VIEW_PHONE_INPUT) { + setPage(VIEW_PHONE_INPUT, true, null, true); + } + }) + .show(); + }); + } + }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + } + + private boolean isRequestingFirebaseSms; + private void fillNextCodeParams(Bundle params, TLRPC.auth_SentCode res, boolean animate) { + if (res.type instanceof TLRPC.TL_auth_sentCodeTypeFirebaseSms && !res.type.verifiedFirebase && !isRequestingFirebaseSms) { + if (PushListenerController.GooglePushListenerServiceProvider.INSTANCE.hasServices()) { + needShowProgress(0); + isRequestingFirebaseSms = true; + SafetyNet.getClient(ApplicationLoader.applicationContext).attest(res.type.nonce, BuildVars.SAFETYNET_KEY) + .addOnSuccessListener(attestationResponse -> { + String jws = attestationResponse.getJwsResult(); + + if (jws != null) { + TLRPC.TL_auth_requestFirebaseSms req = new TLRPC.TL_auth_requestFirebaseSms(); + req.phone_number = params.getString("phoneFormated"); + req.phone_code_hash = res.phone_code_hash; + req.safety_net_token = jws; + req.flags |= 1; + + String[] spl = jws.split("\\."); + if (spl.length > 0) { + try { + JSONObject obj = new JSONObject(new String(Base64.decode(spl[1].getBytes(StandardCharsets.UTF_8), 0))); + + if (obj.optBoolean("basicIntegrity") && obj.optBoolean("ctsProfileMatch")) { + ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { + needHideProgress(false); + isRequestingFirebaseSms = false; + if (response instanceof TLRPC.TL_boolTrue) { + res.type.verifiedFirebase = true; + AndroidUtilities.runOnUIThread(() -> fillNextCodeParams(params, res, animate)); + } else { + FileLog.d("Resend firebase sms because auth.requestFirebaseSms = false"); + resendCodeFromSafetyNet(params, res); + } + }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + } else { + FileLog.d("Resend firebase sms because ctsProfileMatch or basicIntegrity = false"); + resendCodeFromSafetyNet(params, res); + } + } catch (JSONException e) { + FileLog.e(e); + + FileLog.d("Resend firebase sms because of exception"); + resendCodeFromSafetyNet(params, res); + } + } else { + FileLog.d("Resend firebase sms because can't split JWS token"); + resendCodeFromSafetyNet(params, res); + } + } else { + FileLog.d("Resend firebase sms because JWS = null"); + resendCodeFromSafetyNet(params, res); + } + }) + .addOnFailureListener(e -> { + FileLog.e(e); + + FileLog.d("Resend firebase sms because of safetynet exception"); + resendCodeFromSafetyNet(params, res); + }); + } else { + FileLog.d("Resend firebase sms because firebase is not available"); + resendCodeFromSafetyNet(params, res); + } + return; + } + params.putString("phoneHash", res.phone_code_hash); if (res.next_type instanceof TLRPC.TL_auth_codeTypeCall) { params.putInt("nextType", AUTH_TYPE_CALL); @@ -1625,9 +1743,10 @@ private void fillNextCodeParams(Bundle params, TLRPC.TL_auth_sentCode res, boole params.putInt("type", AUTH_TYPE_FLASH_CALL); params.putString("pattern", res.type.pattern); setPage(VIEW_CODE_FLASH_CALL, animate, params, false); - } else if (res.type instanceof TLRPC.TL_auth_sentCodeTypeSms) { + } else if (res.type instanceof TLRPC.TL_auth_sentCodeTypeSms || res.type instanceof TLRPC.TL_auth_sentCodeTypeFirebaseSms) { params.putInt("type", AUTH_TYPE_SMS); params.putInt("length", res.type.length); + params.putBoolean("firebase", res.type instanceof TLRPC.TL_auth_sentCodeTypeFirebaseSms); setPage(VIEW_CODE_SMS, animate, params, false); } else if (res.type instanceof TLRPC.TL_auth_sentCodeTypeFragmentSms) { params.putInt("type", AUTH_TYPE_FRAGMENT_SMS); @@ -1860,6 +1979,9 @@ public void afterTextChanged(Editable editable) { if (c.code.startsWith(text)) { matchedCountries++; if (c.code.equals(text)) { + if (lastMatchedCountry != null && lastMatchedCountry.code.equals(c.code)) { + matchedCountries--; + } lastMatchedCountry = c; } } @@ -2126,7 +2248,7 @@ public void afterTextChanged(Editable s) { }); } - if (BuildVars.DEBUG_PRIVATE_VERSION && activityMode == MODE_LOGIN) { + if (BuildVars.DEBUG_VERSION && activityMode == MODE_LOGIN) { testBackendCheckBox = new CheckBoxCell(context, 2); testBackendCheckBox.setText(LocaleController.getString(R.string.DebugTestBackend), "", testBackend, false); addView(testBackendCheckBox, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 16, 0, 16 + (LocaleController.isRTL && AndroidUtilities.isSmallScreen() ? Build.VERSION.SDK_INT >= 21 ? 56 : 60 : 0), 0)); @@ -2139,7 +2261,7 @@ public void afterTextChanged(Editable s) { testBackend = !testBackend; cell.setChecked(testBackend, true); - boolean testBackend = BuildVars.DEBUG_PRIVATE_VERSION && getConnectionsManager().isTestBackend(); + boolean testBackend = BuildVars.DEBUG_VERSION && getConnectionsManager().isTestBackend(); if (testBackend != LoginActivity.this.testBackend) { getConnectionsManager().switchBackend(false); } @@ -2226,7 +2348,7 @@ public void afterTextChanged(Editable s) { private void loadCountries() { TLRPC.TL_help_getCountriesList req = new TLRPC.TL_help_getCountriesList(); - req.lang_code = ""; + req.lang_code = LocaleController.getInstance().getCurrentLocaleInfo() != null ? LocaleController.getInstance().getCurrentLocaleInfo().getLangCode() : Locale.getDefault().getCountry(); getConnectionsManager().sendRequest(req, (response, error) -> { AndroidUtilities.runOnUIThread(() -> { if (error == null) { @@ -2241,7 +2363,11 @@ private void loadCountries() { TLRPC.TL_help_countryCode countryCode = c.country_codes.get(k); if (countryCode != null) { CountrySelectActivity.Country countryWithCode = new CountrySelectActivity.Country(); - countryWithCode.name = c.default_name; + countryWithCode.name = c.name; + countryWithCode.defaultName = c.default_name; + if (countryWithCode.name == null && countryWithCode.defaultName != null) { + countryWithCode.name = countryWithCode.defaultName; + } countryWithCode.code = countryCode.country_code; countryWithCode.shortname = c.iso2; @@ -2491,7 +2617,7 @@ public void onNothingSelected(AdapterView adapterView) { @Override public void onNextPressed(String code) { - if (getParentActivity() == null || nextPressed) { + if (getParentActivity() == null || nextPressed || isRequestingFirebaseSms) { return; } @@ -2707,17 +2833,41 @@ private void onConfirm(PhoneNumberConfirmView confirmView) { TLRPC.TL_codeSettings settings = new TLRPC.TL_codeSettings(); settings.allow_flashcall = simcardAvailable && allowCall && allowCancelCall && allowReadCallLog; settings.allow_missed_call = simcardAvailable && allowCall; - settings.allow_app_hash = PushListenerController.GooglePushListenerServiceProvider.INSTANCE.hasServices(); + settings.allow_app_hash = settings.allow_firebase = PushListenerController.GooglePushListenerServiceProvider.INSTANCE.hasServices(); + if (forceDisableSafetyNet || TextUtils.isEmpty(BuildVars.SAFETYNET_KEY)) { + settings.allow_firebase = false; + } - ArrayList tokens = MessagesController.getSavedLogOutTokens(); + ArrayList loginTokens = AuthTokensHelper.getSavedLogInTokens(); + if (loginTokens != null) { + for (int i = 0; i < loginTokens.size(); i++) { + if (loginTokens.get(i).future_auth_token == null) { + continue; + } + if (settings.logout_tokens == null) { + settings.logout_tokens = new ArrayList<>(); + } + if (BuildVars.DEBUG_VERSION) { + FileLog.d("login token to check " + new String(loginTokens.get(i).future_auth_token, StandardCharsets.UTF_8)); + } + settings.logout_tokens.add(loginTokens.get(i).future_auth_token); + if (settings.logout_tokens.size() >= 20) { + break; + } + } + } + ArrayList tokens = AuthTokensHelper.getSavedLogOutTokens(); if (tokens != null) { for (int i = 0; i < tokens.size(); i++) { if (settings.logout_tokens == null) { settings.logout_tokens = new ArrayList<>(); } settings.logout_tokens.add(tokens.get(i).future_auth_token); + if (settings.logout_tokens.size() >= 20) { + break; + } } - MessagesController.saveLogOutTokens(tokens); + AuthTokensHelper.saveLogOutTokens(tokens); } if (settings.logout_tokens != null) { settings.flags |= 64; @@ -2784,7 +2934,21 @@ private void onConfirm(PhoneNumberConfirmView confirmView) { int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { nextPressed = false; if (error == null) { - fillNextCodeParams(params, (TLRPC.TL_auth_sentCode) response); + + if (response instanceof TLRPC.TL_auth_sentCodeSuccess) { + TLRPC.auth_Authorization auth = ((TLRPC.TL_auth_sentCodeSuccess) response).authorization; + if (auth instanceof TLRPC.TL_auth_authorizationSignUpRequired) { + TLRPC.TL_auth_authorizationSignUpRequired authorization = (TLRPC.TL_auth_authorizationSignUpRequired) response; + if (authorization.terms_of_service != null) { + currentTermsOfService = authorization.terms_of_service; + } + setPage(VIEW_REGISTER, true, params, false); + } else { + onAuthSuccess((TLRPC.TL_auth_authorization) auth); + } + } else { + fillNextCodeParams(params, (TLRPC.auth_SentCode) response); + } } else { if (error.text != null) { if (error.text.contains("SESSION_PASSWORD_NEEDED")) { @@ -2827,7 +2991,9 @@ private void onConfirm(PhoneNumberConfirmView confirmView) { } } } - needHideProgress(false); + if (!isRequestingFirebaseSms) { + needHideProgress(false); + } }), ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin | ConnectionsManager.RequestFlagTryDifferentDc | ConnectionsManager.RequestFlagEnableUnauthorized); needShowProgress(reqId); } @@ -3070,6 +3236,8 @@ public class LoginActivitySmsView extends SlideView implements NotificationCente @AuthType private int nextType; + private boolean isResendingCode = false; + private String pattern = "*"; private String prefix = ""; private String catchedPhone; @@ -3234,13 +3402,81 @@ protected void processNextPressed() { problemFrame = new FrameLayout(context); - timeText = new TextView(context); + timeText = new TextView(context) { + private LoadingDrawable loadingDrawable = new LoadingDrawable(); + + { + loadingDrawable.setAppearByGradient(true); + } + + @Override + public void setText(CharSequence text, BufferType type) { + super.setText(text, type); + + updateLoadingLayout(); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + + updateLoadingLayout(); + } + + private void updateLoadingLayout() { + Layout layout = getLayout(); + if (layout == null) { + return; + } + CharSequence text = layout.getText(); + if (text == null) { + return; + } + LinkPath path = new LinkPath(true); + int start = 0; + int end = text.length(); + path.setCurrentLayout(layout, start, 0); + layout.getSelectionPath(start, end, path); + loadingDrawable.usePath(path); + loadingDrawable.setRadiiDp(4); + + int color = getThemedColor(Theme.key_chat_linkSelectBackground); + loadingDrawable.setColors( + Theme.multAlpha(color, 0.85f), + Theme.multAlpha(color, 2f), + Theme.multAlpha(color, 3.5f), + Theme.multAlpha(color, 6f) + ); + + loadingDrawable.updateBounds(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (isResendingCode) { + canvas.save(); + canvas.translate(getPaddingLeft(), getPaddingTop()); + loadingDrawable.draw(canvas); + canvas.restore(); + invalidate(); + } + } + }; timeText.setLineSpacing(AndroidUtilities.dp(2), 1.0f); - timeText.setPadding(0, AndroidUtilities.dp(2), 0, AndroidUtilities.dp(10)); + timeText.setPadding(AndroidUtilities.dp(6), AndroidUtilities.dp(8), AndroidUtilities.dp(6), AndroidUtilities.dp(16)); timeText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); timeText.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL); timeText.setOnClickListener(v-> { - if (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_SMS || nextType == AUTH_TYPE_MISSED_CALL) { + if (isRequestingFirebaseSms || isResendingCode) { + return; + } + isResendingCode = true; + timeText.invalidate(); + timeText.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteValueText)); + + if (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_SMS || nextType == AUTH_TYPE_MISSED_CALL || nextType == AUTH_TYPE_FRAGMENT_SMS) { timeText.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText6)); if (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_MISSED_CALL) { timeText.setText(LocaleController.getString("Calling", R.string.Calling)); @@ -3362,7 +3598,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (currentType != AUTH_TYPE_FRAGMENT_SMS) { problemText.setOnClickListener(v -> { - if (nextPressed) { + if (nextPressed || timeText.getVisibility() != View.GONE) { return; } boolean email = nextType == 0; @@ -3449,6 +3685,14 @@ public void onCancelPressed() { } private void resendCode() { + if (nextPressed) { + return; + } + + isResendingCode = true; + timeText.invalidate(); + problemText.invalidate(); + final Bundle params = new Bundle(); params.putString("phone", phone); params.putString("ephone", emailPhone); @@ -5391,6 +5635,10 @@ public void didReceivedNotification(int id, int account, Object... args) { resendCodeView.setMaxLines(2); resendCodeView.setText(LocaleController.getString(R.string.ResendCode)); resendCodeView.setOnClickListener(v -> { + if (resendCodeView.getVisibility() != View.VISIBLE || resendCodeView.getAlpha() != 1f) { + return; + } + showResendCodeView(false); TLRPC.TL_auth_resendCode req = new TLRPC.TL_auth_resendCode(); @@ -6593,7 +6841,7 @@ public LoginActivityRegisterView(Context context) { setOrientation(VERTICAL); - imageUpdater = new ImageUpdater(false); + imageUpdater = new ImageUpdater(false, ImageUpdater.FOR_TYPE_USER, false); imageUpdater.setOpenWithFrontfaceCamera(true); imageUpdater.setSearchAvailable(false); imageUpdater.setUploadAfterSelect(false); @@ -6894,7 +7142,7 @@ private void buildEditTextLayout(boolean small) { } @Override - public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile video, double videoStartTimestamp, String videoPath, final TLRPC.PhotoSize bigSize, final TLRPC.PhotoSize smallSize, boolean isVideo) { + public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile video, double videoStartTimestamp, String videoPath, final TLRPC.PhotoSize bigSize, final TLRPC.PhotoSize smallSize, boolean isVideo, TLRPC.VideoSize emojiMarkup) { AndroidUtilities.runOnUIThread(() -> { avatar = smallSize.location; avatarBig = bigSize.location; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/NewContactBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/NewContactBottomSheet.java index 6bcf59d8b3a..5a2b889ff42 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/NewContactBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/NewContactBottomSheet.java @@ -40,6 +40,7 @@ import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; 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.BaseFragment; @@ -104,6 +105,7 @@ public class NewContactBottomSheet extends BottomSheet implements AdapterView.On public NewContactBottomSheet(BaseFragment parentFragment, Context context) { super(context, true); + waitingKeyboard = true; smoothKeyboardAnimationEnabled = true; classGuid = ConnectionsManager.generateClassGuid(); this.parentFragment = parentFragment; @@ -628,7 +630,6 @@ public void afterTextChanged(Editable s) { plusTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); codeDividerView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhiteInputField)); - return fragmentView; } @@ -699,7 +700,7 @@ public void show() { firstNameField.getEditText().requestFocus(); AndroidUtilities.runOnUIThread(() -> { AndroidUtilities.showKeyboard(firstNameField.getEditText()); - }, 200); + }, 50); } private void showEditDoneProgress(boolean show, boolean animated) { @@ -740,6 +741,27 @@ public static String getPhoneNumber(Context context, TLRPC.User user, String num public void setInitialPhoneNumber(String value, boolean withCoutryCode) { initialPhoneNumber = value; initialPhoneNumberWithCountryCode = withCoutryCode; + + if (!TextUtils.isEmpty(initialPhoneNumber)) { + TLRPC.User user = UserConfig.getInstance(currentAccount).getCurrentUser(); + if (initialPhoneNumber.startsWith("+")) { + codeField.setText(initialPhoneNumber.substring(1)); + } else if (initialPhoneNumberWithCountryCode || user == null || TextUtils.isEmpty(user.phone)) { + codeField.setText(initialPhoneNumber); + } else { + String phone = user.phone; + for (int a = 4; a >= 1; a--) { + String sub = phone.substring(0, a); + List country = codesMap.get(sub); + if (country != null && country.size() > 0) { + codeField.setText(country.get(0).code); + break; + } + } + phoneField.setText(initialPhoneNumber); + } + initialPhoneNumber = null; + } } public void setInitialName(String firstName, String lastName) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsCustomSettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsCustomSettingsActivity.java index b89a03f5142..05f1a3e44c6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsCustomSettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsCustomSettingsActivity.java @@ -397,11 +397,11 @@ private void setDefault() { args.putBoolean("onlySelect", true); args.putBoolean("checkCanWrite", false); if (currentType == NotificationsController.TYPE_GROUP) { - args.putInt("dialogsType", 6); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_GROUPS_ONLY); } else if (currentType == NotificationsController.TYPE_CHANNEL) { - args.putInt("dialogsType", 5); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_CHANNELS_ONLY); } else { - args.putInt("dialogsType", 4); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_USERS_ONLY); } DialogsActivity activity = new DialogsActivity(args); activity.setDelegate((fragment, dids, message, param) -> { @@ -414,6 +414,7 @@ private void setDefault() { updateRows(true); }); presentFragment(profileNotificationsActivity, true); + return true; }); presentFragment(activity); } else if (position == deleteAllRow) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index 38e5b1ece74..4772d679db3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -67,6 +67,7 @@ import android.transition.TransitionSet; import android.transition.TransitionValues; import android.util.FloatProperty; +import android.util.Log; import android.util.Property; import android.util.Range; import android.util.SparseArray; @@ -3327,13 +3328,14 @@ public void didReceivedNotification(int id, int account, Object... args) { imagesArrLocationsVideo.clear(); imagesArrMessages.clear(); avatarsArr.clear(); + for (int a = 0; a < photos.size(); a++) { TLRPC.Photo photo = photos.get(a); if (photo == null || photo instanceof TLRPC.TL_photoEmpty || photo.sizes == null) { continue; } TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(photo.sizes, 640); - TLRPC.VideoSize videoSize = photo.video_sizes.isEmpty() ? null : photo.video_sizes.get(0); + TLRPC.VideoSize videoSize = photo.video_sizes.isEmpty() ? null : FileLoader.getClosestVideoSizeWithSize(photo.video_sizes, 1000); if (sizeFull != null) { if (setToImage == -1 && currentFileLocation != null) { for (int b = 0; b < photo.sizes.size(); b++) { @@ -3344,6 +3346,15 @@ public void didReceivedNotification(int id, int account, Object... args) { } } } + if (setToImage == -1 && currentFileLocation != null) { + for (int b = 0; b < photo.video_sizes.size(); b++) { + TLRPC.VideoSize size = photo.video_sizes.get(b); + if (size.location != null && size.location.local_id == currentFileLocation.location.local_id && size.location.volume_id == currentFileLocation.location.volume_id) { + setToImage = imagesArrLocations.size(); + break; + } + } + } if (photo.dc_id != 0) { sizeFull.location.dc_id = photo.dc_id; sizeFull.location.file_reference = photo.file_reference; @@ -4353,7 +4364,7 @@ public void onItemClick(int id) { } else { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); DialogsActivity fragment = new DialogsActivity(args); final ArrayList fmessages = new ArrayList<>(); fmessages.add(currentMessageObject); @@ -4394,6 +4405,7 @@ public void onItemClick(int id) { fragment1.finishFragment(); } } + return true; }); ((LaunchActivity) parentActivity).presentFragment(fragment, false, true); closePhoto(false, false); @@ -4526,7 +4538,7 @@ public void onItemClick(int id) { if (avatarsDialogId > 0) { MessagesController.getInstance(currentAccount).deleteUserPhoto(null); } else { - MessagesController.getInstance(currentAccount).changeChatAvatar(-avatarsDialogId, null, null, null, 0, null, null, null, null); + MessagesController.getInstance(currentAccount).changeChatAvatar(-avatarsDialogId, null, null, null, null, 0, null, null, null, null); } closePhoto(false, false); } else { @@ -4740,7 +4752,7 @@ public void dismiss() { inputChatPhoto.id.id = photo.id; inputChatPhoto.id.access_hash = photo.access_hash; inputChatPhoto.id.file_reference = photo.file_reference; - MessagesController.getInstance(currentAccount).changeChatAvatar(-avatarsDialogId, inputChatPhoto, null, null, 0, null, null, null, null); + MessagesController.getInstance(currentAccount).changeChatAvatar(-avatarsDialogId, inputChatPhoto, null, null, null, 0, null, null, null, null); chat.photo.dc_id = photo.dc_id; chat.photo.photo_small = smallSize.location; chat.photo.photo_big = bigSize.location; @@ -5602,7 +5614,11 @@ public void setAlpha(float alpha) { } else if (a == 3) { cell.setTextAndIcon(LocaleController.getString("SendAsNewPhoto", R.string.SendAsNewPhoto), R.drawable.msg_send); } else if (a == 4) { - cell.setTextAndIcon(LocaleController.getString("SendWithoutCompression", R.string.SendWithoutCompression), R.drawable.msg_sendfile); + if (placeProvider != null && placeProvider.getSelectedCount() > 1) { + cell.setTextAndIcon(LocaleController.getString(R.string.SendAsFiles), R.drawable.msg_sendfile); + } else { + cell.setTextAndIcon(LocaleController.getString(R.string.SendAsFile), R.drawable.msg_sendfile); + } } cell.setMinimumWidth(AndroidUtilities.dp(196)); cell.setColors(0xffffffff, 0xffffffff); @@ -6727,6 +6743,17 @@ public void onDismiss(DialogInterface dialog) { ((MediaController.MediaEditState) entry).editedInfo = videoEditedInfo; } } + if (parentChatActivity != null && parentChatActivity.getCurrentChat() != null) { + boolean isVideo = (isCurrentVideo || videoEditedInfo != null); + if (isVideo && !ChatObject.canSendVideo(parentChatActivity.getCurrentChat())) { + BulletinFactory.of(containerView, resourcesProvider).createErrorBulletin(LocaleController.getString(R.string.GlobalAttachVideoRestricted)).show(); + return; + } + if (!isVideo && !ChatObject.canSendPhoto(parentChatActivity.getCurrentChat())) { + BulletinFactory.of(containerView, resourcesProvider).createErrorBulletin(LocaleController.getString(R.string.GlobalAttachPhotoRestricted)).show(); + return; + } + } doneButtonPressed = true; if (videoEditedInfo != null) { long sizeToCheck = (long) (videoEditedInfo.estimatedSize * 0.9f); @@ -7141,14 +7168,14 @@ public void getOutline(View view, Outline outline) { videoTextureView.setTranslationX(fromX * (1f - xValue) + (toX2) * xValue); videoTextureView.setTranslationY(fromY * (1f - yValue) + (toY2) * yValue); videoTextureView.invalidateOutline(); - } - if (firstFrameView != null) { - firstFrameView.setTranslationX(videoTextureView.getTranslationX()); - firstFrameView.setTranslationY(videoTextureView.getTranslationY()); - firstFrameView.setScaleX(videoTextureView.getScaleX()); - firstFrameView.setScaleY(videoTextureView.getScaleY()); - firstFrameView.invalidateOutline(); + if (firstFrameView != null) { + firstFrameView.setTranslationX(videoTextureView.getTranslationX()); + firstFrameView.setTranslationY(videoTextureView.getTranslationY()); + firstFrameView.setScaleX(videoTextureView.getScaleX()); + firstFrameView.setScaleY(videoTextureView.getScaleY()); + firstFrameView.invalidateOutline(); + } } }); @@ -7914,12 +7941,12 @@ private void updateVideoPlayerTime() { videoPlayerTotalTime[1] = (int) (total % 60); } String current, total; - if (videoPlayerCurrentTime[0] > 60) { + if (videoPlayerCurrentTime[0] >= 60) { current = String.format(Locale.ROOT, "%02d:%02d:%02d", videoPlayerCurrentTime[0] / 60, videoPlayerCurrentTime[0] % 60, videoPlayerCurrentTime[1]); } else { current = String.format(Locale.ROOT, "%02d:%02d", videoPlayerCurrentTime[0], videoPlayerCurrentTime[1]); } - if (videoPlayerTotalTime[0] > 60) { + if (videoPlayerTotalTime[0] >= 60) { total = String.format(Locale.ROOT, "%02d:%02d:%02d", videoPlayerTotalTime[0] / 60, videoPlayerTotalTime[0] % 60, videoPlayerTotalTime[1]); } else { total = String.format(Locale.ROOT, "%02d:%02d", videoPlayerTotalTime[0], videoPlayerTotalTime[1]); @@ -11449,7 +11476,7 @@ private void onPhotoShow(final MessageObject messageObject, final TLRPC.FileLoca } private boolean canSendMediaToParentChatActivity() { - return parentChatActivity != null && (parentChatActivity.currentUser != null || parentChatActivity.currentChat != null && !ChatObject.isNotInChat(parentChatActivity.currentChat) && ChatObject.canSendMedia(parentChatActivity.currentChat)); + return parentChatActivity != null && (parentChatActivity.currentUser != null || parentChatActivity.currentChat != null && !ChatObject.isNotInChat(parentChatActivity.currentChat) && (ChatObject.canSendPhoto(parentChatActivity.currentChat) || ChatObject.canSendVideo(parentChatActivity.currentChat))); } private void setDoubleTapEnabled(boolean value) { @@ -11496,6 +11523,7 @@ private void setIsAboutToSwitchToIndex(int index, boolean init, boolean animated return; } newMessageObject = imagesArr.get(switchingToIndex); + newMessageObject.updateTranslation(); isVideo = newMessageObject.isVideo(); boolean isInvoice = newMessageObject.isInvoice(); boolean noforwards = MessagesController.getInstance(currentAccount).isChatNoForwards(newMessageObject.getChatId()) || (newMessageObject.messageOwner != null && newMessageObject.messageOwner.noforwards) || newMessageObject.hasRevealedExtendedMedia(); @@ -12134,6 +12162,9 @@ private void setImageIndex(int index, boolean init, boolean animateCaption) { } MessageObject newMessageObject = imagesArr.get(currentIndex); sameImage = init && currentMessageObject != null && currentMessageObject.getId() == newMessageObject.getId(); + if (sameImage) { + newMessageObject.putInDownloadsStore = currentMessageObject.putInDownloadsStore; + } currentMessageObject = newMessageObject; isVideo = newMessageObject.isVideo(); if (sharedMediaType == MediaDataController.MEDIA_FILE) { @@ -14672,6 +14703,9 @@ private void onPhotoClosed(PlaceProviderObject object) { if (doneButtonPressed) { releasePlayer(true); } + if (currentMessageObject != null && !currentMessageObject.putInDownloadsStore) { + FileLoader.getInstance(currentAccount).cancelLoadFile(currentMessageObject.getDocument()); + } isVisible = false; cropInitied = false; disableShowCheck = true; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PinchToZoomHelper.java b/TMessagesProj/src/main/java/org/telegram/ui/PinchToZoomHelper.java index 6ea2e3d4c20..08b0a7c26ef 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PinchToZoomHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PinchToZoomHelper.java @@ -750,7 +750,9 @@ public boolean checkPinchToZoom(MotionEvent ev, View child, ImageReceiver image, invalidateViews(); } else if ((ev.getActionMasked() == MotionEvent.ACTION_UP || (ev.getActionMasked() == MotionEvent.ACTION_POINTER_UP && checkPointerIds(ev)) || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) && isInPinchToZoomTouchMode) { isInPinchToZoomTouchMode = false; - child.getParent().requestDisallowInterceptTouchEvent(false); + if (child != null && child.getParent() != null) { + child.getParent().requestDisallowInterceptTouchEvent(false); + } finishZoom(); } return isInOverlayModeFor(child); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java index 63b1511c08d..4cd90b5bb15 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java @@ -2,6 +2,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Dialog; @@ -95,14 +96,17 @@ import java.util.Collections; import java.util.List; import java.util.Locale; +import java.util.Objects; public class PremiumPreviewFragment extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { - private final static boolean IS_PREMIUM_TIERS_UNAVAILABLE = true; + public final static String TRANSACTION_PATTERN = "^(.*?)(?:\\.\\.\\d*|)$"; + private final static boolean IS_PREMIUM_TIERS_UNAVAILABLE = false; RecyclerListView listView; ArrayList premiumFeatures = new ArrayList<>(); ArrayList subscriptionTiers = new ArrayList<>(); int selectedTierIndex = 0; + SubscriptionTier currentSubscriptionTier; int rowCount; int paddingRow; @@ -144,6 +148,7 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification public final static int PREMIUM_FEATURE_APPLICATION_ICONS = 10; public final static int PREMIUM_FEATURE_ANIMATED_EMOJI = 11; public final static int PREMIUM_FEATURE_EMOJI_STATUS = 12; + public final static int PREMIUM_FEATURE_TRANSLATIONS = 13; private int statusBarHeight; private int firstViewHeight; private boolean isDialogVisible; @@ -156,10 +161,12 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification float totalProgress; private String source; + private boolean selectAnnualByDefault; + final Bitmap gradientTextureBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); final Canvas gradientCanvas = new Canvas(gradientTextureBitmap); - PremiumGradient.GradientTools gradientTools = new PremiumGradient.GradientTools(Theme.key_premiumGradientBackground1, Theme.key_premiumGradientBackground2, Theme.key_premiumGradientBackground3, Theme.key_premiumGradientBackground4); - PremiumGradient.GradientTools tiersGradientTools; + PremiumGradient.PremiumGradientTools gradientTools = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradientBackground1, Theme.key_premiumGradientBackground2, Theme.key_premiumGradientBackground3, Theme.key_premiumGradientBackground4); + PremiumGradient.PremiumGradientTools tiersGradientTools; private boolean forcePremium; float progressToFull; @@ -192,6 +199,8 @@ public static int serverStringToFeatureType(String s) { return PREMIUM_FEATURE_ANIMATED_EMOJI; case "emoji_status": return PREMIUM_FEATURE_EMOJI_STATUS; + case "translations": + return PREMIUM_FEATURE_TRANSLATIONS; } return -1; } @@ -224,6 +233,8 @@ public static String featureTypeToServerString(int type) { return "app_icons"; case PREMIUM_FEATURE_EMOJI_STATUS: return "emoji_status"; + case PREMIUM_FEATURE_TRANSLATIONS: + return "translations"; } return null; } @@ -239,7 +250,7 @@ public PremiumPreviewFragment(String source) { } { - tiersGradientTools = new PremiumGradient.GradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, null, null); + tiersGradientTools = new PremiumGradient.PremiumGradientTools(Theme.key_premiumGradient1, Theme.key_premiumGradient2, null, null); tiersGradientTools.exactly = true; tiersGradientTools.x1 = 0; tiersGradientTools.y1 = 0f; @@ -249,6 +260,11 @@ public PremiumPreviewFragment(String source) { tiersGradientTools.cy = 0; } + public PremiumPreviewFragment setSelectAnnualByDefault() { + this.selectAnnualByDefault = true; + return this; + } + @SuppressLint("NotifyDataSetChanged") @Override public View createView(Context context) { @@ -335,7 +351,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } backgroundView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); particlesView.getLayoutParams().height = backgroundView.getMeasuredHeight(); - int buttonHeight = (getUserConfig().isPremium() || forcePremium ? 0 : AndroidUtilities.dp(68)); + int buttonHeight = (buttonContainer == null || buttonContainer.getVisibility() == View.GONE ? 0 : AndroidUtilities.dp(68)); layoutManager.setAdditionalHeight(buttonHeight + statusBarHeight - AndroidUtilities.dp(16)); layoutManager.setMinimumLastViewHeight(buttonHeight); super.onMeasure(widthMeasureSpec, heightMeasureSpec); @@ -420,13 +436,13 @@ protected void dispatchDraw(Canvas canvas) { backgroundView.tierListView.setAlpha(alpha); particlesView.setAlpha(1f - totalProgress); - particlesView.setTranslationY(-(particlesView.getMeasuredHeight() - backgroundView.imageView.getMeasuredWidth()) / 2f + backgroundView.getY() + backgroundView.imageView.getY()); + particlesView.setTranslationY(-(particlesView.getMeasuredHeight() - backgroundView.imageView.getMeasuredWidth()) / 2f + backgroundView.getY() + backgroundView.imageFrameLayout.getY()); float toX = AndroidUtilities.dp(72) - backgroundView.titleView.getLeft(); float f = totalProgress > 0.3f ? (totalProgress - 0.3f) / 0.7f : 0f; backgroundView.titleView.setTranslationX(toX * (1f - CubicBezierInterpolator.EASE_OUT_QUINT.getInterpolation(1 - f))); - backgroundView.imageView.mRenderer.gradientStartX = (backgroundView.getX() + backgroundView.imageView.getX() + getMeasuredWidth() * 0.1f * progress) / getMeasuredWidth(); - backgroundView.imageView.mRenderer.gradientStartY = (backgroundView.getY() + backgroundView.imageView.getY()) / getMeasuredHeight(); + backgroundView.imageView.mRenderer.gradientStartX = (backgroundView.getX() + backgroundView.imageFrameLayout.getX() + getMeasuredWidth() * 0.1f * progress) / getMeasuredWidth(); + backgroundView.imageView.mRenderer.gradientStartY = (backgroundView.getY() + backgroundView.imageFrameLayout.getY()) / getMeasuredHeight(); if (!isDialogVisible) { invalidate(); @@ -513,11 +529,13 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { // bottomSheet.setParentFragment(PremiumPreviewFragment.this); // showDialog(bottomSheet); // } else { - if (subscriptionTiers.isEmpty()) { - return; - } - showDialog(new PremiumFeatureBottomSheet(PremiumPreviewFragment.this, cell.data.type, false, subscriptionTiers.get(selectedTierIndex))); +// if (subscriptionTiers.isEmpty()) { +// return; +// } // } + + SubscriptionTier tier = selectedTierIndex < 0 || selectedTierIndex >= subscriptionTiers.size() ? null : subscriptionTiers.get(selectedTierIndex); + showDialog(new PremiumFeatureBottomSheet(PremiumPreviewFragment.this, cell.data.type, false, tier)); } }); contentView.addView(listView); @@ -588,6 +606,7 @@ public static void fillPremiumFeaturesList(ArrayList premium premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_ANIMATED_AVATARS, R.drawable.msg_premium_avatar, LocaleController.getString("PremiumPreviewAnimatedProfiles", R.string.PremiumPreviewAnimatedProfiles), LocaleController.getString("PremiumPreviewAnimatedProfilesDescription", R.string.PremiumPreviewAnimatedProfilesDescription))); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_APPLICATION_ICONS, R.drawable.msg_premium_icons, LocaleController.getString("PremiumPreviewAppIcon", R.string.PremiumPreviewAppIcon), LocaleController.getString("PremiumPreviewAppIconDescription", R.string.PremiumPreviewAppIconDescription))); premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_EMOJI_STATUS, R.drawable.msg_premium_status, LocaleController.getString("PremiumPreviewEmojiStatus", R.string.PremiumPreviewEmojiStatus), LocaleController.getString("PremiumPreviewEmojiStatusDescription", R.string.PremiumPreviewEmojiStatusDescription))); + premiumFeatures.add(new PremiumFeatureData(PREMIUM_FEATURE_TRANSLATIONS, R.drawable.msg_premium_translate, LocaleController.getString("PremiumPreviewTranslations", R.string.PremiumPreviewTranslations), LocaleController.getString("PremiumPreviewTranslationsDescription", R.string.PremiumPreviewTranslationsDescription))); if (messagesController.premiumFeaturesTypesToPosition.size() > 0) { for (int i = 0; i < premiumFeatures.size(); i++) { @@ -622,16 +641,29 @@ private void checkButtonDivider() { } public static void buyPremium(BaseFragment fragment, String source) { - buyPremium(fragment, null, source); + buyPremium(fragment, null, source, true); + } + + public static void buyPremium(BaseFragment fragment, String source, boolean forcePremium) { + buyPremium(fragment, null, source, forcePremium); } public static void buyPremium(BaseFragment fragment, SubscriptionTier tier, String source) { + buyPremium(fragment, tier, source, true); + } + + public static void buyPremium(BaseFragment fragment, SubscriptionTier tier, String source, boolean forcePremium) { + buyPremium(fragment, tier, source, forcePremium, null); + } + + public static void buyPremium(BaseFragment fragment, SubscriptionTier tier, String source, boolean forcePremium, BillingFlowParams.SubscriptionUpdateParams updateParams) { if (BuildVars.IS_BILLING_UNAVAILABLE) { fragment.showDialog(new PremiumNotAvailableBottomSheet(fragment)); return; } if (tier == null) { + forcePremium = true; for (TLRPC.TL_premiumSubscriptionOption option : fragment.getAccountInstance().getMediaDataController().getPremiumPromo().period_options) { if (option.months == 1) { tier = new SubscriptionTier(option); @@ -685,17 +717,24 @@ public static void buyPremium(BaseFragment fragment, SubscriptionTier tier, Stri return; } + boolean finalForcePremium = forcePremium; BillingController.getInstance().queryPurchases(BillingClient.ProductType.SUBS, (billingResult1, list) -> AndroidUtilities.runOnUIThread(() -> { if (billingResult1.getResponseCode() == BillingClient.BillingResponseCode.OK) { Runnable onSuccess = () -> { if (fragment instanceof PremiumPreviewFragment) { PremiumPreviewFragment premiumPreviewFragment = (PremiumPreviewFragment) fragment; - premiumPreviewFragment.setForcePremium(); + if (finalForcePremium) { + premiumPreviewFragment.setForcePremium(); + } premiumPreviewFragment.getMediaDataController().loadPremiumPromo(false); premiumPreviewFragment.listView.smoothScrollToPosition(0); } else { - fragment.presentFragment(new PremiumPreviewFragment(null).setForcePremium()); + PremiumPreviewFragment previewFragment = new PremiumPreviewFragment(null); + if (finalForcePremium) { + previewFragment.setForcePremium(); + } + fragment.presentFragment(previewFragment); } if (fragment.getParentActivity() instanceof LaunchActivity) { try { @@ -705,7 +744,7 @@ public static void buyPremium(BaseFragment fragment, SubscriptionTier tier, Stri ((LaunchActivity) fragment.getParentActivity()).getFireworksOverlay().start(); } }; - if (list != null && !list.isEmpty()) { + if (list != null && !list.isEmpty() && !fragment.getUserConfig().isPremium()) { for (Purchase purchase : list) { if (purchase.getProducts().contains(BillingController.PREMIUM_PRODUCT_ID)) { TLRPC.TL_payments_assignPlayMarketTransaction req = new TLRPC.TL_payments_assignPlayMarketTransaction(); @@ -713,6 +752,9 @@ public static void buyPremium(BaseFragment fragment, SubscriptionTier tier, Stri req.receipt.data = purchase.getOriginalJson(); TLRPC.TL_inputStorePaymentPremiumSubscription purpose = new TLRPC.TL_inputStorePaymentPremiumSubscription(); purpose.restore = true; + if (updateParams != null) { + purpose.upgrade = true; + } req.purpose = purpose; fragment.getConnectionsManager().sendRequest(req, (response, error) -> { if (response instanceof TLRPC.Updates) { @@ -736,16 +778,20 @@ public static void buyPremium(BaseFragment fragment, SubscriptionTier tier, Stri }); TLRPC.TL_payments_canPurchasePremium req = new TLRPC.TL_payments_canPurchasePremium(); - req.purpose = new TLRPC.TL_inputStorePaymentPremiumSubscription(); + TLRPC.TL_inputStorePaymentPremiumSubscription purpose = new TLRPC.TL_inputStorePaymentPremiumSubscription(); + if (updateParams != null) { + purpose.upgrade = true; + } + req.purpose = purpose; fragment.getConnectionsManager().sendRequest(req, (response, error) -> { AndroidUtilities.runOnUIThread(() -> { if (response instanceof TLRPC.TL_boolTrue) { - BillingController.getInstance().launchBillingFlow(fragment.getParentActivity(), fragment.getAccountInstance(), new TLRPC.TL_inputStorePaymentPremiumSubscription(), Collections.singletonList( + BillingController.getInstance().launchBillingFlow(fragment.getParentActivity(), fragment.getAccountInstance(), purpose, Collections.singletonList( BillingFlowParams.ProductDetailsParams.newBuilder() .setProductDetails(BillingController.PREMIUM_PRODUCT_DETAILS) .setOfferToken(selectedTier.getOfferDetails().getOfferToken()) .build() - )); + ), updateParams, false); } else { AlertsCreator.processError(fragment.getCurrentAccount(), error, fragment, req); } @@ -802,7 +848,8 @@ public static String getPremiumButtonText(int currentAccount, SubscriptionTier t if (!BuildVars.useInvoiceBilling() && tier.getOfferDetails() == null) { return LocaleController.getString(R.string.Loading); } - return LocaleController.formatString(R.string.SubscribeToPremium, tier.getFormattedPricePerMonth()); + return LocaleController.formatString(UserConfig.getInstance(currentAccount).isPremium() ? tier.getMonths() == 12 ? R.string.UpgradePremiumPerYear : R.string.UpgradePremiumPerMonth : + tier.getMonths() == 12 ? R.string.SubscribeToPremiumPerYear : R.string.SubscribeToPremium, tier.getMonths() == 12 ? tier.getFormattedPricePerYear() : tier.getFormattedPricePerMonth()); } } @@ -829,11 +876,8 @@ private void updateRows() { featuresEndRow = rowCount; statusRow = rowCount++; lastPaddingRow = rowCount++; - if (getUserConfig().isPremium() || forcePremium) { - buttonContainer.setVisibility(View.GONE); - } else { - buttonContainer.setVisibility(View.VISIBLE); - } + + AndroidUtilities.updateViewVisibilityAnimated(buttonContainer, !getUserConfig().isPremium() || currentSubscriptionTier != null && currentSubscriptionTier.getMonths() < subscriptionTiers.get(selectedTierIndex).getMonths() && !forcePremium, 1f, false); int buttonHeight = buttonContainer.getVisibility() == View.VISIBLE ? AndroidUtilities.dp(64) : 0; layoutManager.setAdditionalHeight(buttonHeight + statusBarHeight - AndroidUtilities.dp(16)); @@ -877,6 +921,7 @@ public void onFragmentDestroy() { public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.billingProductDetailsUpdated || id == NotificationCenter.premiumPromoUpdated) { updateButtonText(false); + backgroundView.updatePremiumTiers(); } if (id == NotificationCenter.currentUserPremiumStatusChanged || id == NotificationCenter.premiumPromoUpdated) { backgroundView.updateText(); @@ -1077,6 +1122,7 @@ private class BackgroundView extends LinearLayout { TextView titleView; private final TextView subtitleView; + private final FrameLayout imageFrameLayout; private final GLIconTextureView imageView; private RecyclerListView tierListView; @@ -1084,6 +1130,8 @@ private class BackgroundView extends LinearLayout { public BackgroundView(Context context) { super(context); setOrientation(VERTICAL); + imageFrameLayout = new FrameLayout(context); + addView(imageFrameLayout, LayoutHelper.createLinear(190, 190, Gravity.CENTER_HORIZONTAL)); imageView = new GLIconTextureView(context, GLIconRenderer.FRAGMENT_STYLE) { @Override public void onLongPress() { @@ -1106,7 +1154,7 @@ public void onLongPress() { settingsView.animate().translationY(1).setDuration(300); } }; - addView(imageView, LayoutHelper.createLinear(190, 190, Gravity.CENTER_HORIZONTAL)); + imageFrameLayout.addView(imageView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); titleView = new TextView(context); titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 22); @@ -1175,7 +1223,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { - return true; + return !subscriptionTiers.get(holder.getAdapterPosition()).subscriptionOption.current; } @Override @@ -1184,6 +1232,9 @@ public int getItemCount() { } }); tierListView.setOnItemClickListener((view, position) -> { + if (!view.isEnabled()) { + return; + } if (view instanceof PremiumTierCell) { PremiumTierCell tierCell = (PremiumTierCell) view; selectedTierIndex = subscriptionTiers.indexOf(tierCell.getTier()); @@ -1229,6 +1280,8 @@ public int getItemCount() { } } } + + AndroidUtilities.updateViewVisibilityAnimated(buttonContainer, !getUserConfig().isPremium() || currentSubscriptionTier != null && currentSubscriptionTier.getMonths() < subscriptionTiers.get(selectedTierIndex).getMonths() && !forcePremium); } }); Path path = new Path(); @@ -1252,8 +1305,8 @@ public int getItemCount() { }); addView(tierListView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 12, 16, 12, 0)); - updateText(); updatePremiumTiers(); + updateText(); } private void measureGradient(int w, int h) { @@ -1271,11 +1324,25 @@ private void measureGradient(int w, int h) { @SuppressLint("NotifyDataSetChanged") public void updatePremiumTiers() { subscriptionTiers.clear(); + selectedTierIndex = -1; + currentSubscriptionTier = null; long pricePerYearMax = 0; if (getMediaDataController().getPremiumPromo() != null) { for (TLRPC.TL_premiumSubscriptionOption option : getMediaDataController().getPremiumPromo().period_options) { + if (getUserConfig().isPremium() && !option.can_purchase_upgrade && !option.current) { + continue; + } + SubscriptionTier subscriptionTier = new SubscriptionTier(option); subscriptionTiers.add(subscriptionTier); + if (selectAnnualByDefault) { + if (option.months == 12) { + selectedTierIndex = subscriptionTiers.size() - 1; + } + } + if (option.current) { + currentSubscriptionTier = subscriptionTier; + } if (BuildVars.useInvoiceBilling()) { if (subscriptionTier.getPricePerYear() > pricePerYearMax) { pricePerYearMax = subscriptionTier.getPricePerYear(); @@ -1283,6 +1350,17 @@ public void updatePremiumTiers() { } } } + if (BuildVars.useInvoiceBilling() && getUserConfig().isPremium()) { + subscriptionTiers.clear(); + currentSubscriptionTier = null; + } else if (!BuildVars.useInvoiceBilling() && currentSubscriptionTier != null && !Objects.equals(BillingController.getInstance().getLastPremiumTransaction(), + currentSubscriptionTier.subscriptionOption != null ? currentSubscriptionTier.subscriptionOption.transaction != null ? + currentSubscriptionTier.subscriptionOption.transaction.replaceAll(TRANSACTION_PATTERN, "$1") : null : null) || + currentSubscriptionTier != null && currentSubscriptionTier.getMonths() == 12) { + subscriptionTiers.clear(); + currentSubscriptionTier = null; + } + if (BuildVars.useInvoiceBilling()) { for (SubscriptionTier tier : subscriptionTiers) { tier.setPricePerYearRegular(pricePerYearMax); @@ -1303,39 +1381,102 @@ public void updatePremiumTiers() { } } - for (int i = 0; i < subscriptionTiers.size(); i++) { - SubscriptionTier tier = subscriptionTiers.get(i); - if (tier.getMonths() == 1) { - selectedTierIndex = i; - break; + if (selectedTierIndex == -1) { + for (int i = 0; i < subscriptionTiers.size(); i++) { + SubscriptionTier tier = subscriptionTiers.get(i); + if (tier.getMonths() == 12) { + selectedTierIndex = i; + break; + } + } + if (selectedTierIndex == -1) { + selectedTierIndex = 0; } } updateButtonText(false); tierListView.getAdapter().notifyDataSetChanged(); } + private boolean setTierListViewVisibility; + private boolean tierListViewVisible; public void updateText() { titleView.setText(LocaleController.getString(forcePremium ? R.string.TelegramPremiumSubscribedTitle : R.string.TelegramPremium)); subtitleView.setText(AndroidUtilities.replaceTags(LocaleController.getString(getUserConfig().isPremium() || forcePremium ? R.string.TelegramPremiumSubscribedSubtitle : R.string.TelegramPremiumSubtitle))); - tierListView.setVisibility(getUserConfig().isPremium() || forcePremium || BuildVars.IS_BILLING_UNAVAILABLE || IS_PREMIUM_TIERS_UNAVAILABLE ? GONE : VISIBLE); + boolean tierNotVisible = forcePremium || BuildVars.IS_BILLING_UNAVAILABLE || IS_PREMIUM_TIERS_UNAVAILABLE || subscriptionTiers.size() <= 1; + if (!setTierListViewVisibility || !tierNotVisible) { + tierListView.setVisibility(tierNotVisible ? GONE : VISIBLE); + setTierListViewVisibility = true; + } else if (tierListView.getVisibility() == VISIBLE && tierNotVisible && tierListViewVisible == tierNotVisible) { + View v = tierListView; + ValueAnimator animator = ValueAnimator.ofFloat(1, 0).setDuration(250); + animator.addUpdateListener(animation -> { + float val = (float) animation.getAnimatedValue(); + v.setAlpha(val); + v.setScaleX(val); + v.setScaleY(val); + + float f = animator.getAnimatedFraction(); + for (int i = 0; i < backgroundView.getChildCount(); i++) { + View ch = backgroundView.getChildAt(i); + if (ch != tierListView) { + float offset = 0; + if (ch == imageFrameLayout) { + offset -= AndroidUtilities.dp(15) * f; + } else { + offset += AndroidUtilities.dp(8) * f; + } + ch.setTranslationY(f * v.getMeasuredHeight() + offset); + } + } + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + v.setVisibility(GONE); + + for (int i = 0; i < backgroundView.getChildCount(); i++) { + View ch = backgroundView.getChildAt(i); + if (ch != tierListView) { + ch.setTranslationY(0); + } + } + } + }); + animator.setInterpolator(CubicBezierInterpolator.DEFAULT); + animator.start(); + } + tierListViewVisible = !tierNotVisible; } } private void updateButtonText(boolean animated) { - if (premiumButtonView == null) { + if (premiumButtonView == null || getUserConfig().isPremium() && currentSubscriptionTier != null && subscriptionTiers.get(selectedTierIndex).getMonths() < currentSubscriptionTier.getMonths()) { return; } + if (LocaleController.isRTL) { + animated = false; + } if (BuildVars.IS_BILLING_UNAVAILABLE) { premiumButtonView.setButton(getPremiumButtonText(currentAccount, subscriptionTiers.get(selectedTierIndex)), v -> buyPremium(this), animated); return; } - if (!BuildVars.useInvoiceBilling() && (!BillingController.getInstance().isReady() || subscriptionTiers.isEmpty() || subscriptionTiers.get(selectedTierIndex).googlePlayProductDetails == null)) { + if (!BuildVars.useInvoiceBilling() && (!BillingController.getInstance().isReady() || subscriptionTiers.isEmpty() || selectedTierIndex >= subscriptionTiers.size() || subscriptionTiers.get(selectedTierIndex).googlePlayProductDetails == null)) { premiumButtonView.setButton(LocaleController.getString(R.string.Loading), v -> {}, animated); premiumButtonView.setFlickerDisabled(true); return; } if (!subscriptionTiers.isEmpty()) { - premiumButtonView.setButton(getPremiumButtonText(currentAccount, subscriptionTiers.get(selectedTierIndex)), v -> buyPremium(this, subscriptionTiers.get(selectedTierIndex), "settings"), animated); + premiumButtonView.setButton(getPremiumButtonText(currentAccount, subscriptionTiers.get(selectedTierIndex)), v -> { + SubscriptionTier tier = subscriptionTiers.get(selectedTierIndex); + BillingFlowParams.SubscriptionUpdateParams updateParams = null; + if (currentSubscriptionTier != null && currentSubscriptionTier.subscriptionOption != null && currentSubscriptionTier.subscriptionOption.transaction != null) { + updateParams = BillingFlowParams.SubscriptionUpdateParams.newBuilder() + .setOldPurchaseToken(BillingController.getInstance().getLastPremiumToken()) + .setReplaceProrationMode(BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_FULL_PRICE) + .build(); + } + buyPremium(this, tier, "settings", true, updateParams); + }, animated); premiumButtonView.setFlickerDisabled(false); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java index a0440988a16..1b919d33feb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java @@ -148,7 +148,7 @@ public class PrivacyControlActivity extends BaseFragment implements Notification private TLRPC.Photo avatarForRestPhoto; @Override - public void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double videoStartTimestamp, String videoPath, TLRPC.PhotoSize bigSize, TLRPC.PhotoSize smallSize, boolean isVideo) { + public void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double videoStartTimestamp, String videoPath, TLRPC.PhotoSize bigSize, TLRPC.PhotoSize smallSize, boolean isVideo, TLRPC.VideoSize emojiMarkup) { AndroidUtilities.runOnUIThread(() -> { avatarForRest = smallSize; avatarForRestPhoto = null; @@ -165,6 +165,10 @@ public void didUploadPhoto(TLRPC.InputFile photo, TLRPC.InputFile video, double req.video_start_ts = videoStartTimestamp; req.flags |= 4; } + if (emojiMarkup != null) { + req.video_emoji_markup = emojiMarkup; + req.flags |= 16; + } req.fallback = true; req.flags |= 8; @@ -389,7 +393,7 @@ public PrivacyControlActivity(int type, boolean load) { ContactsController.getInstance(currentAccount).loadPrivacySettings(); } if (rulesType == PRIVACY_RULES_TYPE_PHOTO) { - imageUpdater = new ImageUpdater(false); + imageUpdater = new ImageUpdater(false, ImageUpdater.FOR_TYPE_USER, true); imageUpdater.parentFragment = this; imageUpdater.setDelegate(this); TLRPC.UserFull userFull = getMessagesController().getUserFull(getUserConfig().clientUserId); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java index c115a9719bf..590aec6c72a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java @@ -86,7 +86,7 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio private int sessionsRow; private int passcodeRow; private int autoDeleteMesages; - private int autoDeleteDetailRow; + private int sessionsDetailRow; private int newChatsHeaderRow; private int newChatsRow; private int newChatsSectionRow; @@ -602,16 +602,15 @@ private void updateRows(boolean notify) { rowCount = 0; securitySectionRow = rowCount++; - blockedRow = rowCount++; - sessionsRow = rowCount++; - passcodeRow = rowCount++; passwordRow = rowCount++; - + autoDeleteMesages = rowCount++; + passcodeRow = rowCount++; if (currentPassword != null ? currentPassword.login_email_pattern != null : SharedConfig.hasEmailLogin) { emailLoginRow = rowCount++; } else { emailLoginRow = -1; } + blockedRow = rowCount++; if (currentPassword != null) { boolean hasEmail = currentPassword.login_email_pattern != null; if (SharedConfig.hasEmailLogin != hasEmail) { @@ -619,8 +618,8 @@ private void updateRows(boolean notify) { SharedConfig.saveConfig(); } } - autoDeleteMesages = rowCount++; - autoDeleteDetailRow = rowCount++; + sessionsRow = rowCount++; + sessionsDetailRow = rowCount++; privacySectionRow = rowCount++; phoneNumberRow = rowCount++; @@ -1028,8 +1027,8 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else if (position == groupsDetailRow) { privacyCell.setText(LocaleController.getString("GroupsAndChannelsHelp", R.string.GroupsAndChannelsHelp)); privacyCell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); - } else if (position == autoDeleteDetailRow) { - privacyCell.setText(LocaleController.getString("AutoDeleteSettingsInfo", R.string.AutoDeleteSettingsInfo)); + } else if (position == sessionsDetailRow) { + privacyCell.setText(LocaleController.getString("SessionsSettingsInfo", R.string.SessionsSettingsInfo)); privacyCell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); } else if (position == secretDetailRow) { privacyCell.setText(LocaleController.getString("SecretWebPageInfo", R.string.SecretWebPageInfo)); @@ -1087,6 +1086,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { showLoading = false; loadingLen = 16; value = null; + textCell2.setPrioritizeTitleOverValue(false); if (position == autoDeleteMesages) { int ttl = getUserConfig().getGlobalTTl(); if (ttl == -1) { @@ -1096,23 +1096,39 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else { value = LocaleController.getString("PasswordOff", R.string.PasswordOff); } - textCell2.setTextAndValueAndIcon(LocaleController.getString("AutoDeleteMessages", R.string.AutoDeleteMessages), value, R.drawable.msg_autodelete, false); + textCell2.setTextAndValueAndColorfulIcon(LocaleController.getString("AutoDeleteMessages", R.string.AutoDeleteMessages), value, true, R.drawable.msg_filled_autodelete, getThemedColor(Theme.key_color_lightblue), true); } else if (position == sessionsRow) { String count = ""; - if (sessionsActivityPreload.getSessionsCount() == 0) { if (getMessagesController().lastKnownSessionsCount == 0) { showLoading = true; } else { - count = Integer.toString(getMessagesController().lastKnownSessionsCount); + count = String.format(LocaleController.getInstance().getCurrentLocale(), "%d", getMessagesController().lastKnownSessionsCount); } } else { - count = Integer.toString(sessionsActivityPreload.getSessionsCount()); + count = String.format(LocaleController.getInstance().getCurrentLocale(), "%d", sessionsActivityPreload.getSessionsCount()); } getMessagesController().lastKnownSessionsCount = sessionsActivityPreload.getSessionsCount(); - textCell2.setTextAndValueAndIcon(LocaleController.getString("SessionsTitle", R.string.SessionsTitle), count, R.drawable.msg_devices, true); + textCell2.setTextAndValueAndColorfulIcon(LocaleController.getString("SessionsTitle", R.string.SessionsTitle), count, true, R.drawable.msg_filled_devices, getThemedColor(Theme.key_color_yellow), false); } else if (position == emailLoginRow) { - textCell2.setTextAndValueAndIcon(LocaleController.getString(R.string.EmailLogin), "", R.drawable.msg_email, true); + CharSequence val = ""; + if (currentPassword == null) { + showLoading = true; + } else { + SpannableStringBuilder spannable = SpannableStringBuilder.valueOf(currentPassword.login_email_pattern); + int startIndex = currentPassword.login_email_pattern.indexOf('*'); + int endIndex = currentPassword.login_email_pattern.lastIndexOf('*'); + if (startIndex != endIndex && startIndex != -1 && endIndex != -1) { + TextStyleSpan.TextStyleRun run = new TextStyleSpan.TextStyleRun(); + run.flags |= TextStyleSpan.FLAG_STYLE_SPOILER; + run.start = startIndex; + run.end = endIndex + 1; + spannable.setSpan(new TextStyleSpan(run), startIndex, endIndex + 1, 0); + } + val = spannable; + } + textCell2.setPrioritizeTitleOverValue(true); + textCell2.setTextAndSpoilersValueAndColorfulIcon(LocaleController.getString(R.string.EmailLogin), val, R.drawable.msg_filled_email, getThemedColor(Theme.key_color_orange), true); } else if (position == passwordRow) { value = ""; if (currentPassword == null) { @@ -1122,24 +1138,28 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else { value = LocaleController.getString("PasswordOff", R.string.PasswordOff); } - textCell2.setTextAndValueAndIcon(LocaleController.getString("TwoStepVerification", R.string.TwoStepVerification), value, R.drawable.msg_secret, true); + textCell2.setTextAndValueAndColorfulIcon(LocaleController.getString("TwoStepVerification", R.string.TwoStepVerification), value, true, R.drawable.msg_filled_permissions, getThemedColor(Theme.key_color_blue), true); } else if (position == passcodeRow) { + int icon; if (SharedConfig.passcodeHash.length() != 0) { value = LocaleController.getString("PasswordOn", R.string.PasswordOn); + icon = R.drawable.msg_filled_passcode_on; } else { value = LocaleController.getString("PasswordOff", R.string.PasswordOff); + icon = R.drawable.msg_filled_passcode_off; } - textCell2.setTextAndValueAndIcon(LocaleController.getString("Passcode", R.string.Passcode), value, R.drawable.msg_permissions, true); + textCell2.setTextAndValueAndColorfulIcon(LocaleController.getString("Passcode", R.string.Passcode), value, true, icon, getThemedColor(Theme.key_color_green), true); } else if (position == blockedRow) { int totalCount = getMessagesController().totalBlockedCount; if (totalCount == 0) { - textCell2.setTextAndValueAndIcon(LocaleController.getString("BlockedUsers", R.string.BlockedUsers), LocaleController.getString("BlockedEmpty", R.string.BlockedEmpty), R.drawable.msg_block2, true); + value = LocaleController.getString("BlockedEmpty", R.string.BlockedEmpty); } else if (totalCount > 0) { - textCell2.setTextAndValueAndIcon(LocaleController.getString("BlockedUsers", R.string.BlockedUsers), String.format("%d", totalCount), R.drawable.msg_block2, true); + value = String.format(LocaleController.getInstance().getCurrentLocale(), "%d", totalCount); } else { showLoading = true; - textCell2.setTextAndValueAndIcon(LocaleController.getString("BlockedUsers", R.string.BlockedUsers), "", R.drawable.msg_block2, true); + value = ""; } + textCell2.setTextAndValueAndColorfulIcon(LocaleController.getString("BlockedUsers", R.string.BlockedUsers), value, true, R.drawable.msg_filled_blocked, getThemedColor(Theme.key_color_red), true); } textCell2.setDrawLoading(showLoading, loadingLen, animated); break; @@ -1152,7 +1172,7 @@ public int getItemViewType(int position) { position == deleteAccountRow || position == webSessionsRow || position == groupsRow || position == paymentsClearRow || position == secretMapRow || position == contactsDeleteRow) { return 0; - } else if (position == deleteAccountDetailRow || position == groupsDetailRow || position == autoDeleteDetailRow || position == secretDetailRow || position == botsDetailRow || position == contactsDetailRow || position == newChatsSectionRow) { + } else if (position == deleteAccountDetailRow || position == groupsDetailRow || position == sessionsDetailRow || position == secretDetailRow || position == botsDetailRow || position == contactsDetailRow || position == newChatsSectionRow) { return 1; } else if (position == securitySectionRow || position == advancedSectionRow || position == privacySectionRow || position == secretSectionRow || position == botsSectionRow || position == contactsSectionRow || position == newChatsHeaderRow) { return 2; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java index 4d22c1461b5..c8a67e9349c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -27,7 +27,6 @@ import android.content.pm.PackageManager; import android.content.res.Configuration; import android.database.DataSetObserver; -import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; @@ -202,9 +201,10 @@ import org.telegram.ui.Components.SizeNotifierFrameLayout; import org.telegram.ui.Components.StickerEmptyView; import org.telegram.ui.Components.TimerDrawable; -import org.telegram.ui.Components.TranslateAlert; +import org.telegram.ui.Components.TranslateAlert2; import org.telegram.ui.Components.TypefaceSpan; import org.telegram.ui.Components.UndoView; +import org.telegram.ui.Components.VectorAvatarThumbDrawable; import org.telegram.ui.Components.voip.VoIPHelper; import java.io.BufferedInputStream; @@ -626,6 +626,7 @@ public static class AvatarImageView extends BackupImageView { private ImageReceiver foregroundImageReceiver; private float foregroundAlpha; private ImageReceiver.BitmapHolder drawableHolder; + boolean drawForeground = true; ProfileGalleryView avatarsViewPager; @@ -706,11 +707,11 @@ public void setRoundRadius(int value) { @Override protected void onDraw(Canvas canvas) { ImageReceiver imageReceiver = animatedEmojiDrawable != null ? animatedEmojiDrawable.getImageReceiver() : this.imageReceiver; - if (imageReceiver != null && foregroundAlpha < 1f) { + if (imageReceiver != null && (foregroundAlpha < 1f || !drawForeground)) { imageReceiver.setImageCoords(0, 0, getMeasuredWidth(), getMeasuredHeight()); imageReceiver.draw(canvas); } - if (foregroundAlpha > 0f) { + if (foregroundAlpha > 0f && drawForeground) { if (foregroundImageReceiver.getDrawable() != null) { foregroundImageReceiver.setImageCoords(0, 0, getMeasuredWidth(), getMeasuredHeight()); foregroundImageReceiver.setAlpha(foregroundAlpha); @@ -731,6 +732,10 @@ public void invalidate() { avatarsViewPager.invalidate(); } } + + public void drawForeground(boolean drawForeground) { + this.drawForeground = drawForeground; + } } private class TopView extends View { @@ -1503,7 +1508,7 @@ public boolean onFragmentCreate() { participantsMap = null; if (UserObject.isUserSelf(user)) { - imageUpdater = new ImageUpdater(true); + imageUpdater = new ImageUpdater(true, ImageUpdater.FOR_TYPE_USER, true); imageUpdater.setOpenWithFrontfaceCamera(true); imageUpdater.parentFragment = this; imageUpdater.setDelegate(this); @@ -1805,7 +1810,7 @@ public void onItemClick(final int id) { } else if (id == share_contact) { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); args.putString("selectAlertString", LocaleController.getString("SendContactToText", R.string.SendContactToText)); args.putString("selectAlertStringGroup", LocaleController.getString("SendContactToGroupText", R.string.SendContactToGroupText)); DialogsActivity fragment = new DialogsActivity(args); @@ -1895,7 +1900,7 @@ public void onClick(DialogInterface dialog, int which) { } Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 2); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_ADD_USERS_TO); args.putBoolean("resetDelegate", false); args.putBoolean("closeFragment", false); // args.putString("addToGroupAlertString", LocaleController.formatString("AddToTheGroupAlertText", R.string.AddToTheGroupAlertText, UserObject.getUserName(user), "%1$s")); @@ -1945,6 +1950,7 @@ public void didChangeOwner(TLRPC.User user) { }); showDialog(builder.create()); } + return true; }); presentFragment(fragment); } else if (id == share) { @@ -2147,7 +2153,7 @@ public void didChangeOwner(TLRPC.User user) { int position = avatarsViewPager.getRealPosition(); TLRPC.Photo photo = avatarsViewPager.getPhoto(position); TLRPC.UserFull userFull = getUserInfo(); - if (hasFallbackPhoto && userFull != null && userFull.fallback_photo != null && userFull.fallback_photo.id == photo.id) { + if (hasFallbackPhoto && photo != null && userFull != null && userFull.fallback_photo != null && userFull.fallback_photo.id == photo.id) { userFull.fallback_photo = null; userFull.flags &= ~4194304; getMessagesStorage().updateUserInfo(userFull, true); @@ -2454,6 +2460,11 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { }); wasPortrait = portrait; } + + if (searchItem != null && qrItem != null) { + float translation = AndroidUtilities.dp(48) * currentExpandAnimatorValue; + // qrItem.setTranslationX(translation); + } } @Override @@ -2961,7 +2972,6 @@ public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerVi cells[0].setOnClickListener(v -> { cells[0].setChecked(!cells[0].isChecked(), true); }); - builder.setCustomViewOffset(12); builder.setView(linearLayout); } @@ -3211,9 +3221,9 @@ public void openExceptions() { } else if (position == policyRow) { Browser.openUrl(getParentActivity(), LocaleController.getString("PrivacyPolicyUrl", R.string.PrivacyPolicyUrl)); } else if (position == sendLogsRow) { - sendLogs(false); + sendLogs(getParentActivity(), false); } else if (position == sendLastLogsRow) { - sendLogs(true); + sendLogs(getParentActivity(), true); } else if (position == clearLogsRow) { FileLog.cleanupLogs(); } else if (position == switchBackendRow) { @@ -3286,6 +3296,7 @@ public boolean onItemClick(View view, int position) { (AndroidUtilities.isTabletInternal() && BuildVars.DEBUG_PRIVATE_VERSION) ? (SharedConfig.forceDisableTabletMode ? "Enable tablet mode" : "Disable tablet mode") : null, LocaleController.getString(SharedConfig.useLNavigation ? R.string.AltNavigationDisable : R.string.AltNavigationEnable), BuildVars.DEBUG_PRIVATE_VERSION ? LocaleController.getString(SharedConfig.isFloatingDebugActive ? R.string.FloatingDebugDisable : R.string.FloatingDebugEnable) : null, + BuildVars.DEBUG_PRIVATE_VERSION ? "Force remove premium suggestions" : null }; builder.setItems(items, (dialog, which) -> { @@ -3312,7 +3323,7 @@ public boolean onItemClick(View view, int position) { SharedConfig.setNoSoundHintShowed(false); SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit(); editor.remove("archivehint").remove("proximityhint").remove("archivehint_l").remove("gifhint").remove("reminderhint").remove("soundHint").remove("themehint").remove("bganimationhint").remove("filterhint").commit(); - MessagesController.getEmojiSettings(currentAccount).edit().remove("featured_hidden").commit(); + MessagesController.getEmojiSettings(currentAccount).edit().remove("featured_hidden").remove("emoji_featured_hidden").commit(); SharedConfig.textSelectionHintShows = 0; SharedConfig.lockRecordAudioVideoHint = 0; SharedConfig.stickersReorderingHintUsed = false; @@ -3322,6 +3333,8 @@ public boolean onItemClick(View view, int position) { SharedConfig.dayNightThemeSwitchHintCount = 3; SharedConfig.fastScrollHintCount = 3; ChatThemeController.getInstance(currentAccount).clearCache(); + getNotificationCenter().postNotificationName(NotificationCenter.newSuggestionsAvailable); + RestrictedLanguagesSelectActivity.cleanup(); } else if (which == 7) { VoIPHelper.showCallDebugSettings(getParentActivity()); } else if (which == 8) { @@ -3381,6 +3394,18 @@ public boolean onItemClick(View view, int position) { getParentActivity().recreate(); } else if (which == 22) { FloatingDebugController.setActive((LaunchActivity) getParentActivity(), !FloatingDebugController.isActive()); + } else if (which == 23) { + TLRPC.TL_help_dismissSuggestion req = new TLRPC.TL_help_dismissSuggestion(); + req.suggestion = "VALIDATE_PHONE_NUMBER"; + req.peer = new TLRPC.TL_inputPeerEmpty(); + getConnectionsManager().sendRequest(req, (response, error) -> { + TLRPC.TL_help_dismissSuggestion req2 = new TLRPC.TL_help_dismissSuggestion(); + req2.suggestion = "VALIDATE_PASSWORD"; + req2.peer = new TLRPC.TL_inputPeerEmpty(); + getConnectionsManager().sendRequest(req2, (res2, err2) -> { + getMessagesController().loadAppConfig(); + }); + }); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); @@ -4083,10 +4108,7 @@ public void onZoomStarted(MessageObject messageObject) { if (sharedMediaLayout != null && sharedMediaLayout.getCurrentListView() != null) { sharedMediaLayout.getCurrentListView().cancelClickRunnables(true); } - Bitmap bitmap = pinchToZoomHelper.getPhotoImage() == null ? null : pinchToZoomHelper.getPhotoImage().getBitmap(); - if (bitmap != null) { - topView.setBackgroundColor(ColorUtils.blendARGB(AndroidUtilities.calcBitmapColor(bitmap), getThemedColor(Theme.key_windowBackgroundWhite), 0.1f)); - } + topView.setBackgroundColor(ColorUtils.blendARGB(getAverageColor(pinchToZoomHelper.getPhotoImage()), getThemedColor(Theme.key_windowBackgroundWhite), 0.1f)); } }); avatarsViewPager.setPinchToZoomHelper(pinchToZoomHelper); @@ -4182,6 +4204,7 @@ private void setAvatarExpandProgress(float animatedFracture) { nameTextView[1].setTextColor(ColorUtils.blendARGB(getThemedColor(Theme.key_profile_title), Color.WHITE, value)); actionBar.setItemsColor(ColorUtils.blendARGB(getThemedColor(Theme.key_actionBarDefaultIcon), Color.WHITE, value), false); + actionBar.setMenuOffsetSuppressed(true); avatarImage.setForegroundAlpha(value); @@ -4903,7 +4926,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { } final String[] fromLanguage = new String[1]; fromLanguage[0] = "und"; - final boolean translateButtonEnabled = MessagesController.getGlobalMainSettings().getBoolean("translate_button", false); + final boolean translateButtonEnabled = MessagesController.getInstance(currentAccount).getTranslateController().isContextTranslateEnabled(); final boolean[] withTranslate = new boolean[1]; withTranslate[0] = position == bioRow || position == channelInfoRow || position == userInfoRow; final String toLang = LocaleController.getInstance().getCurrentLocale().getLanguage(); @@ -4945,7 +4968,7 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { BulletinFactory.of(this).createCopyBulletin(LocaleController.getString("TextCopied", R.string.TextCopied)).show(); } } else if (j == 1) { - TranslateAlert.showAlert(fragmentView.getContext(), this, currentAccount, fromLanguage[0], toLang, finalText, false, span -> { + TranslateAlert2.showAlert(fragmentView.getContext(), this, currentAccount, fromLanguage[0], toLang, finalText, null, false, span -> { if (span != null) { openUrl(span.getURL(), null); return true; @@ -5583,7 +5606,12 @@ public void onAnimationEnd(Animator animation) { if (!doNotSetForeground) { BackupImageView imageView = avatarsViewPager.getCurrentItemView(); if (imageView != null) { - avatarImage.setForegroundImageDrawable(imageView.getImageReceiver().getDrawableSafe()); + if (imageView.getImageReceiver().getDrawable() instanceof VectorAvatarThumbDrawable) { + avatarImage.drawForeground(false); + } else { + avatarImage.drawForeground(true); + avatarImage.setForegroundImageDrawable(imageView.getImageReceiver().getDrawableSafe()); + } } } avatarImage.setForegroundAlpha(1f); @@ -5762,7 +5790,9 @@ public void onAnimationEnd(Animator animation) { private void setForegroundImage(boolean secondParent) { Drawable drawable = avatarImage.getImageReceiver().getDrawable(); - if (drawable instanceof AnimatedFileDrawable) { + if (drawable instanceof VectorAvatarThumbDrawable) { + avatarImage.setForegroundImage(null, null, drawable); + } else if (drawable instanceof AnimatedFileDrawable) { AnimatedFileDrawable fileDrawable = (AnimatedFileDrawable) drawable; avatarImage.setForegroundImage(null, null, fileDrawable); if (secondParent) { @@ -6482,7 +6512,7 @@ public AnimatorSet onCustomTransitionAnimation(final boolean isOpen, final Runna animators.add(ObjectAnimator.ofFloat(writeButton, View.ALPHA, 1.0f)); } if (playProfileAnimation == 2) { - avatarColor = AndroidUtilities.calcBitmapColor(avatarImage.getImageReceiver().getBitmap()); + avatarColor = getAverageColor(avatarImage.getImageReceiver()); nameTextView[1].setTextColor(Color.WHITE); onlineTextView[1].setTextColor(Color.argb(179, 255, 255, 255)); actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR, false); @@ -6632,6 +6662,13 @@ public void onAnimationEnd(Animator animation) { return null; } + private int getAverageColor(ImageReceiver imageReceiver) { + if (imageReceiver.getDrawable() instanceof VectorAvatarThumbDrawable) { + return ((VectorAvatarThumbDrawable)imageReceiver.getDrawable()).gradientTools.getAverageColor(); + } + return AndroidUtilities.calcBitmapColor(avatarImage.getImageReceiver().getBitmap()); + } + private void updateOnlineCount(boolean notify) { onlineCount = 0; int currentTime = getConnectionsManager().getCurrentTime(); @@ -7205,7 +7242,7 @@ private void updateEmojiStatusEffectPosition() { } private void updateProfileData(boolean reload) { - if (avatarContainer == null || nameTextView == null) { + if (avatarContainer == null || nameTextView == null || getParentActivity() == null) { return; } String onlineTextOverride; @@ -7241,11 +7278,23 @@ private void updateProfileData(boolean reload) { final ImageLocation imageLocation = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_BIG); final ImageLocation thumbLocation = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL); - final ImageLocation videoThumbLocation = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_VIDEO_THUMB); + final ImageLocation videoThumbLocation = ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_VIDEO_BIG); + VectorAvatarThumbDrawable vectorAvatarThumbDrawable = null; + TLRPC.VideoSize vectorAvatar = null; + if (userInfo != null) { + vectorAvatar = FileLoader.getVectorMarkupVideoSize(user.photo != null && user.photo.personal ? userInfo.personal_photo : userInfo.profile_photo); + if (vectorAvatar != null) { + vectorAvatarThumbDrawable = new VectorAvatarThumbDrawable(vectorAvatar, user.premium, VectorAvatarThumbDrawable.TYPE_PROFILE); + } + } final ImageLocation videoLocation = avatarsViewPager.getCurrentVideoLocation(thumbLocation, imageLocation); - avatarsViewPager.initIfEmpty(imageLocation, thumbLocation, reload); + if (avatar == null) { + avatarsViewPager.initIfEmpty(vectorAvatarThumbDrawable, imageLocation, thumbLocation, reload); + } if (avatarBig == null) { - if (videoThumbLocation != null && !user.photo.personal) { + if (vectorAvatar != null) { + avatarImage.setImageDrawable(vectorAvatarThumbDrawable); + } else if (videoThumbLocation != null && !user.photo.personal) { avatarImage.getImageReceiver().setVideoThumbIsSame(true); avatarImage.setImage(videoThumbLocation, "avatar", thumbLocation, "50_50", avatarDrawable, user); } else { @@ -7647,7 +7696,7 @@ private void updateProfileData(boolean reload) { videoLocation = avatarsViewPager.getCurrentVideoLocation(thumbLocation, imageLocation); } - boolean initied = avatarsViewPager.initIfEmpty(imageLocation, thumbLocation, reload); + boolean initied = avatarsViewPager.initIfEmpty(null, imageLocation, thumbLocation, reload); if ((imageLocation == null || initied) && isPulledDown) { final View view = layoutManager.findViewByPosition(0); if (view != null) { @@ -7970,7 +8019,7 @@ protected void onDialogDismiss(Dialog dialog) { } @Override - public void didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param) { + public boolean didSelectDialogs(DialogsActivity fragment, ArrayList dids, CharSequence message, boolean param) { long did = dids.get(0).dialogId; Bundle args = new Bundle(); args.putBoolean("scrollToTopOnResume", true); @@ -7982,7 +8031,7 @@ public void didSelectDialogs(DialogsActivity fragment, ArrayList { - if (photo != null || video != null) { + if (photo != null || video != null || emojiMarkup != null) { TLRPC.TL_photos_uploadProfilePhoto req = new TLRPC.TL_photos_uploadProfilePhoto(); if (photo != null) { req.file = photo; @@ -8253,8 +8303,11 @@ public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile vi req.video_start_ts = videoStartTimestamp; req.flags |= 4; } + if (emojiMarkup != null) { + req.video_emoji_markup = emojiMarkup; + req.flags |= 16; + } getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { - avatarsViewPager.removeUploadingImage(uploadingImageLocation); if (error == null) { TLRPC.User user = getMessagesController().getUser(getUserConfig().getClientUserId()); if (user == null) { @@ -8266,11 +8319,12 @@ public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile vi } else { getUserConfig().setCurrentUser(user); } + TLRPC.TL_photos_photo photos_photo = (TLRPC.TL_photos_photo) response; ArrayList sizes = photos_photo.photo.sizes; TLRPC.PhotoSize small = FileLoader.getClosestPhotoSizeWithSize(sizes, 150); TLRPC.PhotoSize big = FileLoader.getClosestPhotoSizeWithSize(sizes, 800); - TLRPC.VideoSize videoSize = photos_photo.photo.video_sizes.isEmpty() ? null : photos_photo.photo.video_sizes.get(0); + TLRPC.VideoSize videoSize = photos_photo.photo.video_sizes.isEmpty() ? null : FileLoader.getClosestVideoSizeWithSize(photos_photo.photo.video_sizes, 1000); user.photo = new TLRPC.TL_userProfilePhoto(); user.photo.photo_id = photos_photo.photo.id; if (small != null) { @@ -8288,32 +8342,37 @@ public void didUploadPhoto(final TLRPC.InputFile photo, final TLRPC.InputFile vi String newKey = small.location.volume_id + "_" + small.location.local_id + "@50_50"; ImageLoader.getInstance().replaceImageInCache(oldKey, newKey, ImageLocation.getForUserOrChat(user, ImageLocation.TYPE_SMALL), false); } - if (big != null && avatarBig != null) { - File destFile = FileLoader.getInstance(currentAccount).getPathToAttach(big, true); - File src = FileLoader.getInstance(currentAccount).getPathToAttach(avatarBig, true); - src.renameTo(destFile); - } + if (videoSize != null && videoPath != null) { File destFile = FileLoader.getInstance(currentAccount).getPathToAttach(videoSize, "mp4", true); File src = new File(videoPath); src.renameTo(destFile); + } else if (big != null && avatarBig != null) { + File destFile = FileLoader.getInstance(currentAccount).getPathToAttach(big, true); + File src = FileLoader.getInstance(currentAccount).getPathToAttach(avatarBig, true); + src.renameTo(destFile); } - - getMessagesStorage().clearUserPhotos(user.id); + getMessagesStorage().addDialogPhoto(user.id, ((TLRPC.TL_photos_photo) response).photo); ArrayList users = new ArrayList<>(); users.add(user); getMessagesStorage().putUsersAndChats(users, null, false, true); + TLRPC.UserFull userFull = getMessagesController().getUserFull(userId); + userFull.profile_photo = photos_photo.photo; + getMessagesStorage().updateUserInfo(userFull, false); } allowPullingDown = !AndroidUtilities.isTablet() && !isInLandscapeMode && avatarImage.getImageReceiver().hasNotThumb() && !AndroidUtilities.isAccessibilityScreenReaderEnabled(); avatar = null; avatarBig = null; + avatarsViewPager.scrolledByUser = true; + avatarsViewPager.removeUploadingImage(uploadingImageLocation); avatarsViewPager.setCreateThumbFromParent(false); updateProfileData(true); showAvatarProgress(false, true); getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_ALL); getNotificationCenter().postNotificationName(NotificationCenter.mainUserInfoChanged); getUserConfig().saveConfig(true); + })); } else { avatar = smallSize.location; @@ -8400,11 +8459,11 @@ public void restoreSelfArgs(Bundle args) { } } - private void sendLogs(boolean last) { - if (getParentActivity() == null) { + public static void sendLogs(Activity activity, boolean last) { + if (activity == null) { return; } - AlertDialog progressDialog = new AlertDialog(getParentActivity(), AlertDialog.ALERT_TYPE_SPINNER); + AlertDialog progressDialog = new AlertDialog(activity, AlertDialog.ALERT_TYPE_SPINNER); progressDialog.setCanCancel(false); progressDialog.show(); Utilities.globalQueue.postRunnable(() -> { @@ -8425,7 +8484,7 @@ private void sendLogs(boolean last) { } if (FileLog.databaseIsMalformed) { - files.addAll(getMessagesStorage().getDatabaseFiles()); + files.addAll(MessagesStorage.getInstance(UserConfig.selectedAccount).getDatabaseFiles()); } boolean[] finished = new boolean[1]; @@ -8479,7 +8538,7 @@ private void sendLogs(boolean last) { if (finished[0]) { Uri uri; if (Build.VERSION.SDK_INT >= 24) { - uri = FileProvider.getUriForFile(getParentActivity(), ApplicationLoader.getApplicationId() + ".provider", zipFile); + uri = FileProvider.getUriForFile(activity, ApplicationLoader.getApplicationId() + ".provider", zipFile); } else { uri = Uri.fromFile(zipFile); } @@ -8492,16 +8551,16 @@ private void sendLogs(boolean last) { i.putExtra(Intent.EXTRA_EMAIL, ""); i.putExtra(Intent.EXTRA_SUBJECT, "Logs from " + LocaleController.getInstance().formatterStats.format(System.currentTimeMillis())); i.putExtra(Intent.EXTRA_STREAM, uri); - if (getParentActivity() != null) { + if (activity != null) { try { - getParentActivity().startActivityForResult(Intent.createChooser(i, "Select email application."), 500); + activity.startActivityForResult(Intent.createChooser(i, "Select email application."), 500); } catch (Exception e) { FileLog.e(e); } } } else { - if (getParentActivity() != null) { - Toast.makeText(getParentActivity(), LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred), Toast.LENGTH_SHORT).show(); + if (activity != null) { + Toast.makeText(activity, LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred), Toast.LENGTH_SHORT).show(); } } }); @@ -9522,7 +9581,7 @@ private SearchResult[] onCreateSearchArray() { new SearchResult(203, LocaleController.getString("KeepMedia", R.string.KeepMedia), "keepMediaRow", LocaleController.getString("DataSettings", R.string.DataSettings), LocaleController.getString("StorageUsage", R.string.StorageUsage), R.drawable.msg_data, () -> presentFragment(new CacheControlActivity())), new SearchResult(204, LocaleController.getString("ClearMediaCache", R.string.ClearMediaCache), "cacheRow", LocaleController.getString("DataSettings", R.string.DataSettings), LocaleController.getString("StorageUsage", R.string.StorageUsage), R.drawable.msg_data, () -> presentFragment(new CacheControlActivity())), new SearchResult(205, LocaleController.getString("LocalDatabase", R.string.LocalDatabase), "databaseRow", LocaleController.getString("DataSettings", R.string.DataSettings), LocaleController.getString("StorageUsage", R.string.StorageUsage), R.drawable.msg_data, () -> presentFragment(new CacheControlActivity())), - new SearchResult(206, LocaleController.getString("NetworkUsage", R.string.NetworkUsage), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataUsageActivity())), + new SearchResult(206, LocaleController.getString("NetworkUsage", R.string.NetworkUsage), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataUsage2Activity())), new SearchResult(207, LocaleController.getString("AutomaticMediaDownload", R.string.AutomaticMediaDownload), "mediaDownloadSectionRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), new SearchResult(208, LocaleController.getString("WhenUsingMobileData", R.string.WhenUsingMobileData), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataAutoDownloadActivity(0))), new SearchResult(209, LocaleController.getString("WhenConnectedOnWiFi", R.string.WhenConnectedOnWiFi), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataAutoDownloadActivity(1))), @@ -9599,7 +9658,7 @@ private SearchResult[] onCreateSearchArray() { new SearchResult(400, LocaleController.getString("Language", R.string.Language), R.drawable.msg_language, () -> presentFragment(new LanguageSelectActivity())), new SearchResult(405, LocaleController.getString(R.string.ShowTranslateButton), LocaleController.getString(R.string.Language), R.drawable.msg_language, () -> presentFragment(new LanguageSelectActivity())), - MessagesController.getGlobalMainSettings().getBoolean("translate_button", false) ? new SearchResult(406, LocaleController.getString(R.string.DoNotTranslate), LocaleController.getString(R.string.Language), R.drawable.msg_language, () -> presentFragment(new LanguageSelectActivity())) : null, + MessagesController.getInstance(currentAccount).getTranslateController().isContextTranslateEnabled() ? new SearchResult(406, LocaleController.getString(R.string.DoNotTranslate), LocaleController.getString(R.string.Language), R.drawable.msg_language, () -> presentFragment(new LanguageSelectActivity())) : null, new SearchResult(402, LocaleController.getString("AskAQuestion", R.string.AskAQuestion), LocaleController.getString("SettingsHelp", R.string.SettingsHelp), R.drawable.msg_help, () -> showDialog(AlertsCreator.createSupportAlert(ProfileActivity.this, null))), new SearchResult(403, LocaleController.getString("TelegramFAQ", R.string.TelegramFAQ), LocaleController.getString("SettingsHelp", R.string.SettingsHelp), R.drawable.msg_help, () -> Browser.openUrl(getParentActivity(), LocaleController.getString("TelegramFaqUrl", R.string.TelegramFaqUrl))), diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProxyListActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProxyListActivity.java index f1c31c16198..eee2f7b8bee 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProxyListActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProxyListActivity.java @@ -41,6 +41,7 @@ import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.ProxyRotationController; import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.tgnet.ConnectionsManager; @@ -62,12 +63,14 @@ import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.NumberTextView; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.SlideChooseView; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class ProxyListActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + private final static boolean IS_PROXY_ROTATION_AVAILABLE = true; private static final int MENU_DELETE = 0; private static final int MENU_SHARE = 1; @@ -83,13 +86,16 @@ public class ProxyListActivity extends BaseFragment implements NotificationCente private int rowCount; private int useProxyRow; - private int useProxyDetailRow; + private int useProxyShadowRow; private int connectionsHeaderRow; private int proxyStartRow; private int proxyEndRow; private int proxyAddRow; - private int proxyDetailRow; + private int proxyShadowRow; private int callsRow; + private int rotationRow; + private int rotationTimeoutRow; + private int rotationTimeoutInfoRow; private int callsDetailRow; private int deleteAllRow; @@ -149,7 +155,7 @@ public TextDetailProxyCell(Context context) { checkImageView.setOnClickListener(v -> presentFragment(new ProxySettingsActivity(currentInfo))); checkBox = new CheckBox2(context, 21); - checkBox.setColor(Theme.key_radioBackground, Theme.key_radioBackground, Theme.key_checkboxCheck); + checkBox.setColor(Theme.key_checkbox, Theme.key_radioBackground, Theme.key_checkboxCheck); checkBox.setDrawBackgroundAsArc(14); checkBox.setVisibility(GONE); addView(checkBox, LayoutHelper.createFrame(24, 24, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL, 16, 0, 8, 0)); @@ -324,6 +330,7 @@ public boolean onFragmentCreate() { SharedConfig.loadProxyList(); currentConnectionState = ConnectionsManager.getInstance(currentAccount).getConnectionState(); + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.proxyChangedByRotation); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.proxySettingsChanged); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.proxyCheckDone); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.didUpdateConnectionState); @@ -340,6 +347,7 @@ public boolean onFragmentCreate() { @Override public void onFragmentDestroy() { super.onFragmentDestroy(); + NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.proxyChangedByRotation); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.proxySettingsChanged); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.proxyCheckDone); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.didUpdateConnectionState); @@ -404,6 +412,7 @@ protected void dispatchDraw(Canvas canvas) { } } useProxySettings = !useProxySettings; + updateRows(true); SharedPreferences preferences = MessagesController.getGlobalMainSettings(); @@ -434,7 +443,13 @@ protected void dispatchDraw(Canvas canvas) { cell.updateStatus(); } } + } else if (position == rotationRow) { + SharedConfig.proxyRotationEnabled = !SharedConfig.proxyRotationEnabled; + TextCheckCell textCheckCell = (TextCheckCell) view; + textCheckCell.setChecked(SharedConfig.proxyRotationEnabled); + SharedConfig.saveConfig(); + updateRows(true); } else if (position == callsRow) { useProxyForCalls = !useProxyForCalls; TextCheckCell textCheckCell = (TextCheckCell) view; @@ -609,7 +624,25 @@ public boolean onBackPressed() { private void updateRows(boolean notify) { rowCount = 0; useProxyRow = rowCount++; - useProxyDetailRow = rowCount++; + if (useProxySettings && SharedConfig.currentProxy != null && SharedConfig.proxyList.size() > 1 && IS_PROXY_ROTATION_AVAILABLE) { + rotationRow = rowCount++; + if (SharedConfig.proxyRotationEnabled) { + rotationTimeoutRow = rowCount++; + rotationTimeoutInfoRow = rowCount++; + } else { + rotationTimeoutRow = -1; + rotationTimeoutInfoRow = -1; + } + } else { + rotationRow = -1; + rotationTimeoutRow = -1; + rotationTimeoutInfoRow = -1; + } + if (rotationTimeoutInfoRow == -1) { + useProxyShadowRow = rowCount++; + } else { + useProxyShadowRow = -1; + } connectionsHeaderRow = rowCount++; if (notify) { @@ -653,22 +686,22 @@ private void updateRows(boolean notify) { proxyEndRow = -1; } proxyAddRow = rowCount++; - proxyDetailRow = rowCount++; + proxyShadowRow = rowCount++; if (SharedConfig.currentProxy == null || SharedConfig.currentProxy.secret.isEmpty()) { boolean change = callsRow == -1; callsRow = rowCount++; callsDetailRow = rowCount++; if (!notify && change) { - listAdapter.notifyItemChanged(proxyDetailRow); - listAdapter.notifyItemRangeInserted(proxyDetailRow + 1, 2); + listAdapter.notifyItemChanged(proxyShadowRow); + listAdapter.notifyItemRangeInserted(proxyShadowRow + 1, 2); } } else { boolean change = callsRow != -1; callsRow = -1; callsDetailRow = -1; if (!notify && change) { - listAdapter.notifyItemChanged(proxyDetailRow); - listAdapter.notifyItemRangeRemoved(proxyDetailRow + 1, 2); + listAdapter.notifyItemChanged(proxyShadowRow); + listAdapter.notifyItemRangeRemoved(proxyShadowRow + 1, 2); } } if (proxyList.size() >= 10) { @@ -719,7 +752,18 @@ public void onResume() { @Override public void didReceivedNotification(int id, int account, Object... args) { - if (id == NotificationCenter.proxySettingsChanged) { + if (id == NotificationCenter.proxyChangedByRotation) { + listView.forAllChild(view -> { + RecyclerView.ViewHolder holder = listView.getChildViewHolder(view); + if (holder.itemView instanceof TextDetailProxyCell) { + TextDetailProxyCell cell = (TextDetailProxyCell) holder.itemView; + cell.setChecked(cell.currentInfo == SharedConfig.currentProxy); + cell.updateStatus(); + } + }); + + updateRows(false); + } else if (id == NotificationCenter.proxySettingsChanged) { updateRows(true); } else if (id == NotificationCenter.didUpdateConnectionState) { int state = ConnectionsManager.getInstance(account).getConnectionState(); @@ -772,6 +816,13 @@ public void didReceivedNotification(int id, int account, Object... args) { } private class ListAdapter extends RecyclerListView.SelectionAdapter { + private final static int VIEW_TYPE_SHADOW = 0, + VIEW_TYPE_TEXT_SETTING = 1, + VIEW_TYPE_HEADER = 2, + VIEW_TYPE_TEXT_CHECK = 3, + VIEW_TYPE_INFO = 4, + VIEW_TYPE_PROXY_DETAIL = 5, + VIEW_TYPE_SLIDE_CHOOSER = 6; public static final int PAYLOAD_CHECKED_CHANGED = 0; public static final int PAYLOAD_SELECTION_CHANGED = 1; @@ -828,15 +879,15 @@ public int getItemCount() { @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { - case 0: { - if (position == proxyDetailRow && callsRow == -1) { + case VIEW_TYPE_SHADOW: { + if (position == proxyShadowRow && callsRow == -1) { holder.itemView.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); } else { holder.itemView.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); } break; } - case 1: { + case VIEW_TYPE_TEXT_SETTING: { TextSettingsCell textCell = (TextSettingsCell) holder.itemView; textCell.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); if (position == proxyAddRow) { @@ -847,31 +898,36 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } break; } - case 2: { + case VIEW_TYPE_HEADER: { HeaderCell headerCell = (HeaderCell) holder.itemView; if (position == connectionsHeaderRow) { headerCell.setText(LocaleController.getString("ProxyConnections", R.string.ProxyConnections)); } break; } - case 3: { + case VIEW_TYPE_TEXT_CHECK: { TextCheckCell checkCell = (TextCheckCell) holder.itemView; if (position == useProxyRow) { - checkCell.setTextAndCheck(LocaleController.getString("UseProxySettings", R.string.UseProxySettings), useProxySettings, false); + checkCell.setTextAndCheck(LocaleController.getString("UseProxySettings", R.string.UseProxySettings), useProxySettings, rotationRow != -1); } else if (position == callsRow) { checkCell.setTextAndCheck(LocaleController.getString("UseProxyForCalls", R.string.UseProxyForCalls), useProxyForCalls, false); + } else if (position == rotationRow) { + checkCell.setTextAndCheck(LocaleController.getString(R.string.UseProxyRotation), SharedConfig.proxyRotationEnabled, true); } break; } - case 4: { + case VIEW_TYPE_INFO: { TextInfoPrivacyCell cell = (TextInfoPrivacyCell) holder.itemView; if (position == callsDetailRow) { cell.setText(LocaleController.getString("UseProxyForCallsInfo", R.string.UseProxyForCallsInfo)); - cell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + cell.setBackground(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + } else if (position == rotationTimeoutInfoRow) { + cell.setText(LocaleController.getString(R.string.ProxyRotationTimeoutInfo)); + cell.setBackground(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); } break; } - case 5: { + case VIEW_TYPE_PROXY_DETAIL: { TextDetailProxyCell cell = (TextDetailProxyCell) holder.itemView; SharedConfig.ProxyInfo info = proxyList.get(position - proxyStartRow); cell.setProxy(info); @@ -880,13 +936,29 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { cell.setSelectionEnabled(!selectedItems.isEmpty(), false); break; } + case VIEW_TYPE_SLIDE_CHOOSER: { + if (position == rotationTimeoutRow) { + SlideChooseView chooseView = (SlideChooseView) holder.itemView; + ArrayList options = new ArrayList<>(ProxyRotationController.ROTATION_TIMEOUTS); + String[] values = new String[options.size()]; + for (int i = 0; i < options.size(); i++) { + values[i] = LocaleController.formatString(R.string.ProxyRotationTimeoutSeconds, options.get(i)); + } + chooseView.setCallback(i -> { + SharedConfig.proxyRotationTimeout = i; + SharedConfig.saveConfig(); + }); + chooseView.setOptions(SharedConfig.proxyRotationTimeout, values); + } + break; + } } } @SuppressWarnings("unchecked") @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @NonNull List payloads) { - if (holder.getItemViewType() == 5 && !payloads.isEmpty()) { + if (holder.getItemViewType() == VIEW_TYPE_PROXY_DETAIL && !payloads.isEmpty()) { TextDetailProxyCell cell = (TextDetailProxyCell) holder.itemView; if (payloads.contains(PAYLOAD_SELECTION_CHANGED)) { cell.setItemSelected(selectedItems.contains(proxyList.get(position - proxyStartRow)), true); @@ -894,12 +966,14 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi if (payloads.contains(PAYLOAD_SELECTION_MODE_CHANGED)) { cell.setSelectionEnabled(!selectedItems.isEmpty(), true); } - } else if (holder.getItemViewType() == 3 && payloads.contains(PAYLOAD_CHECKED_CHANGED)) { + } else if (holder.getItemViewType() == VIEW_TYPE_TEXT_CHECK && payloads.contains(PAYLOAD_CHECKED_CHANGED)) { TextCheckCell checkCell = (TextCheckCell) holder.itemView; if (position == useProxyRow) { checkCell.setChecked(useProxySettings); } else if (position == callsRow) { checkCell.setChecked(useProxyForCalls); + } else if (position == rotationRow) { + checkCell.setChecked(SharedConfig.proxyRotationEnabled); } } else { super.onBindViewHolder(holder, position, payloads); @@ -909,13 +983,15 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi @Override public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { int viewType = holder.getItemViewType(); - if (viewType == 3) { + if (viewType == VIEW_TYPE_TEXT_CHECK) { TextCheckCell checkCell = (TextCheckCell) holder.itemView; int position = holder.getAdapterPosition(); if (position == useProxyRow) { checkCell.setChecked(useProxySettings); } else if (position == callsRow) { checkCell.setChecked(useProxyForCalls); + } else if (position == rotationRow) { + checkCell.setChecked(SharedConfig.proxyRotationEnabled); } } } @@ -923,33 +999,37 @@ public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { int position = holder.getAdapterPosition(); - return position == useProxyRow || position == callsRow || position == proxyAddRow || position == deleteAllRow || position >= proxyStartRow && position < proxyEndRow; + return position == useProxyRow || position == rotationRow || position == callsRow || position == proxyAddRow || position == deleteAllRow || position >= proxyStartRow && position < proxyEndRow; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view; switch (viewType) { - case 0: + case VIEW_TYPE_SHADOW: view = new ShadowSectionCell(mContext); break; - case 1: + case VIEW_TYPE_TEXT_SETTING: view = new TextSettingsCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; - case 2: + case VIEW_TYPE_HEADER: view = new HeaderCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; - case 3: + case VIEW_TYPE_TEXT_CHECK: view = new TextCheckCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; - case 4: + case VIEW_TYPE_INFO: view = new TextInfoPrivacyCell(mContext); - view.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); + view.setBackground(Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow)); + break; + case VIEW_TYPE_SLIDE_CHOOSER: + view = new SlideChooseView(mContext); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); break; - case 5: + case VIEW_TYPE_PROXY_DETAIL: default: view = new TextDetailProxyCell(mContext); view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); @@ -962,9 +1042,9 @@ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType @Override public long getItemId(int position) { // Random stable ids, could be anything non-repeating - if (position == useProxyDetailRow) { + if (position == useProxyShadowRow) { return -1; - } else if (position == proxyDetailRow) { + } else if (position == proxyShadowRow) { return -2; } else if (position == proxyAddRow) { return -3; @@ -976,6 +1056,12 @@ public long getItemId(int position) { return -6; } else if (position == deleteAllRow) { return -8; + } else if (position == rotationRow) { + return -9; + } else if (position == rotationTimeoutRow) { + return -10; + } else if (position == rotationTimeoutInfoRow) { + return -11; } else if (position >= proxyStartRow && position < proxyEndRow) { return proxyList.get(position - proxyStartRow).hashCode(); } else { @@ -985,18 +1071,20 @@ public long getItemId(int position) { @Override public int getItemViewType(int position) { - if (position == useProxyDetailRow || position == proxyDetailRow) { - return 0; + if (position == useProxyShadowRow || position == proxyShadowRow) { + return VIEW_TYPE_SHADOW; } else if (position == proxyAddRow || position == deleteAllRow) { - return 1; - } else if (position == useProxyRow || position == callsRow) { - return 3; + return VIEW_TYPE_TEXT_SETTING; + } else if (position == useProxyRow || position == rotationRow || position == callsRow) { + return VIEW_TYPE_TEXT_CHECK; } else if (position == connectionsHeaderRow) { - return 2; + return VIEW_TYPE_HEADER; + } else if (position == rotationTimeoutRow) { + return VIEW_TYPE_SLIDE_CHOOSER; } else if (position >= proxyStartRow && position < proxyEndRow) { - return 5; + return VIEW_TYPE_PROXY_DETAIL; } else { - return 4; + return VIEW_TYPE_INFO; } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/RestrictedLanguagesSelectActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/RestrictedLanguagesSelectActivity.java index a7426642450..a9151e2c82b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/RestrictedLanguagesSelectActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/RestrictedLanguagesSelectActivity.java @@ -8,56 +8,60 @@ package org.telegram.ui; -import android.animation.ValueAnimator; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; +import android.content.res.Resources; +import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.InputMethodSubtype; import android.widget.EditText; import android.widget.FrameLayout; -import android.widget.LinearLayout; import android.widget.TextView; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.TranslateController; +import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.ActionBarMenuItem; 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.CheckBoxCell; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.LanguageCell; -import org.telegram.ui.ActionBar.ActionBar; -import org.telegram.ui.ActionBar.ActionBarMenu; -import org.telegram.ui.ActionBar.ActionBarMenuItem; -import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextCheckbox2Cell; -import org.telegram.ui.Cells.TextCheckCell; -import org.telegram.ui.Cells.TextInfoPrivacyCell; -import org.telegram.ui.Cells.TextRadioCell; -import org.telegram.ui.Cells.TextSettingsCell; -import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.EmptyTextProgressView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.TranslateAlert2; +import java.io.BufferedReader; +import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.HashSet; -import java.util.Set; +import java.util.List; import java.util.Timer; -import java.util.TimerTask; - -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; public class RestrictedLanguagesSelectActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { @@ -72,52 +76,22 @@ public class RestrictedLanguagesSelectActivity extends BaseFragment implements N private Timer searchTimer; private ArrayList searchResult; private ArrayList sortedLanguages; -// private ArrayList unofficialLanguages; private SharedPreferences preferences; - private SharedPreferences.OnSharedPreferenceChangeListener listener; - private HashSet selectedLanguages = null; + private HashSet firstSelectedLanguages; + private HashSet selectedLanguages; public static HashSet getRestrictedLanguages() { -// String currentLangCode = LocaleController.getInstance().getCurrentLocaleInfo().pluralLangCode; -// String[] onlyCurrentLang = new String[] { currentLangCode }; - return new HashSet<>(MessagesController.getGlobalMainSettings().getStringSet("translate_button_restricted_languages", new HashSet(/*Arrays.asList(onlyCurrentLang)*/))); + String currentLangCode = LocaleController.getInstance().getCurrentLocaleInfo().pluralLangCode; + String[] onlyCurrentLang = new String[] { currentLangCode }; + return new HashSet<>(MessagesController.getGlobalMainSettings().getStringSet("translate_button_restricted_languages", new HashSet(Arrays.asList(onlyCurrentLang)))); } @Override public boolean onFragmentCreate() { preferences = MessagesController.getGlobalMainSettings(); + firstSelectedLanguages = getRestrictedLanguages(); selectedLanguages = getRestrictedLanguages(); - preferences.registerOnSharedPreferenceChangeListener(listener = new SharedPreferences.OnSharedPreferenceChangeListener() { - public int langPos(String lng) { - if (lng == null) - return -1; - ArrayList arr = (searching ? searchResult : sortedLanguages); - if (arr == null) - return -1; - for (int i = 0; i < arr.size(); ++i) - if (lng.equals(arr.get(i).pluralLangCode)) - return i; - return -1; - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { - preferences = sharedPreferences; - HashSet newSelectedLanguages = getRestrictedLanguages(); - if (listView != null && listView.getAdapter() != null) { - RecyclerView.Adapter adapter = listView.getAdapter(); - int offset = !searching ? 1 : 0; - for (String lng : selectedLanguages) - if (!newSelectedLanguages.contains(lng)) - adapter.notifyItemChanged(langPos(lng) + offset); - for (String lng : newSelectedLanguages) - if (!selectedLanguages.contains(lng)) - adapter.notifyItemChanged(langPos(lng) + offset); - } - selectedLanguages = newSelectedLanguages; - } - }); fillLanguages(); LocaleController.getInstance().loadRemoteLanguages(currentAccount); @@ -125,13 +99,55 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin return super.onFragmentCreate(); } + private void rebind(int position) { + for (int i = 0; i < listView.getChildCount(); ++i) { + View child = listView.getChildAt(i); + RecyclerView.ViewHolder holder = listView.getChildViewHolder(child); + if (holder == null) { + continue; + } + int childPosition = holder.getAdapterPosition(); + if (childPosition == RecyclerView.NO_POSITION) { + continue; + } + if (childPosition == position) { + listAdapter.onBindViewHolder(holder, position); + return; + } + } + } + @Override public void onFragmentDestroy() { super.onFragmentDestroy(); - preferences.unregisterOnSharedPreferenceChangeListener(listener); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.suggestedLangpack); } + public static boolean toggleLanguage(String language, boolean doNotTranslate) { + if (language == null) { + return false; + } + LocaleController.LocaleInfo currentLocaleInfo = LocaleController.getInstance().getCurrentLocaleInfo(); + HashSet selectedLanguages = getRestrictedLanguages(); + if (language != null && language.equals(currentLocaleInfo.pluralLangCode) && doNotTranslate) { +// AndroidUtilities.shakeViewSpring(view); +// BotWebViewVibrationEffect.APP_ERROR.vibrate(); + return false; + } + if (!doNotTranslate) { + selectedLanguages.remove(language); + } else { + selectedLanguages.add(language); + } + if (selectedLanguages.size() == 1 && selectedLanguages.contains(currentLocaleInfo.pluralLangCode)) { + MessagesController.getGlobalMainSettings().edit().remove("translate_button_restricted_languages").commit(); + } else { + MessagesController.getGlobalMainSettings().edit().putStringSet("translate_button_restricted_languages", selectedLanguages).commit(); + } + TranslateController.invalidateSuggestedLanguageCodes(); + return true; + } + @Override public View createView(Context context) { searching = false; @@ -214,6 +230,7 @@ public void onTextChanged(EditText editText) { return; } boolean search = listView.getAdapter() == searchListViewAdapter; + final int realPosition = position; if (!search) position--; LocaleController.LocaleInfo localeInfo; @@ -225,20 +242,24 @@ public void onTextChanged(EditText editText) { if (localeInfo != null) { LocaleController.LocaleInfo currentLocaleInfo = LocaleController.getInstance().getCurrentLocaleInfo(); String langCode = localeInfo.pluralLangCode; - if (langCode != null && langCode.equals(currentLocaleInfo.pluralLangCode)) { - AndroidUtilities.shakeView(((TextCheckbox2Cell) view).checkbox); + boolean value = selectedLanguages.contains(langCode); + if (langCode != null && langCode.equals(currentLocaleInfo.pluralLangCode) && value) { + AndroidUtilities.shakeViewSpring(view); + BotWebViewVibrationEffect.APP_ERROR.vibrate(); return; } - boolean value = selectedLanguages.contains(langCode); - HashSet newSelectedLanguages = new HashSet(selectedLanguages); if (value) - newSelectedLanguages.removeIf(s -> s != null && s.equals(langCode)); - else - newSelectedLanguages.add(langCode); - if (newSelectedLanguages.size() == 1 && newSelectedLanguages.contains(currentLocaleInfo.pluralLangCode)) - preferences.edit().remove("translate_button_restricted_languages").apply(); + selectedLanguages.removeIf(s -> s != null && s.equals(langCode)); else - preferences.edit().putStringSet("translate_button_restricted_languages", newSelectedLanguages).apply(); + selectedLanguages.add(langCode); + if (selectedLanguages.size() == 1 && selectedLanguages.contains(currentLocaleInfo.pluralLangCode)) { + preferences.edit().remove("translate_button_restricted_languages").remove("translate_button_restricted_languages_changed").apply(); + } else { + preferences.edit().putStringSet("translate_button_restricted_languages", selectedLanguages).putBoolean("translate_button_restricted_languages_changed", true).apply(); + } + rebind(realPosition); + + MessagesController.getInstance(currentAccount).getTranslateController().checkRestrictedLanguagesUpdate(); } }); @@ -331,11 +352,17 @@ private void fillLanguages() { ArrayList arrayList = LocaleController.getInstance().languages; for (int a = 0, size = arrayList.size(); a < size; a++) { LocaleController.LocaleInfo info = arrayList.get(a); - if (info != null && info.serverIndex != Integer.MAX_VALUE/* && (info.pluralLangCode == null || !info.pluralLangCode.equals(currentLocale.pluralLangCode))*/) { + if (info != null && info.serverIndex != Integer.MAX_VALUE && !"en_raw".equals(info.shortName) && (info == currentLocale || !firstSelectedLanguages.contains(info.pluralLangCode))) { sortedLanguages.add(info); } } Collections.sort(sortedLanguages, comparator); + for (int a = 0, size = arrayList.size(); a < size; a++) { + LocaleController.LocaleInfo info = arrayList.get(a); + if (info != null && info.serverIndex != Integer.MAX_VALUE && !"en_raw".equals(info.shortName) && !(info == currentLocale || !firstSelectedLanguages.contains(info.pluralLangCode))) { + sortedLanguages.add(1, info); + } + } } @Override @@ -467,23 +494,21 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { case 0: { if (!search) position--; -// LanguageCell textSettingsCell = (LanguageCell) holder.itemView; TextCheckbox2Cell textSettingsCell = (TextCheckbox2Cell) holder.itemView; - LocaleController.LocaleInfo localeInfo; - boolean last; + LocaleController.LocaleInfo localeInfo = null; + boolean last = false; if (search) { - localeInfo = searchResult.get(position); + if (position >= 0 && position < searchResult.size()) { + localeInfo = searchResult.get(position); + } last = position == searchResult.size() - 1; - } /*else if (!unofficialLanguages.isEmpty() && position >= 0 && position < unofficialLanguages.size()) { - localeInfo = unofficialLanguages.get(position); - last = position == unofficialLanguages.size() - 1; - } */else { -// if (!unofficialLanguages.isEmpty()) { -// position -= unofficialLanguages.size() + 1; -// } + } else if (position >= 0 && position < sortedLanguages.size()) { localeInfo = sortedLanguages.get(position); last = position == sortedLanguages.size() - 1; } + if (localeInfo == null) { + return; + } String langCode = localeInfo.pluralLangCode; boolean value = selectedLanguages.contains(langCode); if (localeInfo.isLocal()) { @@ -491,9 +516,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { } else { textSettingsCell.setTextAndValue(localeInfo.name, localeInfo.nameEnglish, false, !last); } - - boolean isCurrent = langCode != null && langCode.equals(LocaleController.getInstance().getCurrentLocaleInfo().pluralLangCode); - textSettingsCell.setChecked(value || isCurrent); + textSettingsCell.setChecked(value); break; } case 1: { @@ -558,4 +581,207 @@ public ArrayList getThemeDescriptions() { return themeDescriptions; } + + public static void cleanup() { + MessagesController.getGlobalMainSettings().edit() + .remove("translate_button_restricted_languages_changed") + .remove("translate_button_restricted_languages_version") + .remove("translate_button_restricted_languages") + .apply(); + checkRestrictedLanguages(false); + } + + public static final int LAST_DO_NOT_TRANSLATE_VERSION = 2; + public static void checkRestrictedLanguages(boolean accountsChanged) { + boolean manualChanged = MessagesController.getGlobalMainSettings().getBoolean("translate_button_restricted_languages_changed", false); + int version = MessagesController.getGlobalMainSettings().getInt("translate_button_restricted_languages_version", 0); + + if (version != LAST_DO_NOT_TRANSLATE_VERSION || accountsChanged && !manualChanged) { + getExtendedDoNotTranslate(languages -> { + final String currentLangCode = LocaleController.getInstance().getCurrentLocaleInfo().pluralLangCode; + + languages.addAll(getRestrictedLanguages()); + SharedPreferences.Editor edit = MessagesController.getGlobalMainSettings().edit(); + if (languages.size() == 1 && TextUtils.equals(languages.iterator().next(), currentLangCode)) { + edit.remove("translate_button_restricted_languages"); + } else { + edit.putStringSet("translate_button_restricted_languages", languages); + } + edit.putInt("translate_button_restricted_languages_version", LAST_DO_NOT_TRANSLATE_VERSION).apply(); + + for (int i = 0; i < UserConfig.MAX_ACCOUNT_COUNT; ++i) { + final int account = i; + try { + MessagesController.getInstance(account).getTranslateController().checkRestrictedLanguagesUpdate(); + } catch (Exception ignore) {} + } + }); + } + } + + public static void getExtendedDoNotTranslate(Utilities.Callback> onDone) { + if (onDone == null) { + return; + } + + final HashSet result = new HashSet<>(); + + final HashMap countries = new HashMap<>(); +// final HashMap languages = new HashMap<>(); + final HashMap uniquePhoneCodes = new HashMap<>(); + +// final Utilities.Callback pushCountry = countryCode -> { +// if (countryCode == null) { +// return; +// } +// String[] countryLanguages = languages.get(countryCode.toUpperCase()); +// if (countryLanguages == null) { +// return; +// } +// for (int j = 1; j < Math.min(2, countryLanguages.length); ++j) { +// String language = countryLanguages[j]; +// if (language.contains("-")) { +// language = language.split("-")[0]; +// } +// if (TranslateAlert2.languageName(language) != null) { +// result.add(language); +// } +// } +// }; + + Utilities.doCallbacks( + next -> { + try { + String language = LocaleController.getInstance().getCurrentLocaleInfo().pluralLangCode; + if (TranslateAlert2.languageName(language) != null) { + result.add(language); + } + } catch (Exception e0) { + FileLog.e(e0); + } + next.run(); + }, + next -> { + try { + String language = Resources.getSystem().getConfiguration().locale.getLanguage(); + if (TranslateAlert2.languageName(language) != null) { + result.add(language); + } + } catch (Exception e1) { + FileLog.e(e1); + } + next.run(); + }, + next -> { + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(ApplicationLoader.applicationContext.getResources().getAssets().open("countries.txt"))); + ArrayList multipleCodes = new ArrayList<>(); + String line; + while ((line = reader.readLine()) != null) { + String[] args = line.split(";"); + if (args.length >= 3) { + countries.put(args[2], args[1]); + if (uniquePhoneCodes.containsKey(args[0]) && !"7".equals(args[0])) { + multipleCodes.add(args[0]); + uniquePhoneCodes.remove(args[0]); + } else if (!multipleCodes.contains(args[0])) { + uniquePhoneCodes.put(args[0], args[1]); + } + } + } + reader.close(); + +// reader = new BufferedReader(new InputStreamReader(ApplicationLoader.applicationContext.getResources().getAssets().open("languages.txt"))); +// while ((line = reader.readLine()) != null) { +// String[] args = line.split(","); +// if (args.length >= 2) { +// languages.put(args[0], args); +// } +// } +// reader.close(); + } catch (Exception e) { + FileLog.e(e); + } + next.run(); + }, +// next -> { +// ArrayList> getAuthorizationsCallbacks = new ArrayList<>(); +// for (int i = 0; i < UserConfig.MAX_ACCOUNT_COUNT; ++i) { +// final int account = i; +// if (UserConfig.getInstance(account).getClientUserId() != 0 && !ConnectionsManager.getInstance(account).isTestBackend()) { +// getAuthorizationsCallbacks.add(nextInternal -> { +// try { +// ConnectionsManager.getInstance(account).sendRequest(new TLRPC.TL_account_getAuthorizations(), (response, error) -> AndroidUtilities.runOnUIThread(() -> { +// if (error == null) { +// TLRPC.TL_account_authorizations res = (TLRPC.TL_account_authorizations) response; +// if (!res.authorizations.isEmpty()) { +// TLRPC.TL_authorization auth = res.authorizations.get(0); +// String[] separated = auth.country.split(", "); +// if (separated.length > 0) { +// pushCountry.run(countries.get(separated[separated.length - 1])); +// } +// } +// } +// nextInternal.run(); +// })); +// } catch (Exception e2) { +// FileLog.e(e2); +// nextInternal.run(); +// } +// }); +// } +// } +// getAuthorizationsCallbacks.add(n -> next.run()); +// Utilities.doCallbacks(getAuthorizationsCallbacks.toArray(new Utilities.Callback[0])); +// }, +// next -> { +// for (int i = 0; i < UserConfig.MAX_ACCOUNT_COUNT; ++i) { +// final int account = i; +// try { +// TLRPC.User user = UserConfig.getInstance(account).getCurrentUser(); +// if (user != null && user.phone != null) { +// for (int j = 4; j > 0; j--) { +// String code = user.phone.substring(0, j); +// String countryCode = uniquePhoneCodes.get(code); +// if (countryCode != null) { +// pushCountry.run(countryCode); +// break; +// } +// } +// } +// } catch (Exception e3) { +// FileLog.e(e3); +// } +// } +// next.run(); +// }, + next -> { + try { + InputMethodManager imm = (InputMethodManager) ApplicationLoader.applicationContext.getSystemService(Context.INPUT_METHOD_SERVICE); + List ims = imm.getEnabledInputMethodList(); + + for (InputMethodInfo method : ims) { + List submethods = imm.getEnabledInputMethodSubtypeList(method, true); + for (InputMethodSubtype submethod : submethods) { + if ("keyboard".equals(submethod.getMode())) { + String currentLocale = submethod.getLocale(); + if (currentLocale != null && currentLocale.contains("_")) { + currentLocale = currentLocale.split("_")[0]; + } + + if (TranslateAlert2.languageName(currentLocale) != null) { + result.add(currentLocale); + } + } + } + } + } catch (Exception e4) { + FileLog.e(e4); + } + + next.run(); + }, + next -> onDone.run(result) + ); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SaveToGallerySettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SaveToGallerySettingsActivity.java new file mode 100644 index 00000000000..a8cbe0efb1b --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/SaveToGallerySettingsActivity.java @@ -0,0 +1,663 @@ +package org.telegram.ui; + +import static org.telegram.messenger.SharedConfig.SAVE_TO_GALLERY_FLAG_CHANNELS; +import static org.telegram.messenger.SharedConfig.SAVE_TO_GALLERY_FLAG_GROUP; +import static org.telegram.messenger.SharedConfig.SAVE_TO_GALLERY_FLAG_PEER; + +import android.content.Context; +import android.graphics.Canvas; +import android.os.Bundle; +import android.util.LongSparseArray; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.graphics.ColorUtils; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ContactsController; +import org.telegram.messenger.DialogObject; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.SaveToGallerySettingsHelper; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.ActionBarMenuSubItem; +import org.telegram.ui.ActionBar.ActionBarPopupWindow; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BackDrawable; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.Cells.TextCell; +import org.telegram.ui.Cells.TextCheckCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.Cells.UserCell; +import org.telegram.ui.Cells.UserCell2; +import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.AnimatedFloat; +import org.telegram.ui.Components.AnimatedTextView; +import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.ListView.AdapterWithDiffUtils; +import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.SeekBarView; + +import java.util.ArrayList; +import java.util.Objects; + +public class SaveToGallerySettingsActivity extends BaseFragment { + + int type; + long dialogId; + SaveToGallerySettingsHelper.DialogException dialogException; + boolean isNewException; + + public SaveToGallerySettingsActivity(Bundle bundle) { + super(bundle); + } + + @Override + public boolean onFragmentCreate() { + type = getArguments().getInt("type"); + exceptionsDialogs = getUserConfig().getSaveGalleryExceptions(type); + dialogId = getArguments().getLong("dialog_id"); + if (dialogId != 0) { + dialogException = UserConfig.getInstance(currentAccount).getSaveGalleryExceptions(type).get(dialogId); + if (dialogException == null) { + isNewException = true; + dialogException = new SaveToGallerySettingsHelper.DialogException(); + SaveToGallerySettingsHelper.Settings globalSettings = SaveToGallerySettingsHelper.getSettings(type); + + dialogException.savePhoto = globalSettings.savePhoto; + dialogException.saveVideo = globalSettings.saveVideo; + dialogException.limitVideo = globalSettings.limitVideo; + + dialogException.dialogId = dialogId; + } + } + return super.onFragmentCreate(); + } + + private final int VIEW_TYPE_ADD_EXCEPTION = 1; + private final int VIEW_TYPE_CHAT = 2; + private final int VIEW_TYPE_DIVIDER = 3; + private final int VIEW_TYPE_DELETE_ALL = 4; + private final int VIEW_TYPE_HEADER = 5; + private final int VIEW_TYPE_TOGGLE = 6; + private final int VIEW_TYPE_DIVIDER_INFO = 7; + private final int VIEW_TYPE_CHOOSER = 8; + private static final int VIEW_TYPE_USER_INFO = 9; + private final int VIEW_TYPE_DIVIDER_LAST = 10; + + + int savePhotosRow; + int saveVideosRow; + int videoDividerRow; + + Adapter adapter; + + RecyclerListView recyclerListView; + + ArrayList items = new ArrayList<>(); + LongSparseArray exceptionsDialogs = new LongSparseArray<>(); + + @Override + public View createView(Context context) { + FrameLayout frameLayout = new FrameLayout(context); + fragmentView = frameLayout; + + actionBar.setBackButtonDrawable(new BackDrawable(false)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + return; + } + } + }); + if (dialogException != null) { + if (isNewException) { + actionBar.setTitle(LocaleController.getString(R.string.NotificationsNewException)); + } else { + actionBar.setTitle(LocaleController.getString(R.string.SaveToGalleryException)); + } + } else { + if (type == SAVE_TO_GALLERY_FLAG_PEER) { + actionBar.setTitle(LocaleController.getString(R.string.SaveToGalleryPrivate)); + } else if (type == SAVE_TO_GALLERY_FLAG_GROUP) { + actionBar.setTitle(LocaleController.getString(R.string.SaveToGalleryGroups)); + } else { + actionBar.setTitle(LocaleController.getString(R.string.SaveToGalleryChannels)); + } + } + + recyclerListView = new RecyclerListView(context); + DefaultItemAnimator defaultItemAnimator = new DefaultItemAnimator(); + defaultItemAnimator.setDurations(400); + defaultItemAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); + defaultItemAnimator.setDelayAnimations(false); + defaultItemAnimator.setSupportsChangeAnimations(false); + recyclerListView.setItemAnimator(defaultItemAnimator); + recyclerListView.setLayoutManager(new LinearLayoutManager(context)); + recyclerListView.setAdapter(adapter = new Adapter()); + recyclerListView.setOnItemClickListener((view, position, x, y) -> { + if (position == savePhotosRow) { + SaveToGallerySettingsHelper.Settings settings = getSettings(); + settings.savePhoto = !settings.savePhoto; + onSettingsUpdated(); + updateRows(); + } else if (position == saveVideosRow) { + SaveToGallerySettingsHelper.Settings settings = getSettings(); + settings.saveVideo = !settings.saveVideo; + onSettingsUpdated(); + updateRows(); + } else if (items.get(position).viewType == VIEW_TYPE_ADD_EXCEPTION) { + Bundle args = new Bundle(); + args.putBoolean("onlySelect", true); + args.putBoolean("checkCanWrite", false); + if (type == SAVE_TO_GALLERY_FLAG_GROUP) { + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_GROUPS_ONLY); + } else if (type == SAVE_TO_GALLERY_FLAG_CHANNELS) { + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_CHANNELS_ONLY); + } else { + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_USERS_ONLY); + } + args.putBoolean("allowGlobalSearch", false); + DialogsActivity activity = new DialogsActivity(args); + activity.setDelegate((fragment, dids, message, param) -> { + Bundle args2 = new Bundle(); + args2.putLong("dialog_id", dids.get(0).dialogId); + args2.putInt("type", type); + SaveToGallerySettingsActivity addExceptionActivity = new SaveToGallerySettingsActivity(args2); + presentFragment(addExceptionActivity, true); + return true; + }); + presentFragment(activity); + } else if (items.get(position).viewType == VIEW_TYPE_CHAT) { + Bundle args2 = new Bundle(); + args2.putLong("dialog_id", items.get(position).exception.dialogId); + args2.putInt("type", type); + SaveToGallerySettingsActivity addExceptionActivity = new SaveToGallerySettingsActivity(args2); + presentFragment(addExceptionActivity); + } else if (items.get(position).viewType == VIEW_TYPE_DELETE_ALL) { + AlertDialog alertDialog = AlertsCreator.createSimpleAlert(getContext(), + LocaleController.getString("NotificationsDeleteAllExceptionTitle", R.string.NotificationsDeleteAllExceptionTitle), + LocaleController.getString("NotificationsDeleteAllExceptionAlert", R.string.NotificationsDeleteAllExceptionAlert), + LocaleController.getString("Delete", R.string.Delete), + () -> { + exceptionsDialogs.clear(); + getUserConfig().updateSaveGalleryExceptions(type, exceptionsDialogs); + updateRows(); + }, null).create(); + alertDialog.show(); + alertDialog.redPositive(); + } + }); + recyclerListView.setOnItemLongClickListener((view, position, x, y) -> { + if (items.get(position).viewType == VIEW_TYPE_CHAT) { + + SaveToGallerySettingsHelper.DialogException exception = items.get(position).exception; + ActionBarPopupWindow.ActionBarPopupWindowLayout actionBarPopupWindowLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(getContext()); + ActionBarMenuSubItem edit = ActionBarMenuItem.addItem(actionBarPopupWindowLayout, R.drawable.msg_customize, LocaleController.getString("EditException", R.string.EditException), false, null); + ActionBarMenuSubItem delete = ActionBarMenuItem.addItem(actionBarPopupWindowLayout, R.drawable.msg_delete, LocaleController.getString("DeleteException", R.string.DeleteException), false, null); + delete.setColors(Theme.getColor(Theme.key_windowBackgroundWhiteRedText), Theme.getColor(Theme.key_windowBackgroundWhiteRedText)); + ActionBarPopupWindow popupWindow = AlertsCreator.createSimplePopup(SaveToGallerySettingsActivity.this, actionBarPopupWindowLayout, view, x, y); + actionBarPopupWindowLayout.setParentWindow(popupWindow); + + edit.setOnClickListener(v -> { + popupWindow.dismiss(); + Bundle args2 = new Bundle(); + args2.putLong("dialog_id", items.get(position).exception.dialogId); + args2.putInt("type", type); + SaveToGallerySettingsActivity addExceptionActivity = new SaveToGallerySettingsActivity(args2); + presentFragment(addExceptionActivity); + }); + delete.setOnClickListener(v -> { + popupWindow.dismiss(); + LongSparseArray allExceptions = getUserConfig().getSaveGalleryExceptions(type); + allExceptions.remove(exception.dialogId); + getUserConfig().updateSaveGalleryExceptions(type, allExceptions); + updateRows(); + }); + return true; + } + return false; + }); + frameLayout.addView(recyclerListView); + frameLayout.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + + if (dialogException != null) { + // ((ViewGroup.MarginLayoutParams)recyclerListView.getLayoutParams()).bottomMargin = AndroidUtilities.dp() + + FrameLayout button = new FrameLayout(getContext()); + button.setBackground(Theme.AdaptiveRipple.filledRect(Theme.key_featuredStickers_addButton, 8)); + + TextView textView = new TextView(getContext()); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setText(isNewException ? LocaleController.getString("AddException", R.string.AddException) : LocaleController.getString("SaveException", R.string.SaveException)); + textView.setGravity(Gravity.CENTER); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); + button.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + button.setOnClickListener(v -> { + if (isNewException) { + LongSparseArray allExceptions = getUserConfig().getSaveGalleryExceptions(type); + allExceptions.put(dialogException.dialogId, dialogException); + getUserConfig().updateSaveGalleryExceptions(type, allExceptions); + } + finishFragment(); + }); + frameLayout.addView(button, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM, 16, 16, 16, 16)); + + } + updateRows(); + return fragmentView; + } + + private void updateRows() { + boolean animated = !isPaused && adapter != null; + ArrayList oldItems = null; + if (animated) { + oldItems = new ArrayList(); + oldItems.addAll(items); + } + + items.clear(); + + if (dialogException != null) { + items.add(new Item(VIEW_TYPE_USER_INFO)); + items.add(new Item(VIEW_TYPE_DIVIDER)); + } + items.add(new Item(VIEW_TYPE_HEADER, LocaleController.getString("SaveToGallery", R.string.SaveToGallery))); + savePhotosRow = items.size(); + items.add(new Item(VIEW_TYPE_TOGGLE)); + saveVideosRow = items.size(); + items.add(new Item(VIEW_TYPE_TOGGLE)); + String text = null; + if (dialogException != null) { + text = LocaleController.getString("SaveToGalleryHintCurrent", R.string.SaveToGalleryHintCurrent); + } else if (type == SAVE_TO_GALLERY_FLAG_PEER) { + text = LocaleController.getString("SaveToGalleryHintUser", R.string.SaveToGalleryHintUser); + } else if (type == SAVE_TO_GALLERY_FLAG_CHANNELS) { + text = LocaleController.getString("SaveToGalleryHintChannels", R.string.SaveToGalleryHintChannels); + } else if (type == SAVE_TO_GALLERY_FLAG_GROUP) { + text = LocaleController.getString("SaveToGalleryHintGroup", R.string.SaveToGalleryHintGroup); + } + items.add(new Item(VIEW_TYPE_DIVIDER_INFO, text)); + + if (getSettings().saveVideo) { + items.add(new Item(VIEW_TYPE_HEADER, LocaleController.getString("MaxVideoSize", R.string.MaxVideoSize))); + items.add(new Item(VIEW_TYPE_CHOOSER)); + videoDividerRow = items.size(); + items.add(new Item(VIEW_TYPE_DIVIDER_INFO)); + } else { + videoDividerRow = -1; + } + + if (dialogException == null) { + exceptionsDialogs = getUserConfig().getSaveGalleryExceptions(type); + items.add(new Item(VIEW_TYPE_ADD_EXCEPTION)); + boolean added = false; + for (int i = 0; i < exceptionsDialogs.size(); i++) { + items.add(new Item(VIEW_TYPE_CHAT, exceptionsDialogs.valueAt(i))); + added = true; + } + + if (added) { + items.add(new Item(VIEW_TYPE_DIVIDER)); + items.add(new Item(VIEW_TYPE_DELETE_ALL)); + } + items.add(new Item(VIEW_TYPE_DIVIDER_LAST)); + } + + if (adapter != null) { + if (oldItems != null) { + adapter.setItems(oldItems, items); + } else { + adapter.notifyDataSetChanged(); + } + } + } + + private class Adapter extends AdapterWithDiffUtils { + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = null; + switch (viewType) { + case VIEW_TYPE_USER_INFO: + UserCell2 userCell2 = new UserCell2(getContext(), 4, 0, getResourceProvider()); + TLObject object; + if (DialogObject.isUserDialog(dialogId)) { + object = MessagesController.getInstance(currentAccount).getUser(dialogId); + } else { + object = MessagesController.getInstance(currentAccount).getChat(-dialogId); + } + userCell2.setData(object, null, null, 0); + view = userCell2; + view.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_CHAT: + view = new UserCell(parent.getContext(), 4, 0, false, false); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_ADD_EXCEPTION: + TextCell textCell = new TextCell(parent.getContext()); + textCell.setTextAndIcon(LocaleController.getString("NotificationsAddAnException", R.string.NotificationsAddAnException), R.drawable.msg_contact_add, true); + textCell.setColors(Theme.key_windowBackgroundWhiteBlueIcon, Theme.key_windowBackgroundWhiteBlueButton); + view = textCell; + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_DIVIDER_LAST: + view = new ShadowSectionCell(parent.getContext()); + view.setBackgroundDrawable(Theme.getThemedDrawable(getContext(), R.drawable.greydivider_bottom, Theme.getColor(Theme.key_windowBackgroundGrayShadow, getResourceProvider()))); + break; + case VIEW_TYPE_DIVIDER: + view = new ShadowSectionCell(parent.getContext()); + break; + case VIEW_TYPE_DELETE_ALL: + textCell = new TextCell(parent.getContext()); + textCell.setText(LocaleController.getString("NotificationsDeleteAllException", R.string.NotificationsDeleteAllException), false); + textCell.setColors(null, Theme.key_windowBackgroundWhiteRedText5); + view = textCell; + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_HEADER: + HeaderCell headerCell = new HeaderCell(parent.getContext()); + view = headerCell; + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_TOGGLE: + TextCheckCell textCheckCell = new TextCheckCell(parent.getContext()); + view = textCheckCell; + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case VIEW_TYPE_DIVIDER_INFO: + TextInfoPrivacyCell textInfoPrivacyCell = new TextInfoPrivacyCell(parent.getContext()); + view = textInfoPrivacyCell; + break; + case VIEW_TYPE_CHOOSER: + LinearLayout linearLayout = new LinearLayout(getContext()); + linearLayout.setOrientation(LinearLayout.VERTICAL); + SeekBarView slideChooseView = new SeekBarView(getContext()); + FrameLayout textContainer = new FrameLayout(getContext()); + + SelectableAnimatedTextView lowerTextView = new SelectableAnimatedTextView(getContext()); + lowerTextView.setTextSize(AndroidUtilities.dp(13)); + lowerTextView.setText(AndroidUtilities.formatFileSize(1024 * 512, true)); + textContainer.addView(lowerTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM)); + + SelectableAnimatedTextView midTextView = new SelectableAnimatedTextView(getContext()); + midTextView.setTextSize(AndroidUtilities.dp(13)); + // midTextView.setText(AndroidUtilities.formatFileSize(1024 * 512, true)); + textContainer.addView(midTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM)); + + SelectableAnimatedTextView topTextView = new SelectableAnimatedTextView(getContext()); + topTextView.setTextSize(AndroidUtilities.dp(13)); + topTextView.setText(AndroidUtilities.formatFileSize(SaveToGallerySettingsHelper.MAX_VIDEO_LIMIT, true)); + textContainer.addView(topTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.RIGHT | Gravity.BOTTOM)); + + + linearLayout.addView(textContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 20, 0, 21, 10, 21, 0)); + linearLayout.addView(slideChooseView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 38, 0, 5, 0, 5, 4)); + SaveToGallerySettingsHelper.Settings settings = getSettings(); + long currentValue = settings.limitVideo; + long maxValue = 4L * 1000 * 1024 * 1024; + if (currentValue < 0 || currentValue > SaveToGallerySettingsHelper.MAX_VIDEO_LIMIT) { + currentValue = SaveToGallerySettingsHelper.MAX_VIDEO_LIMIT; + } + slideChooseView.setReportChanges(true); + slideChooseView.setDelegate(new SeekBarView.SeekBarViewDelegate() { + @Override + public void onSeekBarDrag(boolean stop, float progress) { + boolean animated = slideChooseView.isAttachedToWindow(); + long limitExtremum = 100 * 1024 * 1024; + float limitExtremumF = 0.7f; + float limitExtremumK = 1f - limitExtremumF; + long value; + if (progress > limitExtremumF) { + float p = (progress - limitExtremumF) / limitExtremumK; + value = (long) (limitExtremum + (SaveToGallerySettingsHelper.MAX_VIDEO_LIMIT - limitExtremum) * p); + } else { + float p = progress / limitExtremumF; + value = (long) (1024 * 512 + (limitExtremum - 1024 * 512) * p); + } + if (progress >= 1f) { + lowerTextView.setSelectedInternal(false, animated); + midTextView.setSelectedInternal(false, animated); + topTextView.setSelectedInternal(true, animated); + AndroidUtilities.updateViewVisibilityAnimated(midTextView, false, 0.8f, animated); + } else if (progress == 0f) { + lowerTextView.setSelectedInternal(true, animated); + midTextView.setSelectedInternal(false, animated); + topTextView.setSelectedInternal(false, animated); + AndroidUtilities.updateViewVisibilityAnimated(midTextView, false, 0.8f, animated); + } else { + midTextView.setText( + LocaleController.formatString("UpToFileSize", R.string.UpToFileSize, + AndroidUtilities.formatFileSize(value, true) + ), false); + lowerTextView.setSelectedInternal(false, animated); + midTextView.setSelectedInternal(true, animated); + topTextView.setSelectedInternal(false, animated); + AndroidUtilities.updateViewVisibilityAnimated(midTextView, true, 0.8f, animated); + } + if (stop) { + getSettings().limitVideo = value; + onSettingsUpdated(); + } + + } + + @Override + public void onSeekBarPressed(boolean pressed) { + + } + }); + + long limitExtremum = 100 * 1024 * 1024; + float limitExtremumF = 0.7f; + float limitExtremumK = 1f - limitExtremumF; + long mimValue = 1024 * 512; + float currentProgress; + if (currentValue > limitExtremum * limitExtremumF) { + float p = (currentValue - limitExtremum) / (float) (maxValue - limitExtremum); + currentProgress = limitExtremumF + limitExtremumK * p; + } else { + float p = (currentValue - mimValue) / (float) (limitExtremum - mimValue); + currentProgress = limitExtremumF * p; + } + slideChooseView.setProgress(currentProgress); + slideChooseView.delegate.onSeekBarDrag(false, slideChooseView.getProgress()); + + view = linearLayout; + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + } + view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if (items.get(position).viewType == VIEW_TYPE_ADD_EXCEPTION) { + TextCell cell = (TextCell) holder.itemView; + cell.setNeedDivider(exceptionsDialogs.size() > 0); + } else if (items.get(position).viewType == VIEW_TYPE_TOGGLE) { + TextCheckCell cell = (TextCheckCell) holder.itemView; + SaveToGallerySettingsHelper.Settings settings = getSettings(); + if (position == savePhotosRow) { + cell.setTextAndCheck(LocaleController.getString(R.string.SaveToGalleryPhotos), settings.savePhoto, true); + cell.setColorfullIcon(getThemedColor(Theme.key_statisticChartLine_lightblue), R.drawable.msg_filled_data_photos); + } else { + cell.setTextAndCheck(LocaleController.getString(R.string.SaveToGalleryVideos), settings.saveVideo, false); + cell.setColorfullIcon(getThemedColor(Theme.key_statisticChartLine_green), R.drawable.msg_filled_data_videos); + } + + } else if (items.get(position).viewType == VIEW_TYPE_DIVIDER_INFO) { + TextInfoPrivacyCell cell = (TextInfoPrivacyCell) holder.itemView; + if (position == videoDividerRow) { + long limit = getSettings().limitVideo; + if (limit == -1) { + limit = 4L * 1000 * 1024 * 1024; + } + if (dialogException != null) { + cell.setText(LocaleController.formatString("SaveToGalleryVideoHintCurrent", R.string.SaveToGalleryVideoHintCurrent)); + } else if (type == SAVE_TO_GALLERY_FLAG_PEER) { + cell.setText(LocaleController.formatString("SaveToGalleryVideoHintUser", R.string.SaveToGalleryVideoHintUser)); + } else if (type == SAVE_TO_GALLERY_FLAG_CHANNELS) { + cell.setText(LocaleController.formatString("SaveToGalleryVideoHintChannels", R.string.SaveToGalleryVideoHintChannels)); + } else if (type == SAVE_TO_GALLERY_FLAG_GROUP) { + cell.setText(LocaleController.formatString("SaveToGalleryVideoHintGroup", R.string.SaveToGalleryVideoHintGroup)); + } + } else { + cell.setText(items.get(position).title); + } + } else if (items.get(position).viewType == VIEW_TYPE_HEADER) { + HeaderCell cell = (HeaderCell) holder.itemView; + cell.setText(items.get(position).title); + } else if (items.get(position).viewType == VIEW_TYPE_CHAT) { + UserCell cell = (UserCell) holder.itemView; + SaveToGallerySettingsHelper.DialogException exception = items.get(position).exception; + TLObject object = getMessagesController().getUserOrChat(exception.dialogId); + String title = null; + if (object instanceof TLRPC.User) { + TLRPC.User user = (TLRPC.User) object; + if (user.self) { + title = LocaleController.getString("SavedMessages", R.string.SavedMessages); + } else { + title = ContactsController.formatName(user.first_name, user.last_name); + } + } else if (object instanceof TLRPC.Chat) { + TLRPC.Chat chat = (TLRPC.Chat) object; + title = chat.title; + } + cell.setSelfAsSavedMessages(true); + cell.setData(object, title, exception.createDescription(currentAccount), 0, !(position != items.size() - 1 && items.get(position + 1).viewType != VIEW_TYPE_CHAT)); + } + } + + @Override + public int getItemCount() { + return items.size(); + } + + @Override + public int getItemViewType(int position) { + return items.get(position).viewType; + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return holder.getItemViewType() == VIEW_TYPE_ADD_EXCEPTION || holder.getItemViewType() == VIEW_TYPE_CHAT + || holder.getItemViewType() == VIEW_TYPE_DELETE_ALL || holder.getItemViewType() == VIEW_TYPE_TOGGLE; + } + } + + private class Item extends AdapterWithDiffUtils.Item { + final SaveToGallerySettingsHelper.DialogException exception; + String title; + + + private Item(int viewType) { + super(viewType, false); + exception = null; + } + + private Item(int viewType, SaveToGallerySettingsHelper.DialogException exception) { + super(viewType, false); + this.exception = exception; + } + + private Item(int viewType, String title) { + super(viewType, false); + this.title = title; + exception = null; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Item item = (Item) o; + if (viewType != item.viewType) { + return false; + } + if (title != null) { + return Objects.equals(title, item.title); + } + if (exception != null && item.exception != null) { + return exception.dialogId == item.exception.dialogId; + } + return true; + } + } + + SaveToGallerySettingsHelper.Settings getSettings() { + if (dialogException != null) { + return dialogException; + } + return SaveToGallerySettingsHelper.getSettings(type); + } + + @Override + public void onResume() { + super.onResume(); + updateRows(); + } + + private void onSettingsUpdated() { + if (isNewException) { + return; + } + if (dialogException != null) { + LongSparseArray allExceptions = getUserConfig().getSaveGalleryExceptions(type); + allExceptions.put(dialogException.dialogId, dialogException); + getUserConfig().updateSaveGalleryExceptions(type, allExceptions); + return; + } else { + SaveToGallerySettingsHelper.saveSettings(type); + } + } + + private class SelectableAnimatedTextView extends AnimatedTextView { + + boolean selected; + AnimatedFloat progressToSelect = new AnimatedFloat(this); + + public SelectableAnimatedTextView(Context context) { + super(context, true, true, false); + getDrawable().setAllowCancel(true); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + progressToSelect.set(selected ? 1f : 0); + setTextColor(ColorUtils.blendARGB(getThemedColor(Theme.key_windowBackgroundWhiteGrayText), getThemedColor(Theme.key_windowBackgroundWhiteBlueText), progressToSelect.get())); + super.dispatchDraw(canvas); + } + + public void setSelectedInternal(boolean selected, boolean animated) { + if (this.selected != selected) { + this.selected = selected; + progressToSelect.set(selected ? 1f : 0, animated); + invalidate(); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java b/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java index d0cb2350f1a..d9a9490d989 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java @@ -26,6 +26,7 @@ import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; +import android.util.Log; import android.util.LongSparseArray; import android.util.SparseArray; import android.util.SparseIntArray; @@ -50,6 +51,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; import androidx.core.graphics.ColorUtils; import androidx.core.math.MathUtils; import androidx.recyclerview.widget.DefaultItemAnimator; @@ -76,6 +78,7 @@ import org.telegram.messenger.SharedConfig; import org.telegram.messenger.SvgHelper; import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; @@ -103,11 +106,14 @@ import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; import org.telegram.ui.Components.Premium.PremiumLockIconView; import org.telegram.ui.Components.RLottieImageView; +import org.telegram.ui.Components.Reactions.CustomEmojiReactionsWindow; import org.telegram.ui.Components.Reactions.ReactionsEffectOverlay; import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; import org.telegram.ui.Components.Reactions.ReactionsUtils; import org.telegram.ui.Components.RecyclerAnimationScrollHelper; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.SearchStateDrawable; +import org.telegram.ui.Components.StickerCategoriesListView; import java.lang.reflect.Field; import java.util.ArrayList; @@ -115,6 +121,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Objects; @@ -124,6 +131,11 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati public final static int TYPE_REACTIONS = 1; public final static int TYPE_SET_DEFAULT_REACTION = 2; public static final int TYPE_TOPIC_ICON = 3; + public static final int TYPE_AVATAR_CONSTRUCTOR = 4; + + private final int SPAN_COUNT_FOR_EMOJI = 8; + private final int SPAN_COUNT_FOR_STICKER = 5; + private final int SPAN_COUNT = 40; private final int RECENT_MAX_LINES = 5; private final int EXPAND_MAX_LINES = 3; @@ -138,7 +150,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati private int longtapHintRow; private int defaultTopicIconRow; private int topicEmojiHeaderRow; - + private EmojiPackExpand recentExpandButton; public onLongPressedListener bigReactionListener; @@ -151,6 +163,9 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati private Drawable forumIconDrawable; private ImageViewEmoji forumIconImage; private boolean animationsEnabled; + private boolean showStickers; + private boolean forUser; + private ArrayList stickerSets = new ArrayList<>(); public void putAnimatedEmojiToCache(AnimatedEmojiDrawable animatedEmojiDrawable) { emojiGridView.animatedEmojiDrawables.put(animatedEmojiDrawable.getDocumentId(), animatedEmojiDrawable); @@ -167,6 +182,11 @@ public void setSelectedReactions(HashSet installedEmojiSets = new ArrayList<>(); private boolean recentExpanded = false; private ArrayList recent = new ArrayList<>(); + private ArrayList recentStickers = new ArrayList<>(); private ArrayList topReactions = new ArrayList<>(); private ArrayList recentReactions = new ArrayList<>(); private ArrayList defaultStatuses = new ArrayList<>(); @@ -363,6 +385,10 @@ public void dismiss() { private int topMarginDp; DefaultItemAnimator emojiItemAnimator; + protected void invalidateParent() { + + } + public SelectAnimatedEmojiDialog(BaseFragment baseFragment, Context context, boolean includeEmpty, Theme.ResourcesProvider resourcesProvider) { this(baseFragment, context, includeEmpty, null, TYPE_EMOJI_STATUS, resourcesProvider); } @@ -433,7 +459,7 @@ protected void dispatchDraw(Canvas canvas) { return; } canvas.save(); - paint.setShadowLayer(dp(2), 0, dp(-0.66f), 0x1e000000); + Theme.applyDefaultShadow(paint); paint.setColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground, resourcesProvider)); paint.setAlpha((int) (255 * getAlpha())); float px = (bubbleX == null ? getWidth() / 2f : bubbleX) + AndroidUtilities.dp(20); @@ -475,55 +501,84 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { addView(bubble2View, LayoutHelper.createFrame(17, 9, Gravity.TOP | Gravity.LEFT, bubbleX / AndroidUtilities.density + (bubbleRight ? -25 : 10), 6 + 8 - 9 + topMarginDp, 0, 0)); } - boolean showSettings = baseFragment != null && type != TYPE_TOPIC_ICON; - emojiTabs = new EmojiTabsStrip(context, null, false, true, type, showSettings ? () -> { - onSettings(); - baseFragment.presentFragment(new StickersActivity(MediaDataController.TYPE_EMOJIPACKS, frozenEmojiPacks)); - if (dismiss != null) { - dismiss.run(); - } - } : null) { + boolean showSettings = baseFragment != null && type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR; + for (int i = 0; i < 2; i++) { + EmojiTabsStrip emojiTabs = new EmojiTabsStrip(context, null, false, true, type, showSettings ? () -> { + search(null, false, false); + onSettings(); + baseFragment.presentFragment(new StickersActivity(MediaDataController.TYPE_EMOJIPACKS, frozenEmojiPacks)); + if (dismiss != null) { + dismiss.run(); + } + } : null) { - @Override - protected ColorFilter getEmojiColorFilter() { - return premiumStarColorFilter; - } + @Override + protected ColorFilter getEmojiColorFilter() { + return premiumStarColorFilter; + } - @Override - protected boolean onTabClick(int index) { - if (smoothScrolling) { - return false; + @Override + protected boolean onTabClick(int index) { + if (smoothScrolling) { + return false; + } + if (type == TYPE_AVATAR_CONSTRUCTOR) { + if (index == 0) { + showStickers = !showStickers; + SelectAnimatedEmojiDialog.this.emojiTabs.setVisibility(View.GONE); + SelectAnimatedEmojiDialog.this.emojiTabs = cachedEmojiTabs[showStickers ? 1 : 0]; + SelectAnimatedEmojiDialog.this.emojiTabs.setVisibility(View.VISIBLE); + SelectAnimatedEmojiDialog.this.emojiTabs.toggleEmojiStickersTab.setDrawable(ContextCompat.getDrawable(getContext(), showStickers ? R.drawable.msg_emoji_stickers : R.drawable.msg_emoji_smiles)); + updateRows(true, false, false); + layoutManager.scrollToPositionWithOffset(0, 0); + return true; + } + index--; + } + int position = 0; + if (index > 0 && sectionToPosition.indexOfKey(index - 1) >= 0) { + position = sectionToPosition.get(index - 1); + } + scrollToPosition(position, AndroidUtilities.dp(-2)); + SelectAnimatedEmojiDialog.this.emojiTabs.select(index); + emojiGridView.scrolledByUserOnce = true; + search(null); + if (searchBox != null && searchBox.categoriesListView != null) { + searchBox.categoriesListView.selectCategory(null); + } + return true; + } + + @Override + protected void onTabCreate(EmojiTabsStrip.EmojiTabButton button) { + if (showAnimator == null || showAnimator.isRunning()) { + button.setScaleX(0); + button.setScaleY(0); + } } - int position = searchRow == -1 ? 1 : 0; - if (index > 0 && sectionToPosition.indexOfKey(index - 1) >= 0) { - position = sectionToPosition.get(index - 1); + }; + emojiTabs.recentTab.setOnLongClickListener(e -> { + onRecentLongClick(); + try { + performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); + } catch (Exception ignore) { } - scrollToPosition(position, AndroidUtilities.dp(-2)); - emojiTabs.select(index); - emojiGridView.scrolledByUserOnce = true; return true; + }); + emojiTabs.updateButtonDrawables = false; + if (type == TYPE_AVATAR_CONSTRUCTOR) { + emojiTabs.setAnimatedEmojiCacheType(AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC); + } else { + emojiTabs.setAnimatedEmojiCacheType(type == TYPE_EMOJI_STATUS || type == TYPE_SET_DEFAULT_REACTION ? AnimatedEmojiDrawable.CACHE_TYPE_TAB_STRIP : AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP); } + emojiTabs.animateAppear = bubbleX == null; + emojiTabs.setPaddingLeft(5); + contentView.addView(emojiTabs, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36)); + cachedEmojiTabs[i] = emojiTabs; + } - @Override - protected void onTabCreate(EmojiTabsStrip.EmojiTabButton button) { - if (showAnimator == null || showAnimator.isRunning()) { - button.setScaleX(0); - button.setScaleY(0); - } - } - }; - emojiTabs.recentTab.setOnLongClickListener(e -> { - onRecentLongClick(); - try { - performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); - } catch (Exception ignore) {} - return true; - }); - emojiTabs.updateButtonDrawables = false; - emojiTabs.setAnimatedEmojiCacheType(type == TYPE_EMOJI_STATUS || type == TYPE_SET_DEFAULT_REACTION ? AnimatedEmojiDrawable.CACHE_TYPE_TAB_STRIP : AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_TAB_STRIP); - emojiTabs.animateAppear = bubbleX == null; - emojiTabs.setPaddingLeft(5); - contentView.addView(emojiTabs, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36)); + emojiTabs = cachedEmojiTabs[0]; + cachedEmojiTabs[1].setVisibility(View.GONE); emojiTabsShadow = new View(context) { @Override @@ -546,7 +601,8 @@ public void onScrolled(int dx, int dy) { updateTabsPosition(layoutManager.findFirstCompletelyVisibleItemPosition()); } updateSearchBox(); - AndroidUtilities.updateViewVisibilityAnimated(emojiTabsShadow, emojiGridView.computeVerticalScrollOffset() != 0, 1f, true); + AndroidUtilities.updateViewVisibilityAnimated(emojiTabsShadow, emojiGridView.computeVerticalScrollOffset() != 0 || type == TYPE_EMOJI_STATUS || type == TYPE_REACTIONS, 1f, true); + invalidateParent(); } @Override @@ -575,7 +631,7 @@ protected float animateByScale(View view) { emojiGridView.setItemAnimator(emojiItemAnimator); emojiGridView.setPadding(dp(5), dp(2), dp(5), dp(2 + 36)); emojiGridView.setAdapter(adapter = new Adapter()); - emojiGridView.setLayoutManager(layoutManager = new GridLayoutManager(context, 8) { + emojiGridView.setLayoutManager(layoutManager = new GridLayoutManager(context, SPAN_COUNT) { @Override public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { try { @@ -595,7 +651,11 @@ public void onEnd() { layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { - return (positionToSection.indexOfKey(position) >= 0 || positionToButton.indexOfKey(position) >= 0 || position == recentReactionsSectionRow || position == popularSectionRow || position == longtapHintRow || position == searchRow || position == topicEmojiHeaderRow) ? layoutManager.getSpanCount() : 1; + if (positionToSection.indexOfKey(position) >= 0 || positionToButton.indexOfKey(position) >= 0 || position == recentReactionsSectionRow || position == popularSectionRow || position == longtapHintRow || position == searchRow || position == topicEmojiHeaderRow) { + return layoutManager.getSpanCount(); + } else { + return showStickers ? 8 : 5; + } } }); @@ -619,7 +679,9 @@ public void onScrolled(int dx, int dy) { emojiSearchGridView.getItemAnimator().setMoveInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); } TextView emptyViewText = new TextView(context); - if (type == TYPE_EMOJI_STATUS) { + if (type == TYPE_AVATAR_CONSTRUCTOR) { + emptyViewText.setText(LocaleController.getString("NoEmojiOrStickersFound", R.string.NoEmojiOrStickersFound)); + } else if (type == TYPE_EMOJI_STATUS) { emptyViewText.setText(LocaleController.getString("NoEmojiFound", R.string.NoEmojiFound)); } else if (type == TYPE_REACTIONS || type == TYPE_SET_DEFAULT_REACTION) { emptyViewText.setText(LocaleController.getString("NoReactionsFound", R.string.NoReactionsFound)); @@ -636,9 +698,9 @@ public void onScrolled(int dx, int dy) { emojiSearchEmptyView.setVisibility(View.GONE); emojiSearchEmptyView.setAlpha(0); gridViewContainer.addView(emojiSearchEmptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 0, 0, 0)); - emojiSearchGridView.setPadding(dp(5), dp(52 + 2), dp(5), dp(2)); + emojiSearchGridView.setPadding(dp(5), dp(52 + 2), dp(5), dp(36 + 2)); emojiSearchGridView.setAdapter(searchAdapter = new SearchAdapter()); - emojiSearchGridView.setLayoutManager(searchLayoutManager = new GridLayoutManager(context, 8) { + emojiSearchGridView.setLayoutManager(searchLayoutManager = new GridLayoutManager(context, SPAN_COUNT) { @Override public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { try { @@ -655,13 +717,20 @@ public void onEnd() { } } }); -// searchLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { -// @Override -// public int getSpanSize(int position) { -// return position == 0 ? layoutManager.getSpanCount() : 1; -// } -// }); + searchLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { + @Override + public int getSpanSize(int position) { + int viewType = searchAdapter.getItemViewType(position); + if (viewType == SearchAdapter.VIEW_TYPE_HEADER) { + return layoutManager.getSpanCount(); + } + if (viewType == SearchAdapter.VIEW_TYPE_STICKER) { + return 8; + } + return 5; + } + }); emojiSearchGridView.setVisibility(View.GONE); gridViewContainer.addView(emojiSearchGridView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, 0, 0, 0)); contentView.addView(gridViewContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP, 0, 36 + (1 / AndroidUtilities.density), 0, 0)); @@ -706,6 +775,7 @@ public boolean onItemClick(View view, int position, float x, float y) { setBigReactionAnimatedEmoji(new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_LARGE, currentAccount, selectedReactionView.span.documentId)); } emojiGridView.invalidate(); + invalidateParent(); return true; } if (view instanceof ImageViewEmoji && ((ImageViewEmoji) view).span != null && type == TYPE_EMOJI_STATUS) { @@ -781,6 +851,8 @@ public void onAnimationEnd(Animator animation) { if (viewEmoji.isDefaultReaction) { incrementHintUse(); onReactionClick(viewEmoji, viewEmoji.reaction); + } else if (viewEmoji.isStaticIcon && viewEmoji.document != null) { + onStickerClick(viewEmoji, viewEmoji.document); } else { onEmojiClick(viewEmoji, viewEmoji.span); } @@ -812,9 +884,9 @@ public void onAnimationEnd(Animator animation) { emojiSearchGridView.setOnItemClickListener(onItemClick); searchBox = new SearchBox(context); - searchBox.setTranslationY(-AndroidUtilities.dp(4 + 52)); + searchBox.setTranslationY(-AndroidUtilities.dp( 52)); searchBox.setVisibility(View.INVISIBLE); - gridViewContainer.addView(searchBox, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 52, Gravity.TOP, 0, 0, 0, 0)); + gridViewContainer.addView(searchBox, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 52, Gravity.TOP, 0, -4, 0, 0)); topGradientView = new View(context) { @Override @@ -850,6 +922,10 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { updateRows(true, false); } + private void onStickerClick(ImageViewEmoji viewEmoji, TLRPC.Document document) { + onEmojiSelected(viewEmoji, null, document, null); + } + protected void onSettings() { } @@ -933,12 +1009,12 @@ private void setDim(float dim, boolean animated) { private void updateTabsPosition(int position) { if (position != RecyclerView.NO_POSITION) { - final int recentmaxlen = layoutManager.getSpanCount() * RECENT_MAX_LINES; + final int recentmaxlen = SPAN_COUNT_FOR_EMOJI * RECENT_MAX_LINES; int recentSize = recent.size() > recentmaxlen && !recentExpanded ? recentmaxlen : recent.size() + (includeEmpty ? 1 : 0); if (position <= recentSize || position <= recentReactions.size()) { emojiTabs.select(0); // recent } else { - final int maxlen = layoutManager.getSpanCount() * EXPAND_MAX_LINES; + final int maxlen = SPAN_COUNT_FOR_EMOJI * EXPAND_MAX_LINES; for (int i = 0; i < positionToSection.size(); ++i) { int startPosition = positionToSection.keyAt(i); int index = i - (defaultStatuses.isEmpty() ? 0 : 1); @@ -963,20 +1039,20 @@ private void updateSearchBox() { if (searched) { searchBox.clearAnimation(); searchBox.setVisibility(View.VISIBLE); - searchBox.animate().translationY(-AndroidUtilities.dp(4)).start(); + searchBox.animate().translationY(0).start(); } else { if (emojiGridView.getChildCount() > 0) { View first = emojiGridView.getChildAt(0); if (emojiGridView.getChildAdapterPosition(first) == searchRow && "searchbox".equals(first.getTag())) { searchBox.setVisibility(View.VISIBLE); - searchBox.setTranslationY(first.getY() - AndroidUtilities.dp(4)); + searchBox.setTranslationY(first.getY()); } else { // searchBox.setVisibility(View.INVISIBLE); - searchBox.setTranslationY(-AndroidUtilities.dp(4 + 52)); + searchBox.setTranslationY(-AndroidUtilities.dp(52)); } } else { // searchBox.setVisibility(View.INVISIBLE); - searchBox.setTranslationY(-AndroidUtilities.dp(4 + 52)); + searchBox.setTranslationY(-AndroidUtilities.dp(52)); } } } @@ -1134,7 +1210,7 @@ private void checkScroll() { private void scrollToPosition(int p, int offset) { View view = layoutManager.findViewByPosition(p); int firstPosition = layoutManager.findFirstVisibleItemPosition(); - if ((view == null && Math.abs(p - firstPosition) > layoutManager.getSpanCount() * 9f) || !SharedConfig.animationsEnabled()) { + if ((view == null && Math.abs(p - firstPosition) > SPAN_COUNT_FOR_EMOJI * 9f) || !SharedConfig.animationsEnabled()) { scrollHelper.setScrollDirection(layoutManager.findFirstVisibleItemPosition() < p ? RecyclerAnimationScrollHelper.SCROLL_DIRECTION_DOWN : RecyclerAnimationScrollHelper.SCROLL_DIRECTION_UP); scrollHelper.scrollToPosition(p, offset, false, true); } else { @@ -1158,12 +1234,18 @@ protected void onStart() { public boolean searching = false; public boolean searched = false; + public boolean searchedLiftUp = false; private String lastQuery; private ArrayList searchResult; + private ArrayList stickersSearchResult; private ValueAnimator gridSwitchAnimator; - private boolean gridSearch = false; public void switchGrids(boolean search) { + switchGrids(search, true); + } + + private boolean gridSearch = false; + public void switchGrids(boolean search, boolean liftUp) { if (gridSearch == search) { return; } @@ -1184,7 +1266,9 @@ public void switchGrids(boolean search) { t = 1f - t; } emojiGridView.setAlpha(1f - t); + emojiGridView.setTranslationY(AndroidUtilities.dp(8) * t); emojiSearchGridView.setAlpha(t); + emojiSearchGridView.setTranslationY(AndroidUtilities.dp(8) * (1f - t)); emojiSearchEmptyView.setAlpha(emojiSearchGridView.getAlpha() * t); }); gridSwitchAnimator.addListener(new AnimatorListenerAdapter() { @@ -1199,22 +1283,27 @@ public void onAnimationEnd(Animator animation) { } } }); - gridSwitchAnimator.setDuration(280); + gridSwitchAnimator.setDuration(320); gridSwitchAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT); gridSwitchAnimator.start(); ((View) emojiGridView.getParent()).animate() - .translationY(gridSearch ? -AndroidUtilities.dp(36) : 0) + .translationY(gridSearch && liftUp ? -AndroidUtilities.dp(36) : 0) .setInterpolator(CubicBezierInterpolator.DEFAULT) .setDuration(160) .start(); + if (gridSearch && liftUp) { + emojiSearchGridView.setPadding(dp(5), dp(52 + 2), dp(5), dp(2)); + } else { + emojiSearchGridView.setPadding(dp(5), dp(52 + 2), dp(5), dp(36 + 2)); + } checkScroll(); } private ArrayList emptyViewEmojis = new ArrayList(4); { - emptyViewEmojis.add("\uD83D\uDE16"); - emptyViewEmojis.add("\uD83D\uDE2B"); - emptyViewEmojis.add("\uD83E\uDEE0"); - emptyViewEmojis.add("\uD83D\uDE28"); + emptyViewEmojis.add("😖"); + emptyViewEmojis.add("😫"); + emptyViewEmojis.add("🫠"); + emptyViewEmojis.add("😨"); emptyViewEmojis.add("❓"); }; public void updateSearchEmptyViewImage() { @@ -1226,6 +1315,7 @@ public void updateSearchEmptyViewImage() { ArrayList featuredSets = MediaDataController.getInstance(currentAccount).getFeaturedEmojiSets(); List shuffledFeaturedSets = new ArrayList<>(featuredSets); Collections.shuffle(shuffledFeaturedSets); + int skip = (int) Math.round(Math.random() * 10); for (int i = 0; i < shuffledFeaturedSets.size(); ++i) { if (shuffledFeaturedSets.get(i) instanceof TLRPC.TL_stickerSetFullCovered && ((TLRPC.TL_stickerSetFullCovered) shuffledFeaturedSets.get(i)).documents != null) { List documents = new ArrayList<>(((TLRPC.TL_stickerSetFullCovered) shuffledFeaturedSets.get(i)).documents); @@ -1234,15 +1324,16 @@ public void updateSearchEmptyViewImage() { TLRPC.Document document = documents.get(j); if (document != null && emptyViewEmojis.contains(MessageObject.findAnimatedEmojiEmoticon(document, null))) { emoji = document; - break; + if (skip-- <= 0) + break; } } } - if (emoji != null) { + if (emoji != null && skip <= 0) { break; } } - if (emoji == null) { + if (emoji == null || skip > 0) { ArrayList sets = MediaDataController.getInstance(currentAccount).getStickerSets(MediaDataController.TYPE_EMOJIPACKS); List shuffledSets = new ArrayList<>(sets); Collections.shuffle(shuffledSets); @@ -1254,11 +1345,12 @@ public void updateSearchEmptyViewImage() { TLRPC.Document document = documents.get(j); if (document != null && emptyViewEmojis.contains(MessageObject.findAnimatedEmojiEmoticon(document, null))) { emoji = document; - break; + if (skip-- <= 0) + break; } } } - if (emoji != null) { + if (emoji != null && skip <= 0) { break; } } @@ -1328,7 +1420,12 @@ public void onAnimationEnd(Animator animation) { private static String[] lastSearchKeyboardLanguage; private Runnable clearSearchRunnable; private Runnable searchRunnable; + public void search(String query) { + search(query, true, true); + } + + public void search(String query, boolean liftUp, boolean delay) { if (clearSearchRunnable != null) { AndroidUtilities.cancelRunOnUIThread(clearSearchRunnable); clearSearchRunnable = null; @@ -1337,12 +1434,13 @@ public void search(String query) { AndroidUtilities.cancelRunOnUIThread(searchRunnable); searchRunnable = null; } - if (query == null) { + if (TextUtils.isEmpty(query)) { searching = false; searched = false; - switchGrids(false); - if (searchBox != null && searchBox.clearDrawable != null) { - searchBox.clearDrawable.stopAnimation(); + switchGrids(false, liftUp); + if (searchBox != null) { + searchBox.showProgress(false); + searchBox.toggleClear(false); } searchAdapter.updateRows(true); lastQuery = null; @@ -1350,8 +1448,9 @@ public void search(String query) { boolean firstSearch = !searching; searching = true; searched = false; - if (searchBox != null && searchBox.clearDrawable != null) { - searchBox.clearDrawable.startAnimation(); + searchedLiftUp = liftUp; + if (searchBox != null) { + searchBox.showProgress(true); } if (firstSearch) { if (searchResult != null) { @@ -1373,45 +1472,146 @@ public void search(String query) { } lastSearchKeyboardLanguage = newLanguage; AndroidUtilities.runOnUIThread(searchRunnable = () -> { - MediaDataController.getInstance(currentAccount).getAnimatedEmojiByKeywords(query, _documentIds -> { - final ArrayList documentIds = _documentIds == null ? new ArrayList<>() : _documentIds; - final HashMap availableReactions = MediaDataController.getInstance(currentAccount).getReactionsMap(); - if (Emoji.fullyConsistsOfEmojis(query)) { - ArrayList stickerSets = MediaDataController.getInstance(currentAccount).getStickerSets(MediaDataController.TYPE_EMOJIPACKS); - String emoticon; - - for (int i = 0; i < stickerSets.size(); ++i) { - if (stickerSets.get(i).documents != null) { - ArrayList documents = stickerSets.get(i).documents; - if (documents != null) { - for (int j = 0; j < documents.size(); ++j) { - emoticon = MessageObject.findAnimatedEmojiEmoticon(documents.get(j), null); - long id = documents.get(j).id; - if (emoticon != null && !documentIds.contains(id) && query.contains(emoticon.toLowerCase())) { - documentIds.add(id); + final LinkedHashSet documentIds = new LinkedHashSet<>(); + final HashMap availableReactions = MediaDataController.getInstance(currentAccount).getReactionsMap(); + final ArrayList reactions = new ArrayList<>(); + final boolean queryFullyConsistsOfEmojis = Emoji.fullyConsistsOfEmojis(query); + final ArrayList> emojiArrays = new ArrayList<>(); + final HashMap, String> emojiStickers = new HashMap<>(); + Utilities.doCallbacks( + next -> { + if (queryFullyConsistsOfEmojis) { + StickerCategoriesListView.search.fetch(UserConfig.selectedAccount, query, list -> { + if (list != null) { + documentIds.addAll(list.document_id); + } + next.run(); + }); + } else { + next.run(); + } + }, + next -> { + MediaDataController.getInstance(currentAccount).getAnimatedEmojiByKeywords(query, _documentIds -> { + if (_documentIds != null) { + documentIds.addAll(_documentIds); + } + next.run(); + }); + }, + next -> { + if (queryFullyConsistsOfEmojis) { + ArrayList stickerSets = MediaDataController.getInstance(currentAccount).getStickerSets(MediaDataController.TYPE_EMOJIPACKS); + String emoticon; + + for (int i = 0; i < stickerSets.size(); ++i) { + if (stickerSets.get(i).documents != null) { + ArrayList documents = stickerSets.get(i).documents; + if (documents != null) { + for (int j = 0; j < documents.size(); ++j) { + emoticon = MessageObject.findAnimatedEmojiEmoticon(documents.get(j), null); + long id = documents.get(j).id; + if (emoticon != null && !documentIds.contains(id) && query.contains(emoticon.toLowerCase())) { + documentIds.add(id); + } + } } } } - } - } - ArrayList featuredStickerSets = MediaDataController.getInstance(currentAccount).getFeaturedEmojiSets(); - for (int i = 0; i < featuredStickerSets.size(); ++i) { - if (featuredStickerSets.get(i) instanceof TLRPC.TL_stickerSetFullCovered && - ((TLRPC.TL_stickerSetFullCovered) featuredStickerSets.get(i)).keywords != null) { - ArrayList documents = ((TLRPC.TL_stickerSetFullCovered) featuredStickerSets.get(i)).documents; - if (documents != null) { - for (int j = 0; j < documents.size(); ++j) { - emoticon = MessageObject.findAnimatedEmojiEmoticon(documents.get(j), null); - long id = documents.get(j).id; - if (emoticon != null && !documentIds.contains(id) && query.contains(emoticon)) { - documentIds.add(id); + ArrayList featuredStickerSets = MediaDataController.getInstance(currentAccount).getFeaturedEmojiSets(); + for (int i = 0; i < featuredStickerSets.size(); ++i) { + if (featuredStickerSets.get(i) instanceof TLRPC.TL_stickerSetFullCovered && + ((TLRPC.TL_stickerSetFullCovered) featuredStickerSets.get(i)).keywords != null) { + ArrayList documents = ((TLRPC.TL_stickerSetFullCovered) featuredStickerSets.get(i)).documents; + if (documents != null) { + for (int j = 0; j < documents.size(); ++j) { + emoticon = MessageObject.findAnimatedEmojiEmoticon(documents.get(j), null); + long id = documents.get(j).id; + if (emoticon != null && !documentIds.contains(id) && query.contains(emoticon)) { + documentIds.add(id); + } + } } } } + + next.run(); + } else { + MediaDataController.getInstance(currentAccount).getEmojiSuggestions( + lastSearchKeyboardLanguage, query, false, + (result, alias) -> { + try { + for (int i = 0; i < result.size(); ++i) { + if (result.get(i).emoji.startsWith("animated_")) { + documentIds.add(Long.parseLong(result.get(i).emoji.substring(9))); + } else { + if (type == TYPE_REACTIONS || type == TYPE_SET_DEFAULT_REACTION) { + TLRPC.TL_availableReaction reaction = availableReactions.get(result.get(i).emoji); + if (reaction != null) { + reactions.add(ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(reaction)); + } + } + } + } + } catch (Exception ignore) { + } + next.run(); + }, + null, true, type == TYPE_TOPIC_ICON, false, 30 + ); + } + }, + next -> { + if (type != TYPE_AVATAR_CONSTRUCTOR) { + next.run(); + return; + } + final ArrayList emojiStickersArray = new ArrayList<>(0); + final LongSparseArray emojiStickersMap = new LongSparseArray<>(0); + HashMap> allStickers = MediaDataController.getInstance(currentAccount).getAllStickers(); + if (query.length() <= 14) { + CharSequence emoji = query; + int length = emoji.length(); + for (int a = 0; a < length; a++) { + if (a < length - 1 && (emoji.charAt(a) == 0xD83C && emoji.charAt(a + 1) >= 0xDFFB && emoji.charAt(a + 1) <= 0xDFFF || emoji.charAt(a) == 0x200D && (emoji.charAt(a + 1) == 0x2640 || emoji.charAt(a + 1) == 0x2642))) { + emoji = TextUtils.concat(emoji.subSequence(0, a), emoji.subSequence(a + 2, emoji.length())); + length -= 2; + a--; + } else if (emoji.charAt(a) == 0xfe0f) { + emoji = TextUtils.concat(emoji.subSequence(0, a), emoji.subSequence(a + 1, emoji.length())); + length--; + a--; + } + } + ArrayList newStickers = allStickers != null ? allStickers.get(emoji.toString()) : null; + if (newStickers != null && !newStickers.isEmpty()) { + emojiStickersArray.addAll(newStickers); + for (int a = 0, size = newStickers.size(); a < size; a++) { + TLRPC.Document document = newStickers.get(a); + emojiStickersMap.put(document.id, document); + } + emojiArrays.add(emojiStickersArray); + } } - } - AndroidUtilities.runOnUIThread(() -> { + if (allStickers != null && !allStickers.isEmpty() && query.length() > 1) { + MediaDataController.getInstance(currentAccount).getEmojiSuggestions(lastSearchKeyboardLanguage, query, false, (param, alias) -> { + boolean added = false; + for (int a = 0, size = param.size(); a < size; a++) { + String emoji = param.get(a).emoji; + ArrayList newStickers = allStickers != null ? allStickers.get(emoji) : null; + if (newStickers != null && !newStickers.isEmpty()) { + if (!emojiStickers.containsKey(newStickers)) { + emojiStickers.put(newStickers, emoji); + emojiArrays.add(newStickers); + } + } + } + next.run(); + }, false); + } + }, + next -> AndroidUtilities.runOnUIThread(() -> { if (clearSearchRunnable != null) { AndroidUtilities.cancelRunOnUIThread(clearSearchRunnable); clearSearchRunnable = null; @@ -1421,101 +1621,61 @@ public void search(String query) { return; } searched = true; - switchGrids(true); - if (searchBox != null && searchBox.clearDrawable != null) { - searchBox.clearDrawable.stopAnimation(); + switchGrids(true, liftUp); + if (searchBox != null) { + searchBox.showProgress(false); } if (searchResult == null) { searchResult = new ArrayList<>(); } else { searchResult.clear(); } + if (stickersSearchResult == null) { + stickersSearchResult = new ArrayList<>(); + } else { + stickersSearchResult.clear(); + } emojiSearchGridView.scrollToPosition(0); - searched = true; if (type == TYPE_REACTIONS || type == TYPE_SET_DEFAULT_REACTION) { - TLRPC.TL_availableReaction reaction = availableReactions.get(query); - if (reaction != null) { - searchResult.add(ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(reaction)); + if (!reactions.isEmpty()) { + searchResult.addAll(reactions); + } else { + TLRPC.TL_availableReaction reaction = availableReactions.get(query); + if (reaction != null) { + searchResult.add(ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(reaction)); + } } } - for (int i = 0; i < documentIds.size(); ++i) { - searchResult.add(ReactionsLayoutInBubble.VisibleReaction.fromCustomEmoji(documentIds.get(i))); + for (long documentId : documentIds) { + searchResult.add(ReactionsLayoutInBubble.VisibleReaction.fromCustomEmoji(documentId)); + } + for (ArrayList array : emojiArrays) { + stickersSearchResult.addAll(array); } searchAdapter.updateRows(!firstSearch); - }); - } else { - MediaDataController.getInstance(currentAccount).getEmojiSuggestions( - lastSearchKeyboardLanguage, - query, - false, - (result, alias) -> { - if (clearSearchRunnable != null) { - AndroidUtilities.cancelRunOnUIThread(clearSearchRunnable); - clearSearchRunnable = null; - } - if (query != lastQuery) { - return; - } - searched = true; - switchGrids(true); - if (searchBox != null && searchBox.clearDrawable != null) { - searchBox.clearDrawable.stopAnimation(); - } - if (searchResult == null) { - searchResult = new ArrayList<>(); - } else { - searchResult.clear(); - } - for (int i = 0; i < result.size(); ++i) { - try { - if (result.get(i).emoji.startsWith("animated_")) { - documentIds.add(Long.parseLong(result.get(i).emoji.substring(9))); - } else { - if (type == TYPE_REACTIONS || type == TYPE_SET_DEFAULT_REACTION) { - TLRPC.TL_availableReaction reaction = availableReactions.get(result.get(i).emoji); - if (reaction != null) { - searchResult.add(ReactionsLayoutInBubble.VisibleReaction.fromEmojicon(reaction)); - } - } - } - } catch (Exception ignore) {} - } - emojiSearchGridView.scrollToPosition(0); - searched = true; - for (int i = 0; i < documentIds.size(); ++i) { - searchResult.add(ReactionsLayoutInBubble.VisibleReaction.fromCustomEmoji(documentIds.get(i))); - } - searchAdapter.updateRows(!firstSearch); - }, - null, - true, - type == TYPE_TOPIC_ICON, - 30 - ); - } - }); - }, 425); - } - updateSearchBox(); - - if (searchBox != null && searchBox.clear != null) { - boolean showed = searchBox.clear.getAlpha() != 0; - if (searching != showed) { - searchBox.clear.animate() - .alpha(searching ? 1.0f : 0.0f) - .setDuration(150) - .scaleX(searching ? 1.0f : 0.1f) - .scaleY(searching ? 1.0f : 0.1f) - .start(); + }) + ); + }, delay ? 425 : 0); + if (searchBox != null) { + searchBox.showProgress(true); + searchBox.toggleClear(liftUp); } } + updateSearchBox(); } private class SearchAdapter extends RecyclerListView.SelectionAdapter { - public int VIEW_TYPE_SEARCH = 7; - public int VIEW_TYPE_EMOJI = 3; - public int VIEW_TYPE_REACTION = 4; + public final static int VIEW_TYPE_SEARCH = 7; + public final static int VIEW_TYPE_EMOJI = 3; + public final static int VIEW_TYPE_REACTION = 4; + public final static int VIEW_TYPE_STICKER = 5; + public final static int VIEW_TYPE_HEADER = 6; + + int stickersStartRow; + int emojiStartRow; + int emojiHeaderRow = -1; + int stickersHeaderRow = -1; @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { @@ -1526,7 +1686,9 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view; - if (viewType == VIEW_TYPE_SEARCH) { + if (viewType == VIEW_TYPE_HEADER) { + view = new HeaderView(getContext()); + } else if (viewType == VIEW_TYPE_SEARCH) { view = new View(getContext()) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @@ -1546,16 +1708,50 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @Override public int getItemViewType(int position) { - if (searchResult == null || position < 0 || position >= searchResult.size() || searchResult.get(position).emojicon == null) { + if (position == emojiHeaderRow || position == stickersHeaderRow) { + return VIEW_TYPE_HEADER; + } + if (position > stickersStartRow && position - stickersStartRow - 1 < stickersSearchResult.size()) { + return VIEW_TYPE_STICKER; + } + if (searchResult == null) { return VIEW_TYPE_EMOJI; - } else { - return VIEW_TYPE_REACTION; } + if (position > emojiStartRow && position - emojiStartRow - 1 < searchResult.size()) { + if (searchResult.get(position - emojiStartRow - 1 ).documentId != 0) { + return VIEW_TYPE_EMOJI; + } + } + return VIEW_TYPE_REACTION; } @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { - if (holder.getItemViewType() == VIEW_TYPE_REACTION) { + if (holder.getItemViewType() == VIEW_TYPE_HEADER) { + HeaderView header = (HeaderView) holder.itemView; + if (position == emojiHeaderRow) { + header.setText(LocaleController.getString("Emoji", R.string.Emoji), false); + } else { + header.setText(LocaleController.getString("AccDescrStickers", R.string.AccDescrStickers), false); + } + header.closeIcon.setVisibility(View.GONE); + } else if (holder.getItemViewType() == VIEW_TYPE_STICKER) { + int p = position - stickersStartRow - 1; + TLRPC.Document document = stickersSearchResult.get(p); + ImageViewEmoji imageView = (ImageViewEmoji) holder.itemView; + if (imageView.imageReceiver == null) { + imageView.imageReceiver = new ImageReceiver(imageView); + imageView.imageReceiver.setLayerNum(7); + imageView.imageReceiver.onAttachedToWindow(); + imageView.imageReceiver.setAspectFit(true); + } + imageView.imageReceiver.setParentView(emojiSearchGridView); + SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(document, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f); + imageView.imageReceiver.setImage(ImageLocation.getForDocument(document), "100_100_firstframe", null, null, svgThumb, 0, "tgs", document, 0); + imageView.isStaticIcon = true; + imageView.document = document; + imageView.span = null; + } else if (holder.getItemViewType() == VIEW_TYPE_REACTION) { ImageViewEmoji imageView = (ImageViewEmoji) holder.itemView; imageView.position = position; if (searchResult == null || position < 0 || position >= searchResult.size()) { @@ -1581,7 +1777,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi if (SharedConfig.getLiteMode().enabled()) { imageView.imageReceiver.setImage(ImageLocation.getForDocument(reaction.select_animation), "60_60_firstframe", null, null, svgThumb, 0, "tgs", currentReaction, 0); } else { - imageView.imageReceiver.setImage(ImageLocation.getForDocument(reaction.select_animation), ReactionsUtils.SELECT_ANIMATION_FILTER, null, null, svgThumb, 0, "tgs", currentReaction, 0); + imageView.imageReceiver.setImage(ImageLocation.getForDocument(reaction.select_animation), ReactionsUtils.SELECT_ANIMATION_FILTER, ImageLocation.getForDocument(reaction.select_animation), "30_30_firstframe", null, null, svgThumb, 0, "tgs", currentReaction, 0); } MediaDataController.getInstance(currentAccount).preloadImage(imageView.preloadEffectImageReceiver, ImageLocation.getForDocument(reaction.around_animation), ReactionsEffectOverlay.getFilterForAroundAnimation()); } else { @@ -1652,7 +1848,7 @@ public int getItemCount() { } public void updateRows(boolean diff) { - if (!isAttached) { + if (!isAttached || type == TYPE_AVATAR_CONSTRUCTOR) { diff = false; } ArrayList prevRowHashCodes = new ArrayList<>(rowHashCodes); @@ -1660,16 +1856,32 @@ public void updateRows(boolean diff) { count = 0; rowHashCodes.clear(); -// count++; -// rowHashCodes.add(132); - if (searchResult != null) { + if (type == TYPE_AVATAR_CONSTRUCTOR && !searchResult.isEmpty()) { + emojiHeaderRow = count++; + rowHashCodes.add(1); + } + + emojiStartRow = count; for (int i = 0; i < searchResult.size(); ++i) { count++; rowHashCodes.add(Objects.hash(-4342, searchResult.get(i))); } } + if (stickersSearchResult != null) { + if (type == TYPE_AVATAR_CONSTRUCTOR && !stickersSearchResult.isEmpty()) { + stickersHeaderRow = count++; + rowHashCodes.add(2); + } + + stickersStartRow = count; + for (int i = 0; i < stickersSearchResult.size(); ++i) { + count++; + rowHashCodes.add(Objects.hash(-7453, stickersSearchResult.get(i))); + } + } + if (diff) { DiffUtil.calculateDiff(new DiffUtil.Callback() { @Override @@ -1711,6 +1923,7 @@ private class Adapter extends RecyclerListView.SelectionAdapter { public int VIEW_TYPE_HINT = 6; public int VIEW_TYPE_SEARCH = 7; public int VIEW_TYPE_TOPIC_ICON = 8; + public int VIEW_TYPE_STICKER = 9; @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { @@ -1793,7 +2006,11 @@ public int getItemViewType(int position) { } if (position == defaultTopicIconRow) { return VIEW_TYPE_TOPIC_ICON; } else { - return VIEW_TYPE_EMOJI; + if (showStickers) { + return VIEW_TYPE_EMOJI; + } else { + return VIEW_TYPE_EMOJI; + } } } @@ -1824,10 +2041,14 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi } if (position == recentReactionsSectionRow) { header.setText(LocaleController.getString("RecentlyUsed", R.string.RecentlyUsed), false); - header.closeIcon.setVisibility(View.VISIBLE); - header.closeIcon.setOnClickListener((view) -> { - clearRecent(); - }); + if (type == TYPE_AVATAR_CONSTRUCTOR) { + header.closeIcon.setVisibility(View.GONE); + } else { + header.closeIcon.setVisibility(View.VISIBLE); + header.closeIcon.setOnClickListener((view) -> { + clearRecent(); + }); + } return; } header.closeIcon.setVisibility(View.GONE); @@ -1839,7 +2060,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi int index = positionToSection.get(position); if (index >= 0) { EmojiView.EmojiPack pack = packs.get(index); - header.setText(pack.set.title, !pack.free && !UserConfig.getInstance(currentAccount).isPremium()); + header.setText(pack.set.title, !pack.free && !UserConfig.getInstance(currentAccount).isPremium() && type != TYPE_AVATAR_CONSTRUCTOR); } else { header.setText(null, false); } @@ -1871,7 +2092,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi if (SharedConfig.getLiteMode().enabled()) { imageView.imageReceiver.setImage(ImageLocation.getForDocument(reaction.select_animation), "60_60_firstframe", null, null, svgThumb, 0, "tgs", currentReaction, 0); } else { - imageView.imageReceiver.setImage(ImageLocation.getForDocument(reaction.select_animation), ReactionsUtils.SELECT_ANIMATION_FILTER, null, null, svgThumb, 0, "tgs", currentReaction, 0); + imageView.imageReceiver.setImage(ImageLocation.getForDocument(reaction.select_animation), ReactionsUtils.SELECT_ANIMATION_FILTER, ImageLocation.getForDocument(reaction.select_animation), "30_30_firstframe", null, null, svgThumb, 0, "tgs", currentReaction, 0); } MediaDataController.getInstance(currentAccount).preloadImage(imageView.preloadEffectImageReceiver, ImageLocation.getForDocument(reaction.around_animation), ReactionsEffectOverlay.getFilterForAroundAnimation()); } else { @@ -1913,13 +2134,13 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi EmojiView.EmojiPack pack = i >= 0 && i < packs.size() ? packs.get(i) : null; if (i == -1) { recentExpandButton = button; - final int maxlen = layoutManager.getSpanCount() * RECENT_MAX_LINES; + final int maxlen = SPAN_COUNT_FOR_EMOJI * RECENT_MAX_LINES; button.textView.setText("+" + (recent.size() - maxlen + (includeEmpty ? 1 : 0) + 1)); } else if (pack != null) { if (recentExpandButton == button) { recentExpandButton = null; } - final int maxlen = layoutManager.getSpanCount() * EXPAND_MAX_LINES; + final int maxlen = SPAN_COUNT_FOR_EMOJI * EXPAND_MAX_LINES; button.textView.setText("+" + (pack.documents.size() - maxlen + 1)); } else { if (recentExpandButton == button) { @@ -1962,36 +2183,75 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi } } else if (viewType == VIEW_TYPE_SEARCH) { + } else if (viewType == VIEW_TYPE_STICKER) { + final int maxlen = SPAN_COUNT_FOR_EMOJI * EXPAND_MAX_LINES; + for (int i = 0; i < positionToSection.size(); ++i) { + int startPosition = positionToSection.keyAt(i); + int index = i - (defaultStatuses.isEmpty() ? 0 : 1); + EmojiView.EmojiPack pack = index >= 0 ? packs.get(index) : null; + if (pack == null) { + continue; + } + int count = pack.expanded ? pack.documents.size() : Math.min(pack.documents.size(), maxlen); + if (position > startPosition && position <= startPosition + 1 + count) { + TLRPC.Document document = pack.documents.get(position - startPosition - 1); + if (document != null) { +// imageView.span = new AnimatedEmojiSpan(document, null); +// imageView.document = document; + } + } + } } else { ImageViewEmoji imageView = (ImageViewEmoji) holder.itemView; imageView.empty = false; imageView.position = position; imageView.setPadding(AndroidUtilities.dp(1), AndroidUtilities.dp(1), AndroidUtilities.dp(1), AndroidUtilities.dp(1)); - final int recentmaxlen = layoutManager.getSpanCount() * RECENT_MAX_LINES; - final int maxlen = layoutManager.getSpanCount() * EXPAND_MAX_LINES; + final int recentmaxlen = SPAN_COUNT_FOR_EMOJI * RECENT_MAX_LINES; + final int maxlen = SPAN_COUNT_FOR_EMOJI * EXPAND_MAX_LINES; int recentSize; - if (type == TYPE_TOPIC_ICON) { + if (type == TYPE_AVATAR_CONSTRUCTOR && showStickers) { + recentSize = recentStickers.size(); + } else if (type == TYPE_AVATAR_CONSTRUCTOR || type == TYPE_TOPIC_ICON) { recentSize = recent.size(); } else { recentSize = recent.size() > recentmaxlen && !recentExpanded ? recentmaxlen : recent.size() + (includeEmpty ? 1 : 0); } boolean selected = false; imageView.setDrawable(null); - if (includeEmpty && position == (searchRow != -1 ? 1 : 0) + (includeHint ? 1 : 0)) { + if (includeEmpty && position == (searchRow != -1 ? 1 : 0) + (longtapHintRow != -1 ? 1 : 0)) { selected = selectedDocumentIds.contains(null); imageView.empty = true; imageView.setPadding(AndroidUtilities.dp(5), AndroidUtilities.dp(5), AndroidUtilities.dp(5), AndroidUtilities.dp(5)); imageView.span = null; imageView.document = null; - } else if (position - (searchRow != -1 ? 1 : 0) - (includeHint ? 1 : 0) < recentSize) { - imageView.span = recent.get(position - (searchRow != -1 ? 1 : 0) - (includeHint ? 1 : 0) - (includeEmpty ? 1 : 0)); - imageView.document = imageView.span == null ? null : imageView.span.document; - selected = imageView.span != null && selectedDocumentIds.contains(imageView.span.getDocumentId()); - } else if (!defaultStatuses.isEmpty() && position - (searchRow != -1 ? 1 : 0) - (includeHint ? 1 : 0) - recentSize - 1 >= 0 && position - (searchRow != -1 ? 1 : 0) - (includeHint ? 1 : 0) - recentSize - 1 < defaultStatuses.size()) { - int index = position - (searchRow != -1 ? 1 : 0) - (includeHint ? 1 : 0) - recentSize - 1; + imageView.isStaticIcon = false; + if (imageView.imageReceiver != null) { + imageView.imageReceiver.clearImage(); + } + } else if (position - (searchRow != -1 ? 1 : 0) - (longtapHintRow != -1 ? 1 : 0) < recentSize) { + int resentPosition = position - (searchRow != -1 ? 1 : 0) - (longtapHintRow != -1 ? 1 : 0) - (includeEmpty ? 1 : 0); + if (type == TYPE_AVATAR_CONSTRUCTOR && showStickers) { + TLRPC.Document document = recentStickers.get(resentPosition); + imageView.setSticker(document); + + } else { + imageView.span = recent.get(resentPosition); + imageView.document = imageView.span == null ? null : imageView.span.document; + selected = imageView.span != null && selectedDocumentIds.contains(imageView.span.getDocumentId()); + imageView.isStaticIcon = false; + if (imageView.imageReceiver != null) { + imageView.imageReceiver.clearImage(); + } + } + } else if (!defaultStatuses.isEmpty() && position - (searchRow != -1 ? 1 : 0) - (longtapHintRow != -1 ? 1 : 0) - recentSize - 1 >= 0 && position - (searchRow != -1 ? 1 : 0) - (longtapHintRow != -1 ? 1 : 0) - recentSize - 1 < defaultStatuses.size()) { + int index = position - (searchRow != -1 ? 1 : 0) - (longtapHintRow != -1 ? 1 : 0) - recentSize - 1; imageView.span = defaultStatuses.get(index); imageView.document = imageView.span == null ? null : imageView.span.document; selected = imageView.span != null && selectedDocumentIds.contains(imageView.span.getDocumentId()); + imageView.isStaticIcon = false; + if (imageView.imageReceiver != null) { + imageView.imageReceiver.clearImage(); + } } else { for (int i = 0; i < positionToSection.size(); ++i) { int startPosition = positionToSection.keyAt(i); @@ -2004,7 +2264,15 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi if (position > startPosition && position <= startPosition + 1 + count) { TLRPC.Document document = pack.documents.get(position - startPosition - 1); if (document != null) { - imageView.span = new AnimatedEmojiSpan(document, null); + if (showStickers) { + imageView.setSticker(document); + } else { + imageView.isStaticIcon = false; + if (imageView.imageReceiver != null) { + imageView.imageReceiver.clearImage(); + } + imageView.span = new AnimatedEmojiSpan(document, null); + } imageView.document = document; } } @@ -2434,11 +2702,25 @@ public void setDrawable(Drawable drawable) { } } + + public void setSticker(TLRPC.Document document) { + this.document = document; + if (imageReceiver == null) { + imageReceiver = new ImageReceiver(); + imageReceiver.setLayerNum(7); + imageReceiver.onAttachedToWindow(); + imageReceiver.setAspectFit(true); + } + SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(document, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f); + imageReceiver.setImage(ImageLocation.getForDocument(document), "100_100_firstframe", null, null, svgThumb, 0, "tgs", document, 0); + isStaticIcon = true; + span = null; + } } public void onEmojiClick(View view, AnimatedEmojiSpan span) { incrementHintUse(); - if (span == null) { + if (span == null || type == TYPE_EMOJI_STATUS && selectedDocumentIds.contains(span.documentId)) { onEmojiSelected(view, null, null, null); } else { TLRPC.TL_emojiStatus status = new TLRPC.TL_emojiStatus(); @@ -2492,6 +2774,9 @@ public void preload(int type, int account) { MediaDataController.getInstance(account).fetchEmojiStatuses(0, true); } else if (type == TYPE_TOPIC_ICON) { MediaDataController.getInstance(account).checkDefaultTopicIcons(); + } else if (type == TYPE_AVATAR_CONSTRUCTOR) { + MediaDataController.getInstance(currentAccount).loadRecents(MediaDataController.TYPE_IMAGE, false, true, false); + MediaDataController.getInstance(account).checkStickers(MediaDataController.TYPE_IMAGE); } MediaDataController.getInstance(account).getStickerSet(new TLRPC.TL_inputStickerSetEmojiDefaultStatuses(), false); } @@ -2505,20 +2790,26 @@ public static void preload(int account) { MediaDataController.getInstance(account).checkReactions(); MediaDataController.getInstance(account).getStickerSet(new TLRPC.TL_inputStickerSetEmojiDefaultStatuses(), false); MediaDataController.getInstance(account).checkDefaultTopicIcons(); + StickerCategoriesListView.preload(account, StickerCategoriesListView.CategoriesType.STATUS); } private boolean defaultSetLoading = false; - private void updateRows(boolean updateEmojipacks, boolean diff) { + + private void updateRows(boolean updateEmojipacks, boolean animated) { + updateRows(updateEmojipacks, animated, true); + } + + private void updateRows(boolean updateEmojipacks, boolean animated, boolean diff) { if (!animationsEnabled) { - diff = false; + animated = false; } - MediaDataController mediaDataController = MediaDataController.getInstance(UserConfig.selectedAccount); + MediaDataController mediaDataController = MediaDataController.getInstance(currentAccount); if (mediaDataController == null) { return; } if (updateEmojipacks || frozenEmojiPacks == null) { - frozenEmojiPacks = new ArrayList<>(mediaDataController.getStickerSets(MediaDataController.TYPE_EMOJIPACKS)); + frozenEmojiPacks = new ArrayList<>(mediaDataController.getStickerSets(showStickers ? MediaDataController.TYPE_IMAGE : MediaDataController.TYPE_EMOJIPACKS)); } ArrayList installedEmojipacks = frozenEmojiPacks; ArrayList featuredEmojiPacks = new ArrayList<>(mediaDataController.getFeaturedEmojiSets()); @@ -2542,15 +2833,36 @@ private void updateRows(boolean updateEmojipacks, boolean diff) { positionToExpand.clear(); rowHashCodes.clear(); positionToButton.clear(); + stickerSets.clear(); + recentStickers.clear(); - if (!installedEmojipacks.isEmpty()) { + if (!installedEmojipacks.isEmpty() || type == TYPE_AVATAR_CONSTRUCTOR) { searchRow = totalCount++; rowHashCodes.add(9); } else { searchRow = -1; } - if (type == TYPE_TOPIC_ICON) { + if (type == TYPE_AVATAR_CONSTRUCTOR) { + if (showStickers) { + recentStickers.addAll(MediaDataController.getInstance(currentAccount).getRecentStickersNoCopy(MediaDataController.TYPE_IMAGE)); + for (int i = 0; i < recentStickers.size(); ++i) { + rowHashCodes.add(Objects.hash(62425, recentStickers.get(i).id)); + totalCount++; + } + } else { + TLRPC.TL_emojiList emojiList = forUser ? MediaDataController.getInstance(currentAccount).profileAvatarConstructorDefault : MediaDataController.getInstance(currentAccount).groupAvatarConstructorDefault; + if (emojiList != null && emojiList.document_id != null && !emojiList.document_id.isEmpty()) { + for (int i = 0; i < emojiList.document_id.size(); ++i) { + recent.add(new AnimatedEmojiSpan(emojiList.document_id.get(i), null)); + } + for (int i = 0; i < recent.size(); ++i) { + rowHashCodes.add(Objects.hash(43223, recent.get(i).getDocumentId())); + totalCount++; + } + } + } + } else if (type == TYPE_TOPIC_ICON) { topicEmojiHeaderRow = totalCount++; rowHashCodes.add(12); defaultTopicIconRow = totalCount++; @@ -2586,7 +2898,7 @@ private void updateRows(boolean updateEmojipacks, boolean diff) { } - if (includeHint && type != TYPE_SET_DEFAULT_REACTION && type != TYPE_TOPIC_ICON) { + if (includeHint && type != TYPE_SET_DEFAULT_REACTION && type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR) { longtapHintRow = totalCount++; rowHashCodes.add(6); } @@ -2643,9 +2955,9 @@ private void updateRows(boolean updateEmojipacks, boolean diff) { rowHashCodes.add(2); } ArrayList defaultEmojiStatuses = MediaDataController.getInstance(currentAccount).getDefaultEmojiStatuses(); - final int maxrecentlen = layoutManager.getSpanCount() * (RECENT_MAX_LINES + 8); + final int maxrecentlen = SPAN_COUNT_FOR_EMOJI * (RECENT_MAX_LINES + 8); if (defaultSet.documents != null && !defaultSet.documents.isEmpty()) { - for (int i = 0; i < Math.min(layoutManager.getSpanCount() - 1, defaultSet.documents.size()); ++i) { + for (int i = 0; i < Math.min(SPAN_COUNT_FOR_EMOJI - 1, defaultSet.documents.size()); ++i) { recent.add(new AnimatedEmojiSpan(defaultSet.documents.get(i), null)); if (recent.size() + (includeEmpty ? 1 : 0) >= maxrecentlen) { break; @@ -2654,12 +2966,8 @@ private void updateRows(boolean updateEmojipacks, boolean diff) { } if (recentEmojiStatuses != null && !recentEmojiStatuses.isEmpty()) { for (TLRPC.EmojiStatus emojiStatus : recentEmojiStatuses) { - long did; - if (emojiStatus instanceof TLRPC.TL_emojiStatus) { - did = ((TLRPC.TL_emojiStatus) emojiStatus).document_id; - } else if (emojiStatus instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) emojiStatus).until > (int) (System.currentTimeMillis() / 1000)) { - did = ((TLRPC.TL_emojiStatusUntil) emojiStatus).document_id; - } else { + Long did = UserObject.getEmojiStatusDocumentId(emojiStatus); + if (did == null) { continue; } boolean foundDuplicate = false; @@ -2679,12 +2987,8 @@ private void updateRows(boolean updateEmojipacks, boolean diff) { } if (defaultEmojiStatuses != null && !defaultEmojiStatuses.isEmpty()) { for (TLRPC.EmojiStatus emojiStatus : defaultEmojiStatuses) { - long did; - if (emojiStatus instanceof TLRPC.TL_emojiStatus) { - did = ((TLRPC.TL_emojiStatus) emojiStatus).document_id; - } else if (emojiStatus instanceof TLRPC.TL_emojiStatusUntil && ((TLRPC.TL_emojiStatusUntil) emojiStatus).until > (int) (System.currentTimeMillis() / 1000)) { - did = ((TLRPC.TL_emojiStatusUntil) emojiStatus).document_id; - } else { + Long did = UserObject.getEmojiStatusDocumentId(emojiStatus); + if (did == null) { continue; } boolean foundDuplicate = false; @@ -2703,7 +3007,7 @@ private void updateRows(boolean updateEmojipacks, boolean diff) { } } - final int maxlen = layoutManager.getSpanCount() * RECENT_MAX_LINES; + final int maxlen = SPAN_COUNT_FOR_EMOJI * RECENT_MAX_LINES; int len = maxlen - (includeEmpty ? 1 : 0); if (recent.size() > len && !recentExpanded) { for (int i = 0; i < len - 1; ++i) { @@ -2727,7 +3031,7 @@ private void updateRows(boolean updateEmojipacks, boolean diff) { if (installedEmojipacks != null) { for (int i = 0, j = 0; i < installedEmojipacks.size(); ++i) { TLRPC.TL_messages_stickerSet set = installedEmojipacks.get(i); - if (set != null && set.set != null && set.set.emojis && !installedEmojiSets.contains(set.set.id)) { + if (set != null && set.set != null && (set.set.emojis || showStickers) && !installedEmojiSets.contains(set.set.id)) { positionToSection.put(totalCount, packs.size()); sectionToPosition.put(packs.size(), totalCount); totalCount++; @@ -2750,8 +3054,8 @@ private void updateRows(boolean updateEmojipacks, boolean diff) { } } } - if (featuredEmojiPacks != null) { - final int maxlen = layoutManager.getSpanCount() * EXPAND_MAX_LINES; + if (featuredEmojiPacks != null && !showStickers) { + final int maxlen = SPAN_COUNT_FOR_EMOJI * EXPAND_MAX_LINES; for (int i = 0; i < featuredEmojiPacks.size(); ++i) { TLRPC.StickerSetCovered set1 = featuredEmojiPacks.get(i); TLRPC.StickerSet set = set1.set; @@ -2808,7 +3112,7 @@ private void updateRows(boolean updateEmojipacks, boolean diff) { } } - if (!pack.installed) { + if (!pack.installed && type != TYPE_AVATAR_CONSTRUCTOR) { positionToButton.put(totalCount, packs.size()); totalCount++; rowHashCodes.add(Objects.hash(3321, set.id)); @@ -2823,35 +3127,39 @@ private void updateRows(boolean updateEmojipacks, boolean diff) { emojiTabs.updateEmojiPacks(packs); }); - if (diff) { + if (animated) { emojiGridView.setItemAnimator(emojiItemAnimator); } else { emojiGridView.setItemAnimator(null); } - DiffUtil.calculateDiff(new DiffUtil.Callback() { - @Override - public int getOldListSize() { - return prevRowHashCodes.size(); - } + if (diff) { + DiffUtil.calculateDiff(new DiffUtil.Callback() { + @Override + public int getOldListSize() { + return prevRowHashCodes.size(); + } - @Override - public int getNewListSize() { - return rowHashCodes.size(); - } + @Override + public int getNewListSize() { + return rowHashCodes.size(); + } - @Override - public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { - return prevRowHashCodes.get(oldItemPosition).equals(rowHashCodes.get(newItemPosition)); - } + @Override + public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { + return prevRowHashCodes.get(oldItemPosition).equals(rowHashCodes.get(newItemPosition)); + } - @Override - public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { - return true; - } - }, false).dispatchUpdatesTo(adapter); + @Override + public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { + return true; + } + }, false).dispatchUpdatesTo(adapter); + } else { + adapter.notifyDataSetChanged(); + } if (!emojiGridView.scrolledByUserOnce) { - emojiGridView.scrollToPosition(1); + emojiGridView.scrollToPosition(0); } } @@ -2863,7 +3171,7 @@ public void expand(int position, View expandButton) { int fromCount, start, toCount; animateExpandFromButtonTranslate = 0; if (index >= 0 && index < packs.size()) { - maxlen = layoutManager.getSpanCount() * EXPAND_MAX_LINES; + maxlen = SPAN_COUNT_FOR_EMOJI * EXPAND_MAX_LINES; EmojiView.EmojiPack pack = packs.get(index); if (pack.expanded) { return; @@ -2880,12 +3188,12 @@ public void expand(int position, View expandButton) { pack.expanded = true; toCount = pack.documents.size(); } else if (index == -1) { - maxlen = layoutManager.getSpanCount() * RECENT_MAX_LINES; + maxlen = SPAN_COUNT_FOR_EMOJI * RECENT_MAX_LINES; if (recentExpanded) { return; } last = false; - start = (searchRow != -1 ? 1 : 0) + (includeHint ? 1 : 0) + (includeEmpty ? 1 : 0); + start = (searchRow != -1 ? 1 : 0) + (longtapHintRow != -1 ? 1 : 0) + (includeEmpty ? 1 : 0); fromCount = recentExpanded ? recent.size() : Math.min(maxlen - (includeEmpty ? 1 : 0) - 2, recent.size()); toCount = recent.size(); recentExpanded = true; @@ -2924,7 +3232,7 @@ public void expand(int position, View expandButton) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - if (drawBackground && type != TYPE_TOPIC_ICON) { + if (drawBackground && type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR) { super.onMeasure( MeasureSpec.makeMeasureSpec((int) Math.min(AndroidUtilities.dp(340 - 16), AndroidUtilities.displaySize.x * .95f), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) Math.min(AndroidUtilities.dp(410 - 16 - 64), AndroidUtilities.displaySize.y * .75f), MeasureSpec.AT_MOST) @@ -2935,6 +3243,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { } private int getCacheType() { + if (type == TYPE_AVATAR_CONSTRUCTOR) { + return AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_STATIC; + } return type == TYPE_EMOJI_STATUS || type == TYPE_SET_DEFAULT_REACTION ? AnimatedEmojiDrawable.CACHE_TYPE_KEYBOARD : AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW; } @@ -3000,6 +3311,12 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { private int lastChildCount = -1; + @Override + public void setAlpha(float alpha) { + super.setAlpha(alpha); + invalidate(); + } + @Override public void dispatchDraw(Canvas canvas) { if (getVisibility() != View.VISIBLE) { @@ -3119,7 +3436,7 @@ public void dispatchDraw(Canvas canvas) { int w = getMeasuredWidth() - firstView.getLeft() * 2; int h = firstView.getMeasuredHeight(); if (w > 0 && h > 0) { - drawable.draw(canvas, time, w, h, 1f); + drawable.draw(canvas, time, w, h, getAlpha()); } canvas.restore(); } @@ -3182,7 +3499,7 @@ public void draw(Canvas canvas, long time, int w, int h, float alpha) { skewAlpha = .25f + .75f * skewAlpha; } } - boolean drawInUi = skewAlpha < 1 || isAnimating() || imageViewEmojis.size() <= 4 || SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_LOW || showAnimator != null && showAnimator.isRunning() || SharedConfig.getLiteMode().enabled(); + boolean drawInUi = skewAlpha < 1 || isAnimating() || imageViewEmojis.size() <= 4 || SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_LOW || (showAnimator != null && showAnimator.isRunning()) || SharedConfig.getLiteMode().enabled() || type == TYPE_AVATAR_CONSTRUCTOR; if (!drawInUi) { boolean animatedExpandIn = animateExpandStartTime > 0 && (SystemClock.elapsedRealtime() - animateExpandStartTime) < animateExpandDuration(); for (int i = 0; i < imageViewEmojis.size(); i++) { @@ -3193,7 +3510,6 @@ public void draw(Canvas canvas, long time, int w, int h, float alpha) { } } } -// canvas.drawRect(0,0,w,h,Theme.DEBUG_RED); if (drawInUi) { prepareDraw(System.currentTimeMillis()); drawInUiThread(canvas, alpha); @@ -3203,7 +3519,7 @@ public void draw(Canvas canvas, long time, int w, int h, float alpha) { } } - float[] verts = new float[16]; +// float[] verts = new float[16]; @Override public void drawBitmap(Canvas canvas, Bitmap bitmap, Paint paint) { @@ -3296,7 +3612,7 @@ public void prepareDraw(long time) { alpha *= alphaT; } } else { - alpha = imageView.getAlpha(); + alpha *= imageView.getAlpha(); } if (!imageView.isDefaultReaction && !imageView.isStaticIcon) { @@ -3339,7 +3655,7 @@ public void prepareDraw(long time) { int w = imageView.getWidth() - imageView.getPaddingLeft() - imageView.getPaddingRight(); int h = imageView.getHeight() - imageView.getPaddingTop() - imageView.getPaddingBottom(); AndroidUtilities.rectTmp2.set(imageView.getPaddingLeft(), imageView.getPaddingTop(), imageView.getWidth() - imageView.getPaddingRight(), imageView.getHeight() - imageView.getPaddingBottom()); - if (imageView.selected && type != TYPE_TOPIC_ICON) { + if (imageView.selected && type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR) { AndroidUtilities.rectTmp2.set( (int) Math.round(AndroidUtilities.rectTmp2.centerX() - AndroidUtilities.rectTmp2.width() / 2f * 0.86f), (int) Math.round(AndroidUtilities.rectTmp2.centerY() - AndroidUtilities.rectTmp2.height() / 2f * 0.86f), @@ -3389,7 +3705,7 @@ protected void drawInUiThread(Canvas canvas, float alpha) { float scale = imageView.getScaleX(); if (imageView.pressedProgress != 0 || imageView.selected) { - scale *= 0.8f + 0.2f * (1f - ((imageView.selected && type != TYPE_TOPIC_ICON) ? 0.7f : imageView.pressedProgress)); + scale *= 0.8f + 0.2f * (1f - ((imageView.selected && type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR) ? 0.7f : imageView.pressedProgress)); } boolean animatedExpandIn = animateExpandStartTime > 0 && (SystemClock.elapsedRealtime() - animateExpandStartTime) < animateExpandDuration(); boolean animatedExpandInLocal = animatedExpandIn && animateExpandFromPosition >= 0 && animateExpandToPosition >= 0 && animateExpandStartTime > 0; @@ -3406,7 +3722,7 @@ protected void drawInUiThread(Canvas canvas, float alpha) { alpha = alphaT; } } else { - alpha = imageView.getAlpha(); + alpha *= imageView.getAlpha(); } AndroidUtilities.rectTmp2.set((int) imageView.getX() + imageView.getPaddingLeft(), imageView.getPaddingTop(), (int) imageView.getX() + imageView.getWidth() - imageView.getPaddingRight(), imageView.getHeight() - imageView.getPaddingBottom()); @@ -3473,8 +3789,11 @@ private void drawImage(Canvas canvas, Drawable drawable, ImageViewEmoji imageVie } } else if ((imageView.isDefaultReaction || imageView.isStaticIcon) && imageView.imageReceiver != null) { + canvas.save(); + canvas.clipRect(imageView.imageReceiver.getDrawRegion().left, imageView.imageReceiver.getDrawRegion().top, imageView.imageReceiver.getDrawRegion().right, imageView.imageReceiver.getDrawRegion().bottom); imageView.imageReceiver.setAlpha(alpha); imageView.imageReceiver.draw(canvas); + canvas.restore(); } } @@ -3534,12 +3853,12 @@ protected void onDetachedFromWindow() { } } - private Runnable updateRowsDelayed = () -> updateRows(true, true); + private final Runnable updateRowsDelayed = () -> NotificationCenter.getInstance(currentAccount).doOnIdle(() -> updateRows(true, true)); @Override public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.stickersDidLoad) { - if (((int) args[0]) == MediaDataController.TYPE_EMOJIPACKS) { + if (((int) args[0]) == MediaDataController.TYPE_EMOJIPACKS || (((int) args[0]) == MediaDataController.TYPE_IMAGE && showStickers)) { updateRows(true, true); } } else if (id == NotificationCenter.featuredEmojiDidLoad) { @@ -3584,7 +3903,7 @@ public void onShow(Runnable dismiss) { hideAnimator.cancel(); hideAnimator = null; } - boolean animated = type != TYPE_TOPIC_ICON; + boolean animated = type != TYPE_TOPIC_ICON && type != TYPE_AVATAR_CONSTRUCTOR; if (animated) { showAnimator = ValueAnimator.ofFloat(0, 1); @@ -3625,11 +3944,16 @@ private class SearchBox extends FrameLayout { private FrameLayout box; private ImageView search; private ImageView clear; - private CloseProgressDrawable2 clearDrawable; + private FrameLayout inputBox; + private View inputBoxGradient; + private SearchStateDrawable searchStateDrawable; private EditTextCaption input; + private StickerCategoriesListView categoriesListView; + public SearchBox(Context context) { super(context); + setClickable(true); setBackgroundColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground, resourcesProvider)); box = new FrameLayout(context); @@ -3643,16 +3967,33 @@ public void getOutline(View view, Outline outline) { } }); } - addView(box, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.TOP | Gravity.FILL_HORIZONTAL, 8, 4 + 8, 8, 8)); + addView(box, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.TOP | Gravity.FILL_HORIZONTAL, 8, 8 + 4, 8, 8)); search = new ImageView(context); search.setScaleType(ImageView.ScaleType.CENTER); - search.setImageResource(R.drawable.smiles_inputsearch); - search.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_emojiSearchIcon, resourcesProvider), PorterDuff.Mode.MULTIPLY)); + searchStateDrawable = new SearchStateDrawable(); + searchStateDrawable.setIconState(SearchStateDrawable.State.STATE_SEARCH, false); + searchStateDrawable.setColor(Theme.getColor(Theme.key_chat_emojiSearchIcon, resourcesProvider)); + search.setImageDrawable(searchStateDrawable); + search.setOnClickListener(e -> { + if (searchStateDrawable.getIconState() == SearchStateDrawable.State.STATE_BACK) { + input.setText(""); + search(null, true, false); + if (categoriesListView != null) { + categoriesListView.selectCategory(null); + categoriesListView.updateCategoriesShown(true, true); + } + input.clearAnimation(); + input.animate().translationX(0).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + showInputBoxGradient(false); + } + }); box.addView(search, LayoutHelper.createFrame(36, 36, Gravity.LEFT | Gravity.TOP)); - input = new EditTextCaption(context, resourcesProvider) { + inputBox = new FrameLayout(context); + box.addView(inputBox, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 36, 0, 0, 0)); + input = new EditTextCaption(context, resourcesProvider) { @Override protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { if (focused) { @@ -3667,30 +4008,28 @@ protected void onFocusChanged(boolean focused, int direction, Rect previouslyFoc }; input.addTextChangedListener(new TextWatcher() { @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - - } - + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - - } - + public void onTextChanged(CharSequence s, int start, int before, int count) {} @Override public void afterTextChanged(Editable s) { - search(input.getText() == null || AndroidUtilities.trim(input.getText(), null).length() == 0 ? null : input.getText().toString()); + final String query = input.getText() == null || AndroidUtilities.trim(input.getText(), null).length() == 0 ? null : input.getText().toString(); + search(query); + if (categoriesListView != null) { + categoriesListView.selectCategory(null); + categoriesListView.updateCategoriesShown(TextUtils.isEmpty(query), true); + } + if (input != null) { + input.clearAnimation(); + input.animate().translationX(0).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + } + showInputBoxGradient(false); } }); input.setBackground(null); input.setPadding(0, 0, AndroidUtilities.dp(4), 0); input.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - if (type == TYPE_EMOJI_STATUS) { - input.setHint(LocaleController.getString(R.string.SearchEmojiHint)); - } else if (type == TYPE_REACTIONS || type == TYPE_SET_DEFAULT_REACTION) { - input.setHint(LocaleController.getString(R.string.SearchReactionsHint)); - } else { - input.setHint(LocaleController.getString(R.string.SearchIconsHint)); - } + input.setHint(LocaleController.getString("Search", R.string.Search)); input.setHintTextColor(Theme.getColor(Theme.key_chat_emojiSearchIcon, resourcesProvider)); input.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider)); @@ -3702,36 +4041,146 @@ public void afterTextChanged(Editable s) { input.setMaxLines(1); input.setSingleLine(true); input.setLines(1); - box.addView(input, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 36, -1, 32, 0)); + input.setTranslationY(AndroidUtilities.dp(-1)); + inputBox.addView(input, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 0, 0, 32, 0)); + + inputBoxGradient = new View(context); + Drawable gradientDrawable = context.getResources().getDrawable(R.drawable.gradient_right).mutate(); + gradientDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_emojiPanelBackground, resourcesProvider), PorterDuff.Mode.MULTIPLY)); + inputBoxGradient.setBackground(gradientDrawable); + inputBoxGradient.setAlpha(0f); + inputBox.addView(inputBoxGradient, LayoutHelper.createFrame(18, LayoutHelper.MATCH_PARENT, Gravity.LEFT)); + + setOnClickListener(e -> { + onInputFocus(); + input.requestFocus(); + scrollToPosition(0, 0); + }); + + if (type == TYPE_REACTIONS || type == TYPE_EMOJI_STATUS || type == TYPE_AVATAR_CONSTRUCTOR) { + int categoriesType; + switch (type) { + case TYPE_EMOJI_STATUS: + categoriesType = StickerCategoriesListView.CategoriesType.STATUS; + break; + case TYPE_AVATAR_CONSTRUCTOR: + categoriesType = StickerCategoriesListView.CategoriesType.PROFILE_PHOTOS; + break; + case TYPE_REACTIONS: + default: + categoriesType = StickerCategoriesListView.CategoriesType.DEFAULT; + break; + } + categoriesListView = new StickerCategoriesListView(context, categoriesType, resourcesProvider) { + @Override + public void selectCategory(int categoryIndex) { + super.selectCategory(categoryIndex); + updateButton(); + } + + @Override + protected boolean isTabIconsAnimationEnabled(boolean loaded) { + return !SharedConfig.getLiteMode().enabled() && (!loaded || type == TYPE_AVATAR_CONSTRUCTOR); + } + }; + categoriesListView.setShownButtonsAtStart(type == TYPE_AVATAR_CONSTRUCTOR ? 6.5f : 4.5f); + categoriesListView.setDontOccupyWidth((int) (input.getPaint().measureText(input.getHint() + ""))); + categoriesListView.setBackgroundColor(Theme.getColor(Theme.key_chat_emojiPanelBackground, resourcesProvider)); + categoriesListView.setOnScrollIntoOccupiedWidth(scrolled -> { + input.setTranslationX(-Math.max(0, scrolled)); + showInputBoxGradient(scrolled > 0); + updateButton(); + }); + categoriesListView.setOnCategoryClick(category -> { + if (categoriesListView.getSelectedCategory() == category) { + search(null, false, false); + categoriesListView.selectCategory(null); + } else { + search(category.emojis, false, false); + categoriesListView.selectCategory(category); + } + }); + box.addView(categoriesListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.FILL, 36, 0, 0, 0)); + } clear = new ImageView(context); clear.setScaleType(ImageView.ScaleType.CENTER); - clear.setImageDrawable(clearDrawable = new CloseProgressDrawable2(1.25f) { + clear.setImageDrawable(new CloseProgressDrawable2(1.25f) { + { setSide(AndroidUtilities.dp(7)); } @Override protected int getCurrentColor() { return Theme.getColor(Theme.key_chat_emojiSearchIcon, resourcesProvider); } }); - clearDrawable.setSide(AndroidUtilities.dp(7)); - clear.setScaleX(0.1f); - clear.setScaleY(0.1f); - clear.setAlpha(0.0f); - box.addView(clear, LayoutHelper.createFrame(36, 36, Gravity.RIGHT | Gravity.TOP)); - clear.setOnClickListener(v -> { + clear.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), Theme.RIPPLE_MASK_CIRCLE_20DP, AndroidUtilities.dp(15))); + clear.setAlpha(0f); + clear.setOnClickListener(e -> { input.setText(""); - search(null); + search(null, true, false); + if (categoriesListView != null) { + categoriesListView.selectCategory(null); + categoriesListView.updateCategoriesShown(true, true); + } + input.clearAnimation(); + input.animate().translationX(0).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + showInputBoxGradient(false); }); + box.addView(clear, LayoutHelper.createFrame(36, 36, Gravity.RIGHT | Gravity.TOP)); + } - setOnClickListener(e -> { - onInputFocus(); - input.requestFocus(); - scrollToPosition(0, 0); - }); + private Runnable delayedToggle; + private void toggleClear(boolean enabled) { + if (enabled) { + if (delayedToggle == null) { + AndroidUtilities.runOnUIThread(delayedToggle = () -> { + AndroidUtilities.updateViewShow(clear, true); + }, 340); + } + } else { + if (delayedToggle != null) { + AndroidUtilities.cancelRunOnUIThread(delayedToggle); + delayedToggle = null; + } + AndroidUtilities.updateViewShow(clear, false); + } + } + + private boolean inputBoxShown = false; + private void showInputBoxGradient(boolean show) { + if (show == inputBoxShown || inputBoxGradient == null) { + return; + } + inputBoxShown = show; + inputBoxGradient.clearAnimation(); + inputBoxGradient.animate().alpha(show ? 1 : 0).setDuration(120).setInterpolator(CubicBezierInterpolator.EASE_OUT_QUINT).start(); + } + + public boolean isInProgress() { + return searchStateDrawable.getIconState() == SearchStateDrawable.State.STATE_PROGRESS; + } + + public void showProgress(boolean progress) { + if (progress) { + searchStateDrawable.setIconState(SearchStateDrawable.State.STATE_PROGRESS); + } else { + updateButton(true); + } + } + + private void updateButton() { + updateButton(false); + } + + private void updateButton(boolean force) { + if (!isInProgress() || input.length() == 0 && (categoriesListView == null || categoriesListView.getSelectedCategory() == null) || force) { + boolean backButton = input.length() > 0 || categoriesListView != null && categoriesListView.isCategoriesShown() && (categoriesListView.isScrolledIntoOccupiedWidth() || categoriesListView.getSelectedCategory() != null); + searchStateDrawable.setIconState(backButton ? SearchStateDrawable.State.STATE_BACK : SearchStateDrawable.State.STATE_SEARCH); + } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(4 + 8+36+8), MeasureSpec.EXACTLY)); + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(8+36+8), MeasureSpec.EXACTLY)); } } @@ -4056,7 +4505,7 @@ protected void dispatchDraw(Canvas canvas) { if (skew < 1) { canvas.translate(AndroidUtilities.rectTmp2.left, AndroidUtilities.rectTmp2.top); canvas.scale(1f, skew, 0, 0); - canvas.skew((1f - 2f * imageViewEmoji.skewIndex / layoutManager.getSpanCount()) * (1f - skew), 0); + canvas.skew((1f - 2f * imageViewEmoji.skewIndex / SPAN_COUNT_FOR_EMOJI) * (1f - skew), 0); canvas.translate(-AndroidUtilities.rectTmp2.left, -AndroidUtilities.rectTmp2.top); } canvas.clipRect(0, 0, getWidth(), clipBottom + showT * AndroidUtilities.dp(45)); @@ -4068,9 +4517,9 @@ protected void dispatchDraw(Canvas canvas) { AndroidUtilities.rectTmp2.offset(AndroidUtilities.dp(8 * skew), 0); } else if (imageViewEmoji.skewIndex == 1) { AndroidUtilities.rectTmp2.offset(AndroidUtilities.dp(4 * skew), 0); - } else if (imageViewEmoji.skewIndex == layoutManager.getSpanCount() - 2) { + } else if (imageViewEmoji.skewIndex == SPAN_COUNT_FOR_EMOJI - 2) { AndroidUtilities.rectTmp2.offset(-AndroidUtilities.dp(-4 * skew), 0); - } else if (imageViewEmoji.skewIndex == layoutManager.getSpanCount() - 1) { + } else if (imageViewEmoji.skewIndex == SPAN_COUNT_FOR_EMOJI - 1) { AndroidUtilities.rectTmp2.offset(AndroidUtilities.dp(-8 * skew), 0); } canvas.saveLayerAlpha(AndroidUtilities.rectTmp2.left, AndroidUtilities.rectTmp2.top, AndroidUtilities.rectTmp2.right, AndroidUtilities.rectTmp2.bottom, (int) (255 * (1f - showT)), Canvas.ALL_SAVE_FLAG); @@ -4295,7 +4744,11 @@ private void done(Integer date) { } animateShow(false, () -> { onEnd(date); - super.dismiss(); + try { + super.dismiss(); + } catch (Exception ignore) { + + } }, () -> { if (date != null) { try { @@ -4530,7 +4983,7 @@ public void setPressed(boolean pressed) { return; } - void setAnimationsEnabled(boolean aniationsEnabled) { + public void setAnimationsEnabled(boolean aniationsEnabled) { this.animationsEnabled = aniationsEnabled; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/StickersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/StickersActivity.java index 97261b36225..2a69c142e3b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/StickersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/StickersActivity.java @@ -1170,7 +1170,7 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { TLRPC.TL_availableReaction availableReaction = MediaDataController.getInstance(currentAccount).getReactionsMap().get(reaction); if (availableReaction != null) { SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(availableReaction.static_icon.thumbs, Theme.key_windowBackgroundGray, 1.0f); - settingsCell.getValueBackupImageView().getImageReceiver().setImage(ImageLocation.getForDocument(availableReaction.center_icon), "100_100_lastframe", svgThumb, "webp", availableReaction, 1); + settingsCell.getValueBackupImageView().getImageReceiver().setImage(ImageLocation.getForDocument(availableReaction.center_icon), "100_100_lastreactframe", svgThumb, "webp", availableReaction, 1); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TextMessageEnterTransition.java b/TMessagesProj/src/main/java/org/telegram/ui/TextMessageEnterTransition.java index 881c90abe83..799f575bcf0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TextMessageEnterTransition.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TextMessageEnterTransition.java @@ -427,7 +427,7 @@ public void onDraw(Canvas canvas) { if (messageView.animatedEmojiStack != null) { messageView.animatedEmojiStack.clearPositions(); } - messageView.drawMessageText(bitmapCanvas, messageView.getMessageObject().textLayoutBlocks, true, 1f, true); + messageView.drawMessageText(bitmapCanvas, messageView.getMessageObject().textLayoutBlocks, messageView.getMessageObject().textXOffset, true, 1f, true); messageView.drawAnimatedEmojis(bitmapCanvas, 1f); } float listViewBottom = listView.getY() - container.getY() + listView.getMeasuredHeight(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java index b5ebb2bf6d3..4f6064071f8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemeActivity.java @@ -177,6 +177,7 @@ public class ThemeActivity extends BaseFragment implements NotificationCenter.No private int themeAccentListRow; private int themeInfoRow; private int chatBlurRow; + private int pauseOnRecordRow; private int swipeGestureHeaderRow; private int swipeGestureRow; @@ -514,6 +515,7 @@ private void updateRows(boolean notify) { chatListRow = -1; chatListInfoRow = -1; chatBlurRow = -1; + pauseOnRecordRow = -1; lightModeRow = -1; lightModeTopInfoRow = -1; @@ -618,6 +620,7 @@ private void updateRows(boolean notify) { directShareRow = rowCount++; enableAnimationsRow = rowCount++; raiseToSpeakRow = rowCount++; + pauseOnRecordRow = rowCount++; bluetoothScoRow = rowCount++; sendByEnterRow = rowCount++; if (SharedConfig.canBlurChat()) { @@ -626,7 +629,7 @@ private void updateRows(boolean notify) { distanceRow = rowCount++; settings2Row = rowCount++; - if (SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_LOW || BuildVars.DEBUG_VERSION) { + if (SharedConfig.getDevicePerformanceClass() <= SharedConfig.PERFORMANCE_CLASS_AVERAGE || BuildVars.DEBUG_VERSION) { lightModeRow = rowCount++; lightModeTopInfoRow = rowCount++; } @@ -903,7 +906,7 @@ public void onItemClick(int id) { if (setFontSize(AndroidUtilities.isTablet() ? 18 : 16)) { changed = true; } - if (setBubbleRadius(10, true)) { + if (setBubbleRadius(17, true)) { changed = true; } if (changed) { @@ -1018,6 +1021,11 @@ public void onItemClick(int id) { if (view instanceof TextCheckCell) { ((TextCheckCell) view).setChecked(SharedConfig.raiseToSpeak); } + } else if (position == pauseOnRecordRow) { + SharedConfig.togglePauseMusicOnRecord(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(SharedConfig.pauseMusicOnRecord); + } } else if (position == distanceRow) { if (getParentActivity() == null) { return; @@ -1310,7 +1318,7 @@ private void updateMenuItem() { } int fontSize = AndroidUtilities.isTablet() ? 18 : 16; Theme.ThemeInfo currentTheme = Theme.getCurrentTheme(); - if (SharedConfig.fontSize != fontSize || SharedConfig.bubbleRadius != 10 || !currentTheme.firstAccentIsDefault || currentTheme.currentAccentId != Theme.DEFALT_THEME_ACCENT_ID || accent != null && accent.overrideWallpaper != null && !Theme.DEFAULT_BACKGROUND_SLUG.equals(accent.overrideWallpaper.slug)) { + if (SharedConfig.fontSize != fontSize || SharedConfig.bubbleRadius != 17 || !currentTheme.firstAccentIsDefault || currentTheme.currentAccentId != Theme.DEFALT_THEME_ACCENT_ID || accent != null && accent.overrideWallpaper != null && !Theme.DEFAULT_BACKGROUND_SLUG.equals(accent.overrideWallpaper.slug)) { menuItem.showSubItem(reset_settings); } else { menuItem.hideSubItem(reset_settings); @@ -2237,6 +2245,8 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { textCheckCell.setTextAndCheck(LocaleController.getString("SendByEnter", R.string.SendByEnter), preferences.getBoolean("send_by_enter", false), true); } else if (position == raiseToSpeakRow) { textCheckCell.setTextAndCheck(LocaleController.getString("RaiseToSpeak", R.string.RaiseToSpeak), SharedConfig.raiseToSpeak, true); + } else if (position == pauseOnRecordRow) { + textCheckCell.setTextAndCheck(LocaleController.getString(R.string.PauseMusicOnRecord), SharedConfig.pauseMusicOnRecord, true); } else if (position == customTabsRow) { textCheckCell.setTextAndValueAndCheck(LocaleController.getString("ChromeCustomTabs", R.string.ChromeCustomTabs), LocaleController.getString("ChromeCustomTabsInfo", R.string.ChromeCustomTabsInfo), SharedConfig.customTabs, false, true); } else if (position == directShareRow) { @@ -2352,7 +2362,7 @@ public int getItemViewType(int position) { } else if (position == automaticBrightnessRow) { return TYPE_BRIGHTNESS; } else if (position == scheduleLocationRow || position == enableAnimationsRow || position == sendByEnterRow || - position == raiseToSpeakRow || position == customTabsRow || + position == raiseToSpeakRow || position == pauseOnRecordRow || position == customTabsRow || position == directShareRow || position == chatBlurRow || position == lightModeRow) { return TYPE_TEXT_CHECK; } else if (position == textSizeRow) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java index 4edde87cd1c..61debde21fa 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java @@ -2042,6 +2042,9 @@ private void clearSelectedTopics() { private void toggleSelection(View view) { if (view instanceof TopicDialogCell) { TopicDialogCell cell = (TopicDialogCell) view; + if (cell.forumTopic == null) { + return; + } int id = cell.forumTopic.id; if (!selectedTopics.remove(id)) { selectedTopics.add(id); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/WallpapersListActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/WallpapersListActivity.java index 209c36dee17..6a3b4e4d875 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/WallpapersListActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/WallpapersListActivity.java @@ -564,7 +564,7 @@ public void onItemClick(int id) { } else if (id == forward) { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 3); + args.putInt("dialogsType", DialogsActivity.DIALOGS_TYPE_FORWARD); DialogsActivity fragment = new DialogsActivity(args); fragment.setDelegate((fragment1, dids, message, param) -> { StringBuilder fmessage = new StringBuilder(); @@ -614,7 +614,7 @@ public void onItemClick(int id) { args1.putLong("chat_id", -did); } if (!MessagesController.getInstance(currentAccount).checkCanOpenChat(args1, fragment1)) { - return; + return true; } } NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.closeChats); @@ -623,6 +623,7 @@ public void onItemClick(int id) { presentFragment(chatActivity, true); SendMessagesHelper.getInstance(currentAccount).sendMessage(fmessage.toString(), did, null, null, null, true, null, null, null, true, 0, null, false); } + return true; }); presentFragment(fragment); } diff --git a/TMessagesProj/src/main/java/org/webrtc/DefaultVideoEncoderFactory.java b/TMessagesProj/src/main/java/org/webrtc/DefaultVideoEncoderFactory.java index 76896b6b2d7..87dccd7f82e 100644 --- a/TMessagesProj/src/main/java/org/webrtc/DefaultVideoEncoderFactory.java +++ b/TMessagesProj/src/main/java/org/webrtc/DefaultVideoEncoderFactory.java @@ -11,6 +11,9 @@ package org.webrtc; import androidx.annotation.Nullable; + +import com.google.android.exoplayer2.util.Log; + import java.util.Arrays; import java.util.LinkedHashSet; diff --git a/TMessagesProj/src/main/java/org/webrtc/HardwareVideoEncoderFactory.java b/TMessagesProj/src/main/java/org/webrtc/HardwareVideoEncoderFactory.java index 8e9bac2ecc3..a147295696c 100644 --- a/TMessagesProj/src/main/java/org/webrtc/HardwareVideoEncoderFactory.java +++ b/TMessagesProj/src/main/java/org/webrtc/HardwareVideoEncoderFactory.java @@ -11,18 +11,20 @@ package org.webrtc; import static org.webrtc.MediaCodecUtils.EXYNOS_PREFIX; +import static org.webrtc.MediaCodecUtils.EXYNOS_PREFIX_C2; +import static org.webrtc.MediaCodecUtils.HISI_PREFIX; import static org.webrtc.MediaCodecUtils.INTEL_PREFIX; import static org.webrtc.MediaCodecUtils.QCOM_PREFIX; -import static org.webrtc.MediaCodecUtils.HISI_PREFIX; import android.media.MediaCodecInfo; -import android.media.MediaCodecList; import android.os.Build; +import android.util.Log; + +import androidx.annotation.Nullable; import org.telegram.messenger.voip.Instance; import org.telegram.messenger.voip.VoIPService; -import androidx.annotation.Nullable; import java.util.ArrayList; import java.util.List; @@ -222,7 +224,8 @@ private boolean isHardwareSupportedInCurrentSdkVp8(MediaCodecInfo info) { || (name.startsWith(EXYNOS_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) // Intel Vp8 encoder is supported in LOLLIPOP or later, with the intel encoder enabled. || (name.startsWith(INTEL_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP - && enableIntelVp8Encoder); + && enableIntelVp8Encoder) + || ((name.startsWith(EXYNOS_PREFIX_C2) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)); } private boolean isHardwareSupportedInCurrentSdkVp9(MediaCodecInfo info) { diff --git a/TMessagesProj/src/main/java/org/webrtc/MediaCodecUtils.java b/TMessagesProj/src/main/java/org/webrtc/MediaCodecUtils.java index 40dca27a5de..f59a21d92f2 100644 --- a/TMessagesProj/src/main/java/org/webrtc/MediaCodecUtils.java +++ b/TMessagesProj/src/main/java/org/webrtc/MediaCodecUtils.java @@ -16,14 +16,12 @@ import android.media.MediaCodecList; import android.os.Build; -import org.telegram.messenger.FileLog; -import org.telegram.messenger.voip.VoIPService; - import androidx.annotation.Nullable; +import org.telegram.messenger.FileLog; + import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.Map; @@ -35,6 +33,7 @@ class MediaCodecUtils { // Prefixes for supported hardware encoder/decoder component names. static final String EXYNOS_PREFIX = "OMX.Exynos."; + static final String EXYNOS_PREFIX_C2 = "c2.exynos."; static final String INTEL_PREFIX = "OMX.Intel."; static final String NVIDIA_PREFIX = "OMX.Nvidia."; static final String QCOM_PREFIX = "OMX.qcom."; diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_channel_create.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_channel_create.png new file mode 100644 index 00000000000..c7ecdb1815b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_channel_create.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_download_settings.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_download_settings.png new file mode 100644 index 00000000000..da98eae6c8b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_download_settings.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_activities.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_activities.png index 6df94497329..d9f07f27920 100644 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_activities.png and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_activities.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_angry.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_angry.png new file mode 100644 index 00000000000..2f2f9ccad7a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_angry.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_back.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_back.png new file mode 100644 index 00000000000..044f51cc870 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_back.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_bath.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_bath.png new file mode 100644 index 00000000000..662bebd0f15 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_bath.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_busy.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_busy.png new file mode 100644 index 00000000000..1a1aa669cc5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_busy.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_dislike.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_dislike.png new file mode 100644 index 00000000000..5ff72d2173f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_dislike.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_food.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_food.png index bb46604e500..0911c7093f0 100644 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_food.png and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_food.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_happy.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_happy.png new file mode 100644 index 00000000000..d6242143e47 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_happy.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_hi.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_hi.png new file mode 100644 index 00000000000..61a5e910c24 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_hi.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_home.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_home.png new file mode 100644 index 00000000000..36b9d3080d2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_home.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_like.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_like.png new file mode 100644 index 00000000000..a596b56e09f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_like.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_love.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_love.png new file mode 100644 index 00000000000..1f844a27364 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_love.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_neutral.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_neutral.png new file mode 100644 index 00000000000..370cad77f71 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_neutral.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_omg.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_omg.png new file mode 100644 index 00000000000..eef79fee4ff Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_omg.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_party.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_party.png new file mode 100644 index 00000000000..8bfcd1de3d3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_party.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_person.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_person.png new file mode 100644 index 00000000000..bba030e0526 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_person.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_sad.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_sad.png new file mode 100644 index 00000000000..e14a99ed701 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_sad.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_sleep.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_sleep.png new file mode 100644 index 00000000000..03848d1faff Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_sleep.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_stickers.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_stickers.png new file mode 100644 index 00000000000..b0eec704924 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_stickers.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_study.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_study.png new file mode 100644 index 00000000000..763a15f4f28 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_study.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_tongue.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_tongue.png new file mode 100644 index 00000000000..01f4df16556 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_tongue.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_vacation.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_vacation.png new file mode 100644 index 00000000000..6c6283b078f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_vacation.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_what.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_what.png new file mode 100644 index 00000000000..bdca1b7e757 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_what.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_work.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_work.png new file mode 100644 index 00000000000..df3ee4b8e67 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_emoji_work.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_autodelete.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_autodelete.png new file mode 100644 index 00000000000..d130d6f4c10 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_autodelete.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_blocked.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_blocked.png new file mode 100644 index 00000000000..fa005bc31c9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_blocked.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_calls.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_calls.png new file mode 100644 index 00000000000..43f3b8a2105 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_calls.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_files.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_files.png new file mode 100644 index 00000000000..d05ffda5f93 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_files.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_messages.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_messages.png new file mode 100644 index 00000000000..858706671e6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_messages.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_music.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_music.png new file mode 100644 index 00000000000..3ab04523785 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_music.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_photos.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_photos.png new file mode 100644 index 00000000000..1d308d57d6c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_photos.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_received.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_received.png new file mode 100644 index 00000000000..68caa3dd4c8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_received.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_sent.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_sent.png new file mode 100644 index 00000000000..fbddd3a92a1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_sent.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_videos.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_videos.png new file mode 100644 index 00000000000..5443cb1e260 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_videos.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_voice.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_voice.png new file mode 100644 index 00000000000..8ac581698e3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_data_voice.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_datausage.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_datausage.png new file mode 100644 index 00000000000..d083c94fb78 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_datausage.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_devices.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_devices.png new file mode 100644 index 00000000000..553b5fe5050 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_devices.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_email.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_email.png new file mode 100644 index 00000000000..9364dc54e15 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_email.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_passcode_off.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_passcode_off.png new file mode 100644 index 00000000000..564806bb1a7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_passcode_off.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_passcode_on.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_passcode_on.png new file mode 100644 index 00000000000..3b31d978f46 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_passcode_on.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_permissions.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_permissions.png new file mode 100644 index 00000000000..85b97dde895 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_permissions.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_plus.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_plus.png new file mode 100644 index 00000000000..a7e13b41d0c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_plus.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_sdcard.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_sdcard.png new file mode 100644 index 00000000000..1181f57ef94 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_sdcard.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_storageusage.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_storageusage.png new file mode 100644 index 00000000000..2a3959fda02 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_filled_storageusage.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_download.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_download.png new file mode 100644 index 00000000000..80d3f89afab Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_download.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_lock3.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_lock3.png new file mode 100644 index 00000000000..e1fa596d0a6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_lock3.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_upload.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_upload.png new file mode 100644 index 00000000000..3984f65d551 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_upload.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_premium_translate.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_premium_translate.png new file mode 100644 index 00000000000..17c47dd47e3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_premium_translate.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_smile_status.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_smile_status.png new file mode 100644 index 00000000000..3aa209db4a2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_smile_status.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_channel_create.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_channel_create.png new file mode 100644 index 00000000000..9b5a168160d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_channel_create.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_download_settings.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_download_settings.png new file mode 100644 index 00000000000..2f3c231aee6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_download_settings.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_activities.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_activities.png index 481d4e08df3..6a118c73e79 100644 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_activities.png and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_activities.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_angry.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_angry.png new file mode 100644 index 00000000000..4917f47527a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_angry.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_back.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_back.png new file mode 100644 index 00000000000..7b5a9f34789 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_back.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_bath.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_bath.png new file mode 100644 index 00000000000..a693b972c2e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_bath.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_busy.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_busy.png new file mode 100644 index 00000000000..2059e0b32d1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_busy.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_dislike.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_dislike.png new file mode 100644 index 00000000000..0e9b993f15f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_dislike.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_food.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_food.png index 4c63c287f15..2924d3d8a9c 100644 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_food.png and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_food.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_happy.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_happy.png new file mode 100644 index 00000000000..3011b2e419f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_happy.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_hi.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_hi.png new file mode 100644 index 00000000000..550b6461d79 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_hi.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_home.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_home.png new file mode 100644 index 00000000000..6c92c48fc3f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_home.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_like.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_like.png new file mode 100644 index 00000000000..e8c47893090 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_like.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_love.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_love.png new file mode 100644 index 00000000000..de4e490c910 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_love.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_neutral.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_neutral.png new file mode 100644 index 00000000000..146e446e523 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_neutral.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_omg.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_omg.png new file mode 100644 index 00000000000..17d6835bd4e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_omg.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_party.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_party.png new file mode 100644 index 00000000000..0e60a7d1804 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_party.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_person.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_person.png new file mode 100644 index 00000000000..372718ee13e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_person.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_sad.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_sad.png new file mode 100644 index 00000000000..8e9c986fbd5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_sad.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_sleep.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_sleep.png new file mode 100644 index 00000000000..8a58a9671ce Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_sleep.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_stickers.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_stickers.png new file mode 100644 index 00000000000..daa3f215e54 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_stickers.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_study.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_study.png new file mode 100644 index 00000000000..e9d35731586 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_study.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_tongue.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_tongue.png new file mode 100644 index 00000000000..8e95182e4c9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_tongue.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_vacation.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_vacation.png new file mode 100644 index 00000000000..eb996261438 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_vacation.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_what.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_what.png new file mode 100644 index 00000000000..32aba82e910 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_what.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_work.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_work.png new file mode 100644 index 00000000000..829ca59ca69 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_emoji_work.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_autodelete.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_autodelete.png new file mode 100644 index 00000000000..cd741c8e16a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_autodelete.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_blocked.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_blocked.png new file mode 100644 index 00000000000..c26c84d67c2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_blocked.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_calls.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_calls.png new file mode 100644 index 00000000000..ebd73c3bb2a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_calls.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_files.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_files.png new file mode 100644 index 00000000000..88e155d3dc5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_files.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_messages.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_messages.png new file mode 100644 index 00000000000..51ed58fc9e7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_messages.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_music.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_music.png new file mode 100644 index 00000000000..cf0f6d5ee40 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_music.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_photos.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_photos.png new file mode 100644 index 00000000000..03a9d7bebdc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_photos.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_received.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_received.png new file mode 100644 index 00000000000..348a3646069 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_received.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_sent.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_sent.png new file mode 100644 index 00000000000..f03c8cd983c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_sent.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_videos.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_videos.png new file mode 100644 index 00000000000..e68b58bf203 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_videos.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_voice.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_voice.png new file mode 100644 index 00000000000..eec3fbf10ac Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_data_voice.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_datausage.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_datausage.png new file mode 100644 index 00000000000..8f402616390 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_datausage.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_devices.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_devices.png new file mode 100644 index 00000000000..d712d51a295 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_devices.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_email.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_email.png new file mode 100644 index 00000000000..45c57009ad3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_email.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_passcode_off.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_passcode_off.png new file mode 100644 index 00000000000..cc151b3899a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_passcode_off.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_passcode_on.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_passcode_on.png new file mode 100644 index 00000000000..70beef3711e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_passcode_on.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_permissions.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_permissions.png new file mode 100644 index 00000000000..dd4d9e62a6d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_permissions.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_plus.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_plus.png new file mode 100644 index 00000000000..960dd891534 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_plus.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_sdcard.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_sdcard.png new file mode 100644 index 00000000000..80b7d06c498 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_sdcard.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_storageusage.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_storageusage.png new file mode 100644 index 00000000000..c4a0bf9ba45 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_filled_storageusage.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_download.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_download.png new file mode 100644 index 00000000000..fd404abd4aa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_download.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_lock3.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_lock3.png new file mode 100644 index 00000000000..4d562a90aa3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_lock3.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_upload.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_upload.png new file mode 100644 index 00000000000..2f82a04d2c8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_upload.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_premium_translate.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_premium_translate.png new file mode 100644 index 00000000000..32a3942ef84 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_premium_translate.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_smile_status.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_smile_status.png new file mode 100644 index 00000000000..0761be69793 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_smile_status.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_channel_create.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_channel_create.png new file mode 100644 index 00000000000..53b0a25c3c0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_channel_create.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_download_settings.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_download_settings.png new file mode 100644 index 00000000000..c85c04fc42c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_download_settings.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_activities.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_activities.png index 898b395d1a3..af874d5507f 100644 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_activities.png and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_activities.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_angry.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_angry.png new file mode 100644 index 00000000000..06c4be53216 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_angry.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_back.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_back.png new file mode 100644 index 00000000000..da5d1e571b0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_back.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_bath.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_bath.png new file mode 100644 index 00000000000..d50924bd534 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_bath.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_busy.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_busy.png new file mode 100644 index 00000000000..9e5731cfdd9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_busy.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_dislike.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_dislike.png new file mode 100644 index 00000000000..b76dd319ed7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_dislike.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_food.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_food.png index a95a9e3b765..10fedebf853 100644 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_food.png and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_food.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_happy.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_happy.png new file mode 100644 index 00000000000..50a0f24080a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_happy.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_hi.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_hi.png new file mode 100644 index 00000000000..126e88cf536 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_hi.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_home.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_home.png new file mode 100644 index 00000000000..d13a012b2d7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_home.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_like.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_like.png new file mode 100644 index 00000000000..8fb406f8a66 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_like.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_love.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_love.png new file mode 100644 index 00000000000..d33496c224b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_love.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_neutral.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_neutral.png new file mode 100644 index 00000000000..f140e799bd8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_neutral.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_omg.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_omg.png new file mode 100644 index 00000000000..3fb65fecf65 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_omg.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_party.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_party.png new file mode 100644 index 00000000000..6e6eb41117e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_party.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_person.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_person.png new file mode 100644 index 00000000000..9ed0f63af21 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_person.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_sad.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_sad.png new file mode 100644 index 00000000000..cb3dc2d318a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_sad.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_sleep.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_sleep.png new file mode 100644 index 00000000000..d968b18c813 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_sleep.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_stickers.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_stickers.png new file mode 100644 index 00000000000..050830b9121 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_stickers.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_study.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_study.png new file mode 100644 index 00000000000..1f88f2e939f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_study.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_tongue.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_tongue.png new file mode 100644 index 00000000000..cabbc3a2fe2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_tongue.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_vacation.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_vacation.png new file mode 100644 index 00000000000..464c61c6ad2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_vacation.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_what.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_what.png new file mode 100644 index 00000000000..b6225d01b95 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_what.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_work.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_work.png new file mode 100644 index 00000000000..f296d094317 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_emoji_work.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_autodelete.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_autodelete.png new file mode 100644 index 00000000000..a0875f05d2b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_autodelete.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_blocked.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_blocked.png new file mode 100644 index 00000000000..7cb4ed96f71 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_blocked.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_calls.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_calls.png new file mode 100644 index 00000000000..207eedcbe01 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_calls.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_files.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_files.png new file mode 100644 index 00000000000..42f1c12e897 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_files.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_messages.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_messages.png new file mode 100644 index 00000000000..b8877f0fb8b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_messages.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_music.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_music.png new file mode 100644 index 00000000000..83f79b5a37a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_music.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_photos.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_photos.png new file mode 100644 index 00000000000..2a5e9999655 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_photos.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_received.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_received.png new file mode 100644 index 00000000000..31f4cb8fed8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_received.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_sent.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_sent.png new file mode 100644 index 00000000000..7ed2ebfffb6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_sent.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_videos.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_videos.png new file mode 100644 index 00000000000..94c7081855e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_videos.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_voice.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_voice.png new file mode 100644 index 00000000000..f29be26a9be Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_data_voice.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_datausage.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_datausage.png new file mode 100644 index 00000000000..e6dc691bd02 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_datausage.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_devices.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_devices.png new file mode 100644 index 00000000000..2aa5e719722 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_devices.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_email.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_email.png new file mode 100644 index 00000000000..fe88c7cf832 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_email.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_passcode_off.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_passcode_off.png new file mode 100644 index 00000000000..cbc4928c23a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_passcode_off.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_passcode_on.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_passcode_on.png new file mode 100644 index 00000000000..6bd2f3ef14d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_passcode_on.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_permissions.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_permissions.png new file mode 100644 index 00000000000..6f47026b1bf Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_permissions.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_plus.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_plus.png new file mode 100644 index 00000000000..9f98d9a812e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_plus.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_sdcard.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_sdcard.png new file mode 100644 index 00000000000..babdec449ac Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_sdcard.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_storageusage.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_storageusage.png new file mode 100644 index 00000000000..17fe0ab309a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_filled_storageusage.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_download.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_download.png new file mode 100644 index 00000000000..6e2ced23a98 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_download.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_lock3.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_lock3.png new file mode 100644 index 00000000000..5841c6cdcef Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_lock3.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_upload.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_upload.png new file mode 100644 index 00000000000..04c63878fee Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_upload.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_premium_translate.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_premium_translate.png new file mode 100644 index 00000000000..cf3aa07034b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_premium_translate.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_smile_status.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_smile_status.png new file mode 100644 index 00000000000..92e38f86552 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_smile_status.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_channel_create.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_channel_create.png new file mode 100644 index 00000000000..fa7ce4bd0ef Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_channel_create.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_download_settings.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_download_settings.png new file mode 100644 index 00000000000..ef6e38bc2fa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_download_settings.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_activities.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_activities.png index e8ee8cc00d8..01e2fc92f61 100644 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_activities.png and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_activities.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_angry.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_angry.png new file mode 100644 index 00000000000..b52eb874351 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_angry.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_back.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_back.png new file mode 100644 index 00000000000..ff83f9ecd9d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_back.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_bath.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_bath.png new file mode 100644 index 00000000000..1fc7a789af6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_bath.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_busy.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_busy.png new file mode 100644 index 00000000000..ce81d1660b4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_busy.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_dislike.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_dislike.png new file mode 100644 index 00000000000..c39d4f25ed2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_dislike.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_food.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_food.png index ef4160eb104..87e80205c92 100644 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_food.png and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_food.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_happy.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_happy.png new file mode 100644 index 00000000000..d26de4e123c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_happy.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_hi.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_hi.png new file mode 100644 index 00000000000..757bf58be8a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_hi.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_home.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_home.png new file mode 100644 index 00000000000..9ade49edccd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_home.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_like.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_like.png new file mode 100644 index 00000000000..822456fb2bc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_like.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_love.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_love.png new file mode 100644 index 00000000000..b19cf84b352 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_love.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_neutral.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_neutral.png new file mode 100644 index 00000000000..1eb5f6deab0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_neutral.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_omg.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_omg.png new file mode 100644 index 00000000000..e479479dfba Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_omg.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_party.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_party.png new file mode 100644 index 00000000000..f379037df40 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_party.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_person.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_person.png new file mode 100644 index 00000000000..1bbba0f1464 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_person.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_sad.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_sad.png new file mode 100644 index 00000000000..e01f1a23a9f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_sad.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_sleep.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_sleep.png new file mode 100644 index 00000000000..44f0e06c9fd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_sleep.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_stickers.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_stickers.png new file mode 100644 index 00000000000..3448ec98f9b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_stickers.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_study.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_study.png new file mode 100644 index 00000000000..61d149d9697 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_study.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_tongue.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_tongue.png new file mode 100644 index 00000000000..3205f4899e9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_tongue.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_vacation.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_vacation.png new file mode 100644 index 00000000000..29484185426 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_vacation.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_what.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_what.png new file mode 100644 index 00000000000..69ddda9e590 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_what.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_work.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_work.png new file mode 100644 index 00000000000..8c595cbbe9a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_emoji_work.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_autodelete.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_autodelete.png new file mode 100644 index 00000000000..9cf64dfd842 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_autodelete.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_blocked.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_blocked.png new file mode 100644 index 00000000000..6fb2d134ede Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_blocked.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_calls.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_calls.png new file mode 100644 index 00000000000..b40ae41fc56 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_calls.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_files.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_files.png new file mode 100644 index 00000000000..080957bf7b0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_files.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_messages.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_messages.png new file mode 100644 index 00000000000..4d93c6d59e5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_messages.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_music.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_music.png new file mode 100644 index 00000000000..3fc0deb165e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_music.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_photos.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_photos.png new file mode 100644 index 00000000000..3f4d9047abd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_photos.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_received.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_received.png new file mode 100644 index 00000000000..4e63b498fd6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_received.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_sent.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_sent.png new file mode 100644 index 00000000000..82c42418724 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_sent.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_videos.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_videos.png new file mode 100644 index 00000000000..267fcd8c7e1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_videos.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_voice.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_voice.png new file mode 100644 index 00000000000..eddf2ee2d63 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_data_voice.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_datausage.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_datausage.png new file mode 100644 index 00000000000..535b001b111 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_datausage.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_devices.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_devices.png new file mode 100644 index 00000000000..3e75039f5b2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_devices.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_email.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_email.png new file mode 100644 index 00000000000..75a5a602423 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_email.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_passcode_off.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_passcode_off.png new file mode 100644 index 00000000000..a1eaa2dd54b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_passcode_off.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_passcode_on.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_passcode_on.png new file mode 100644 index 00000000000..a1fab57e59a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_passcode_on.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_permissions.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_permissions.png new file mode 100644 index 00000000000..51324af25d9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_permissions.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_plus.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_plus.png new file mode 100644 index 00000000000..4421cc02f44 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_plus.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_sdcard.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_sdcard.png new file mode 100644 index 00000000000..58f8ad0d7c8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_sdcard.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_storageusage.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_storageusage.png new file mode 100644 index 00000000000..02e13ac4825 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_filled_storageusage.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_download.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_download.png new file mode 100644 index 00000000000..2c059a820f9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_download.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_lock3.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_lock3.png new file mode 100644 index 00000000000..324436938a7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_lock3.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_upload.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_upload.png new file mode 100644 index 00000000000..34cad727e3e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_upload.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_premium_translate.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_premium_translate.png new file mode 100644 index 00000000000..6618705e206 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_premium_translate.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_smile_status.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_smile_status.png new file mode 100644 index 00000000000..132a443bb73 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_smile_status.png differ diff --git a/TMessagesProj/src/main/res/raw/msg_translate.json b/TMessagesProj/src/main/res/raw/msg_translate.json new file mode 100644 index 00000000000..f6be1fc8472 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/msg_translate.json @@ -0,0 +1 @@ +{"v":"5.10.1","fr":60,"ip":0,"op":180,"w":512,"h":512,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"ee Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.693]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[-45]},{"i":{"x":[0.833],"y":[0.86]},"o":{"x":[0.167],"y":[0.114]},"t":1,"s":[-43.325]},{"i":{"x":[0.833],"y":[0.721]},"o":{"x":[0.167],"y":[0.206]},"t":2,"s":[-38.834]},{"i":{"x":[0.833],"y":[0.824]},"o":{"x":[0.167],"y":[0.119]},"t":3,"s":[-35.792]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.159]},"t":4,"s":[-28.638]},{"i":{"x":[0.833],"y":[0.877]},"o":{"x":[0.167],"y":[0.166]},"t":5,"s":[-20.719]},{"i":{"x":[0.833],"y":[0.764]},"o":{"x":[0.167],"y":[0.257]},"t":6,"s":[-12.743]},{"i":{"x":[0.833],"y":[0.88]},"o":{"x":[0.167],"y":[0.129]},"t":7,"s":[-8.922]},{"i":{"x":[0.833],"y":[0.776]},"o":{"x":[0.167],"y":[0.272]},"t":8,"s":[-1.912]},{"i":{"x":[0.833],"y":[0.856]},"o":{"x":[0.167],"y":[0.133]},"t":9,"s":[1.185]},{"i":{"x":[0.833],"y":[0.887]},"o":{"x":[0.167],"y":[0.197]},"t":10,"s":[6.404]},{"i":{"x":[0.833],"y":[0.813]},"o":{"x":[0.167],"y":[0.316]},"t":11,"s":[10.216]},{"i":{"x":[0.833],"y":[0.895]},"o":{"x":[0.167],"y":[0.15]},"t":12,"s":[11.584]},{"i":{"x":[0.833],"y":[0.955]},"o":{"x":[0.167],"y":[0.409]},"t":13,"s":[13.283]},{"i":{"x":[0.833],"y":[0.461]},"o":{"x":[0.167],"y":[-0.1]},"t":14,"s":[13.717]},{"i":{"x":[0.833],"y":[0.779]},"o":{"x":[0.167],"y":[0.099]},"t":15,"s":[13.52]},{"i":{"x":[0.833],"y":[0.866]},"o":{"x":[0.167],"y":[0.134]},"t":16,"s":[12.442]},{"i":{"x":[0.833],"y":[0.734]},"o":{"x":[0.167],"y":[0.222]},"t":17,"s":[10.663]},{"i":{"x":[0.833],"y":[0.83]},"o":{"x":[0.167],"y":[0.121]},"t":18,"s":[9.591]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.163]},"t":19,"s":[7.236]},{"i":{"x":[0.833],"y":[0.761]},"o":{"x":[0.167],"y":[0.254]},"t":20,"s":[4.787]},{"i":{"x":[0.833],"y":[0.845]},"o":{"x":[0.167],"y":[0.128]},"t":21,"s":[3.589]},{"i":{"x":[0.833],"y":[0.881]},"o":{"x":[0.167],"y":[0.18]},"t":22,"s":[1.348]},{"i":{"x":[0.833],"y":[0.782]},"o":{"x":[0.167],"y":[0.279]},"t":23,"s":[-0.584]},{"i":{"x":[0.833],"y":[0.861]},"o":{"x":[0.167],"y":[0.135]},"t":24,"s":[-1.406]},{"i":{"x":[0.833],"y":[0.89]},"o":{"x":[0.167],"y":[0.208]},"t":25,"s":[-2.732]},{"i":{"x":[0.833],"y":[0.837]},"o":{"x":[0.167],"y":[0.344]},"t":26,"s":[-3.621]},{"i":{"x":[0.833],"y":[0.941]},"o":{"x":[0.167],"y":[0.171]},"t":27,"s":[-3.905]},{"i":{"x":[0.833],"y":[0.759]},"o":{"x":[0.167],"y":[-0.201]},"t":28,"s":[-4.176]},{"i":{"x":[0.833],"y":[0.654]},"o":{"x":[0.167],"y":[0.127]},"t":29,"s":[-4.097]},{"i":{"x":[0.833],"y":[0.804]},"o":{"x":[0.167],"y":[0.11]},"t":30,"s":[-3.947]},{"i":{"x":[0.833],"y":[0.87]},"o":{"x":[0.167],"y":[0.145]},"t":31,"s":[-3.475]},{"i":{"x":[0.833],"y":[0.743]},"o":{"x":[0.167],"y":[0.232]},"t":32,"s":[-2.839]},{"i":{"x":[0.833],"y":[0.834]},"o":{"x":[0.167],"y":[0.123]},"t":33,"s":[-2.483]},{"i":{"x":[0.833],"y":[0.877]},"o":{"x":[0.167],"y":[0.168]},"t":34,"s":[-1.739]},{"i":{"x":[0.833],"y":[0.766]},"o":{"x":[0.167],"y":[0.26]},"t":35,"s":[-1.005]},{"i":{"x":[0.833],"y":[0.848]},"o":{"x":[0.167],"y":[0.129]},"t":36,"s":[-0.658]},{"i":{"x":[0.833],"y":[0.883]},"o":{"x":[0.167],"y":[0.185]},"t":37,"s":[-0.029]},{"i":{"x":[0.833],"y":[0.79]},"o":{"x":[0.167],"y":[0.288]},"t":38,"s":[0.487]},{"i":{"x":[0.833],"y":[0.867]},"o":{"x":[0.167],"y":[0.138]},"t":39,"s":[0.698]},{"i":{"x":[0.833],"y":[0.895]},"o":{"x":[0.167],"y":[0.225]},"t":40,"s":[1.019]},{"i":{"x":[0.833],"y":[0.893]},"o":{"x":[0.167],"y":[0.41]},"t":41,"s":[1.208]},{"i":{"x":[0.833],"y":[1.414]},"o":{"x":[0.167],"y":[0.382]},"t":42,"s":[1.256]},{"i":{"x":[0.833],"y":[0.846]},"o":{"x":[0.167],"y":[0.069]},"t":43,"s":[1.27]},{"i":{"x":[0.833],"y":[0.7]},"o":{"x":[0.167],"y":[0.181]},"t":44,"s":[1.189]},{"i":{"x":[0.833],"y":[0.817]},"o":{"x":[0.167],"y":[0.115]},"t":45,"s":[1.121]},{"i":{"x":[0.833],"y":[0.872]},"o":{"x":[0.167],"y":[0.153]},"t":46,"s":[0.943]},{"i":{"x":[0.833],"y":[0.75]},"o":{"x":[0.167],"y":[0.241]},"t":47,"s":[0.729]},{"i":{"x":[0.833],"y":[0.838]},"o":{"x":[0.167],"y":[0.125]},"t":48,"s":[0.616]},{"i":{"x":[0.833],"y":[0.879]},"o":{"x":[0.167],"y":[0.172]},"t":49,"s":[0.389]},{"i":{"x":[0.833],"y":[0.771]},"o":{"x":[0.167],"y":[0.266]},"t":50,"s":[0.175]},{"i":{"x":[0.833],"y":[0.852]},"o":{"x":[0.167],"y":[0.131]},"t":51,"s":[0.077]},{"i":{"x":[0.833],"y":[0.884]},"o":{"x":[0.167],"y":[0.19]},"t":52,"s":[-0.094]},{"i":{"x":[0.833],"y":[0.799]},"o":{"x":[0.167],"y":[0.299]},"t":53,"s":[-0.227]},{"i":{"x":[0.833],"y":[0.878]},"o":{"x":[0.167],"y":[0.142]},"t":54,"s":[-0.279]},{"i":{"x":[0.833],"y":[0.907]},"o":{"x":[0.167],"y":[0.261]},"t":55,"s":[-0.351]},{"i":{"x":[0.833],"y":[1.224]},"o":{"x":[0.167],"y":[0.8]},"t":56,"s":[-0.386]},{"i":{"x":[0.833],"y":[0.694]},"o":{"x":[0.167],"y":[0.061]},"t":57,"s":[-0.389]},{"i":{"x":[0.833],"y":[0.86]},"o":{"x":[0.167],"y":[0.115]},"t":58,"s":[-0.375]},{"i":{"x":[0.833],"y":[0.721]},"o":{"x":[0.167],"y":[0.206]},"t":59,"s":[-0.336]},{"i":{"x":[0.833],"y":[0.824]},"o":{"x":[0.167],"y":[0.119]},"t":60,"s":[-0.31]},{"i":{"x":[0.833],"y":[0.874]},"o":{"x":[0.167],"y":[0.159]},"t":61,"s":[-0.248]},{"i":{"x":[0.833],"y":[0.756]},"o":{"x":[0.167],"y":[0.248]},"t":62,"s":[-0.179]},{"i":{"x":[0.833],"y":[0.842]},"o":{"x":[0.167],"y":[0.126]},"t":63,"s":[-0.144]},{"i":{"x":[0.833],"y":[0.88]},"o":{"x":[0.167],"y":[0.176]},"t":64,"s":[-0.077]},{"i":{"x":[0.833],"y":[0.776]},"o":{"x":[0.167],"y":[0.272]},"t":65,"s":[-0.016]},{"i":{"x":[0.833],"y":[0.856]},"o":{"x":[0.167],"y":[0.133]},"t":66,"s":[0.01]},{"i":{"x":[0.833],"y":[0.887]},"o":{"x":[0.167],"y":[0.197]},"t":67,"s":[0.056]},{"i":{"x":[0.833],"y":[0.813]},"o":{"x":[0.167],"y":[0.316]},"t":68,"s":[0.089]},{"i":{"x":[0.833],"y":[0.896]},"o":{"x":[0.167],"y":[0.15]},"t":69,"s":[0.1]},{"i":{"x":[0.833],"y":[0.955]},"o":{"x":[0.167],"y":[0.412]},"t":70,"s":[0.115]},{"i":{"x":[0.833],"y":[0.464]},"o":{"x":[0.167],"y":[-0.097]},"t":71,"s":[0.119]},{"i":{"x":[0.833],"y":[0.779]},"o":{"x":[0.167],"y":[0.099]},"t":72,"s":[0.117]},{"i":{"x":[0.833],"y":[0.866]},"o":{"x":[0.167],"y":[0.134]},"t":73,"s":[0.108]},{"i":{"x":[0.833],"y":[0.734]},"o":{"x":[0.167],"y":[0.222]},"t":74,"s":[0.092]},{"i":{"x":[0.833],"y":[0.83]},"o":{"x":[0.167],"y":[0.121]},"t":75,"s":[0.083]},{"i":{"x":[0.833],"y":[0.876]},"o":{"x":[0.167],"y":[0.163]},"t":76,"s":[0.063]},{"i":{"x":[0.833],"y":[0.761]},"o":{"x":[0.167],"y":[0.254]},"t":77,"s":[0.041]},{"i":{"x":[0.833],"y":[0.845]},"o":{"x":[0.167],"y":[0.128]},"t":78,"s":[0.031]},{"i":{"x":[0.833],"y":[0.881]},"o":{"x":[0.167],"y":[0.18]},"t":79,"s":[0.012]},{"i":{"x":[0.833],"y":[0.782]},"o":{"x":[0.167],"y":[0.279]},"t":80,"s":[-0.005]},{"i":{"x":[0.833],"y":[0.861]},"o":{"x":[0.167],"y":[0.135]},"t":81,"s":[-0.012]},{"i":{"x":[0.833],"y":[0.89]},"o":{"x":[0.167],"y":[0.208]},"t":82,"s":[-0.024]},{"i":{"x":[0.833],"y":[0.837]},"o":{"x":[0.167],"y":[0.344]},"t":83,"s":[-0.031]},{"i":{"x":[0.833],"y":[0.942]},"o":{"x":[0.167],"y":[0.171]},"t":84,"s":[-0.034]},{"i":{"x":[0.833],"y":[0.761]},"o":{"x":[0.167],"y":[-0.196]},"t":85,"s":[-0.036]},{"i":{"x":[0.833],"y":[0.654]},"o":{"x":[0.167],"y":[0.128]},"t":86,"s":[-0.035]},{"i":{"x":[0.833],"y":[0.804]},"o":{"x":[0.167],"y":[0.11]},"t":87,"s":[-0.034]},{"i":{"x":[0.833],"y":[0.87]},"o":{"x":[0.167],"y":[0.145]},"t":88,"s":[-0.03]},{"i":{"x":[0.833],"y":[0.743]},"o":{"x":[0.167],"y":[0.232]},"t":89,"s":[-0.025]},{"i":{"x":[0.833],"y":[0.834]},"o":{"x":[0.167],"y":[0.123]},"t":90,"s":[-0.021]},{"i":{"x":[0.833],"y":[0.877]},"o":{"x":[0.167],"y":[0.168]},"t":91,"s":[-0.015]},{"i":{"x":[0.833],"y":[0.766]},"o":{"x":[0.167],"y":[0.26]},"t":92,"s":[-0.009]},{"i":{"x":[0.833],"y":[0.848]},"o":{"x":[0.167],"y":[0.129]},"t":93,"s":[-0.006]},{"i":{"x":[0.833],"y":[0.883]},"o":{"x":[0.167],"y":[0.185]},"t":94,"s":[0]},{"i":{"x":[0.833],"y":[0.79]},"o":{"x":[0.167],"y":[0.288]},"t":95,"s":[0.004]},{"i":{"x":[0.833],"y":[0.868]},"o":{"x":[0.167],"y":[0.138]},"t":96,"s":[0.006]},{"i":{"x":[0.833],"y":[0.895]},"o":{"x":[0.167],"y":[0.225]},"t":97,"s":[0.009]},{"i":{"x":[0.833],"y":[0.894]},"o":{"x":[0.167],"y":[0.411]},"t":98,"s":[0.01]},{"i":{"x":[0.833],"y":[1.43]},"o":{"x":[0.167],"y":[0.389]},"t":99,"s":[0.011]},{"i":{"x":[0.833],"y":[0.846]},"o":{"x":[0.167],"y":[0.07]},"t":100,"s":[0.011]},{"i":{"x":[0.833],"y":[0.7]},"o":{"x":[0.167],"y":[0.182]},"t":101,"s":[0.01]},{"i":{"x":[0.833],"y":[0.817]},"o":{"x":[0.167],"y":[0.115]},"t":102,"s":[0.01]},{"i":{"x":[0.833],"y":[0.873]},"o":{"x":[0.167],"y":[0.153]},"t":103,"s":[0.008]},{"i":{"x":[0.833],"y":[0.75]},"o":{"x":[0.167],"y":[0.241]},"t":104,"s":[0.006]},{"i":{"x":[0.833],"y":[0.838]},"o":{"x":[0.167],"y":[0.125]},"t":105,"s":[0.005]},{"i":{"x":[0.833],"y":[0.879]},"o":{"x":[0.167],"y":[0.172]},"t":106,"s":[0.003]},{"i":{"x":[0.833],"y":[0.771]},"o":{"x":[0.167],"y":[0.266]},"t":107,"s":[0.002]},{"i":{"x":[0.833],"y":[0.852]},"o":{"x":[0.167],"y":[0.131]},"t":108,"s":[0.001]},{"i":{"x":[0.833],"y":[0.884]},"o":{"x":[0.167],"y":[0.19]},"t":109,"s":[-0.001]},{"i":{"x":[0.833],"y":[0.799]},"o":{"x":[0.167],"y":[0.299]},"t":110,"s":[-0.002]},{"i":{"x":[0.833],"y":[0.878]},"o":{"x":[0.167],"y":[0.142]},"t":111,"s":[-0.002]},{"i":{"x":[0.833],"y":[0.907]},"o":{"x":[0.167],"y":[0.261]},"t":112,"s":[-0.003]},{"i":{"x":[0.833],"y":[1.23]},"o":{"x":[0.167],"y":[0.808]},"t":113,"s":[-0.003]},{"i":{"x":[0.833],"y":[0.695]},"o":{"x":[0.167],"y":[0.061]},"t":114,"s":[-0.003]},{"i":{"x":[0.833],"y":[0.86]},"o":{"x":[0.167],"y":[0.115]},"t":115,"s":[-0.003]},{"i":{"x":[0.833],"y":[0.721]},"o":{"x":[0.167],"y":[0.207]},"t":116,"s":[-0.003]},{"i":{"x":[0.833],"y":[0.824]},"o":{"x":[0.167],"y":[0.119]},"t":117,"s":[-0.003]},{"i":{"x":[0.833],"y":[0.874]},"o":{"x":[0.167],"y":[0.159]},"t":118,"s":[-0.002]},{"i":{"x":[0.833],"y":[0.756]},"o":{"x":[0.167],"y":[0.248]},"t":119,"s":[-0.002]},{"i":{"x":[0.833],"y":[0.842]},"o":{"x":[0.167],"y":[0.126]},"t":120,"s":[-0.001]},{"i":{"x":[0.833],"y":[0.88]},"o":{"x":[0.167],"y":[0.176]},"t":121,"s":[-0.001]},{"i":{"x":[0.833],"y":[0.776]},"o":{"x":[0.167],"y":[0.272]},"t":122,"s":[0]},{"i":{"x":[0.833],"y":[0.856]},"o":{"x":[0.167],"y":[0.133]},"t":123,"s":[0]},{"i":{"x":[0.833],"y":[0.865]},"o":{"x":[0.167],"y":[0.198]},"t":124,"s":[0]},{"i":{"x":[0.833],"y":[0.893]},"o":{"x":[0.167],"y":[0.217]},"t":125,"s":[0.001]},{"i":{"x":[0.833],"y":[0.864]},"o":{"x":[0.167],"y":[0.376]},"t":126,"s":[0.001]},{"i":{"x":[0.833],"y":[1.042]},"o":{"x":[0.167],"y":[0.216]},"t":127,"s":[0.001]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.028]},"t":128,"s":[0.001]},{"i":{"x":[0.833],"y":[0.686]},"o":{"x":[0.167],"y":[0.166]},"t":129,"s":[0.001]},{"i":{"x":[0.833],"y":[0.813]},"o":{"x":[0.167],"y":[0.113]},"t":130,"s":[0.001]},{"i":{"x":[0.833],"y":[0.872]},"o":{"x":[0.167],"y":[0.15]},"t":131,"s":[0.001]},{"i":{"x":[0.833],"y":[0.747]},"o":{"x":[0.167],"y":[0.238]},"t":132,"s":[0.001]},{"i":{"x":[0.833],"y":[0.837]},"o":{"x":[0.167],"y":[0.124]},"t":133,"s":[0.001]},{"i":{"x":[0.833],"y":[0.878]},"o":{"x":[0.167],"y":[0.17]},"t":134,"s":[0]},{"i":{"x":[0.833],"y":[0.769]},"o":{"x":[0.167],"y":[0.263]},"t":135,"s":[0]},{"i":{"x":[0.833],"y":[0.85]},"o":{"x":[0.167],"y":[0.13]},"t":136,"s":[0]},{"i":{"x":[0.833],"y":[0.884]},"o":{"x":[0.167],"y":[0.188]},"t":137,"s":[0]},{"i":{"x":[0.833],"y":[0.795]},"o":{"x":[0.167],"y":[0.294]},"t":138,"s":[0]},{"i":{"x":[0.833],"y":[0.873]},"o":{"x":[0.167],"y":[0.14]},"t":139,"s":[0]},{"i":{"x":[0.833],"y":[0.901]},"o":{"x":[0.167],"y":[0.242]},"t":140,"s":[0]},{"i":{"x":[0.833],"y":[0.995]},"o":{"x":[0.167],"y":[0.531]},"t":141,"s":[0]},{"i":{"x":[0.833],"y":[0.547]},"o":{"x":[0.167],"y":[-0.005]},"t":142,"s":[0]},{"i":{"x":[0.833],"y":[0.856]},"o":{"x":[0.167],"y":[0.102]},"t":143,"s":[0]},{"i":{"x":[0.833],"y":[0.714]},"o":{"x":[0.167],"y":[0.198]},"t":144,"s":[0]},{"i":{"x":[0.833],"y":[0.822]},"o":{"x":[0.167],"y":[0.118]},"t":145,"s":[0]},{"i":{"x":[0.833],"y":[0.874]},"o":{"x":[0.167],"y":[0.156]},"t":146,"s":[0]},{"i":{"x":[0.833],"y":[0.753]},"o":{"x":[0.167],"y":[0.245]},"t":147,"s":[0]},{"i":{"x":[0.833],"y":[0.84]},"o":{"x":[0.167],"y":[0.126]},"t":148,"s":[0]},{"i":{"x":[0.833],"y":[0.879]},"o":{"x":[0.167],"y":[0.174]},"t":149,"s":[0]},{"i":{"x":[0.833],"y":[0.774]},"o":{"x":[0.167],"y":[0.269]},"t":150,"s":[0]},{"i":{"x":[0.833],"y":[0.854]},"o":{"x":[0.167],"y":[0.132]},"t":151,"s":[0]},{"i":{"x":[0.833],"y":[0.886]},"o":{"x":[0.167],"y":[0.194]},"t":152,"s":[0]},{"i":{"x":[0.833],"y":[0.807]},"o":{"x":[0.167],"y":[0.308]},"t":153,"s":[0]},{"i":{"x":[0.833],"y":[0.887]},"o":{"x":[0.167],"y":[0.147]},"t":154,"s":[0]},{"i":{"x":[0.833],"y":[0.925]},"o":{"x":[0.167],"y":[0.317]},"t":155,"s":[0]},{"i":{"x":[0.833],"y":[-0.093]},"o":{"x":[0.167],"y":[-0.755]},"t":156,"s":[0]},{"i":{"x":[0.833],"y":[0.76]},"o":{"x":[0.167],"y":[0.09]},"t":157,"s":[0]},{"i":{"x":[0.833],"y":[0.865]},"o":{"x":[0.167],"y":[0.128]},"t":158,"s":[0]},{"i":{"x":[0.833],"y":[0.729]},"o":{"x":[0.167],"y":[0.216]},"t":159,"s":[0]},{"i":{"x":[0.833],"y":[0.828]},"o":{"x":[0.167],"y":[0.12]},"t":160,"s":[0]},{"i":{"x":[0.833],"y":[0.875]},"o":{"x":[0.167],"y":[0.162]},"t":161,"s":[0]},{"i":{"x":[0.833],"y":[0.759]},"o":{"x":[0.167],"y":[0.251]},"t":162,"s":[0]},{"i":{"x":[0.833],"y":[0.844]},"o":{"x":[0.167],"y":[0.127]},"t":163,"s":[0]},{"i":{"x":[0.833],"y":[0.881]},"o":{"x":[0.167],"y":[0.178]},"t":164,"s":[0]},{"i":{"x":[0.833],"y":[0.78]},"o":{"x":[0.167],"y":[0.276]},"t":165,"s":[0]},{"i":{"x":[0.833],"y":[0.859]},"o":{"x":[0.167],"y":[0.134]},"t":166,"s":[0]},{"i":{"x":[0.833],"y":[0.889]},"o":{"x":[0.167],"y":[0.203]},"t":167,"s":[0]},{"i":{"x":[0.833],"y":[0.826]},"o":{"x":[0.167],"y":[0.331]},"t":168,"s":[0]},{"i":{"x":[0.833],"y":[0.917]},"o":{"x":[0.167],"y":[0.16]},"t":169,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":170,"s":[0]},{"i":{"x":[0.833],"y":[0.617]},"o":{"x":[0.167],"y":[0.084]},"t":171,"s":[0]},{"i":{"x":[0.833],"y":[0.797]},"o":{"x":[0.167],"y":[0.107]},"t":172,"s":[0]},{"i":{"x":[0.833],"y":[0.869]},"o":{"x":[0.167],"y":[0.141]},"t":173,"s":[0]},{"i":{"x":[0.833],"y":[0.739]},"o":{"x":[0.167],"y":[0.229]},"t":174,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.123]},"t":175,"s":[0]},{"i":{"x":[0.833],"y":[0.877]},"o":{"x":[0.167],"y":[0.166]},"t":176,"s":[0]},{"i":{"x":[0.833],"y":[0.764]},"o":{"x":[0.167],"y":[0.257]},"t":177,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.129]},"t":178,"s":[0]},{"t":179,"s":[0]}],"ix":10},"p":{"a":0,"k":[256,256,0],"ix":2,"l":2},"a":{"a":0,"k":[45,45,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":0,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":1,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":2,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":3,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":4,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":5,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":6,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":7,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.759,0.759,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":8,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.306,0.306,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.083,0.083,0]},"t":9,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.85,0.85,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.095,0.095,0]},"t":10,"s":[502.898,502.898,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.705,0.705,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.188,0.188,0]},"t":11,"s":[524.133,524.133,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.818,0.818,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.116,0.116,0]},"t":12,"s":[541.109,541.109,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.878,0.878,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.154,0.154,0]},"t":13,"s":[584.273,584.273,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.805,0.805,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.261,0.261,0]},"t":14,"s":[635.15,635.15,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.884,0.884,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.145,0.145,0]},"t":15,"s":[658.975,658.975,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.919,0.919,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.298,0.298,0]},"t":16,"s":[690.914,690.914,100]},{"i":{"x":[0.833,0.833,0.833],"y":[-2.003,-2.003,1]},"o":{"x":[0.167,0.167,0.167],"y":[-3.01,-3.01,0]},"t":17,"s":[703.312,703.312,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.75,0.75,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.086,0.086,0]},"t":18,"s":[702.978,702.978,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.864,0.864,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.125,0.125,0]},"t":19,"s":[691.278,691.278,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.727,0.727,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.214,0.214,0]},"t":20,"s":[667.922,667.922,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.827,0.827,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.12,0.12,0]},"t":21,"s":[653.061,653.061,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.875,0.875,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.161,0.161,0]},"t":22,"s":[619.309,619.309,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.758,0.758,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.25,0.25,0]},"t":23,"s":[583.081,583.081,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.843,0.843,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.127,0.127,0]},"t":24,"s":[565.017,565.017,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.88,0.88,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.178,0.178,0]},"t":25,"s":[530.628,530.628,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.779,0.779,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.275,0.275,0]},"t":26,"s":[500.267,500.267,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.858,0.858,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.134,0.134,0]},"t":27,"s":[487.078,487.078,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.888,0.888,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.202,0.202,0]},"t":28,"s":[465.281,465.281,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.823,0.823,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.327,0.327,0]},"t":29,"s":[449.937,449.937,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.91,0.91,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.157,0.157,0]},"t":30,"s":[444.682,444.682,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1.205,1.205,1]},"o":{"x":[0.167,0.167,0.167],"y":[1.193,1.193,0]},"t":31,"s":[438.75,438.75,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.596,0.596,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.059,0.059,0]},"t":32,"s":[438.304,438.304,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.794,0.794,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.105,0.105,0]},"t":33,"s":[439.846,439.846,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.868,0.868,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.14,0.14,0]},"t":34,"s":[445.774,445.774,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.738,0.738,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.227,0.227,0]},"t":35,"s":[454.534,454.534,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.832,0.832,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.122,0.122,0]},"t":36,"s":[459.615,459.615,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.877,0.877,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.166,0.166,0]},"t":37,"s":[470.5,470.5,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.763,0.763,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.257,0.257,0]},"t":38,"s":[481.537,481.537,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.846,0.846,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.129,0.129,0]},"t":39,"s":[486.847,486.847,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.882,0.882,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.182,0.182,0]},"t":40,"s":[496.631,496.631,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.786,0.786,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.283,0.283,0]},"t":41,"s":[504.883,504.883,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.864,0.864,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.136,0.136,0]},"t":42,"s":[508.329,508.329,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.892,0.892,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.214,0.214,0]},"t":43,"s":[513.751,513.751,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.857,0.857,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.367,0.367,0]},"t":44,"s":[517.201,517.201,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1.004,1.004,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.199,0.199,0]},"t":45,"s":[518.214,518.214,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.825,0.825,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.004,0.004,0]},"t":46,"s":[518.946,518.946,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.681,0.681,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.159,0.159,0]},"t":47,"s":[518.18,518.18,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.811,0.811,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.113,0.113,0]},"t":48,"s":[517.336,517.336,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.871,0.871,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.149,0.149,0]},"t":49,"s":[514.946,514.946,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.746,0.746,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.236,0.236,0]},"t":50,"s":[511.912,511.912,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.836,0.836,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.124,0.124,0]},"t":51,"s":[510.26,510.26,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.878,0.878,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.17,0.17,0]},"t":52,"s":[506.879,506.879,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.768,0.768,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.262,0.262,0]},"t":53,"s":[503.615,503.615,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.85,0.85,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.13,0.13,0]},"t":54,"s":[502.096,502.096,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.883,0.883,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.187,0.187,0]},"t":55,"s":[499.39,499.39,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.794,0.794,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.293,0.293,0]},"t":56,"s":[497.218,497.218,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.872,0.872,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.14,0.14,0]},"t":57,"s":[496.354,496.354,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.9,0.9,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.237,0.237,0]},"t":58,"s":[495.078,495.078,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.96,0.96,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.489,0.489,0]},"t":59,"s":[494.388,494.388,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.386,0.386,1]},"o":{"x":[0.167,0.167,0.167],"y":[-0.077,-0.077,0]},"t":60,"s":[494.246,494.246,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.854,0.854,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.096,0.096,0]},"t":61,"s":[494.32,494.32,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.711,0.711,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.195,0.195,0]},"t":62,"s":[494.79,494.79,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.821,0.821,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.117,0.117,0]},"t":63,"s":[495.14,495.14,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.873,0.873,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.156,0.156,0]},"t":64,"s":[496.004,496.004,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.752,0.752,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.244,0.244,0]},"t":65,"s":[497,497,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.84,0.84,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.126,0.126,0]},"t":66,"s":[497.516,497.516,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.879,0.879,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.174,0.174,0]},"t":67,"s":[498.534,498.534,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.773,0.773,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.269,0.269,0]},"t":68,"s":[499.472,499.472,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.854,0.854,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.132,0.132,0]},"t":69,"s":[499.895,499.895,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.885,0.885,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.193,0.193,0]},"t":70,"s":[500.621,500.621,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.805,0.805,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.306,0.306,0]},"t":71,"s":[501.171,501.171,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.884,0.884,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.146,0.146,0]},"t":72,"s":[501.377,501.377,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.919,0.919,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.299,0.299,0]},"t":73,"s":[501.653,501.653,100]},{"i":{"x":[0.833,0.833,0.833],"y":[-1.781,-1.781,1]},"o":{"x":[0.167,0.167,0.167],"y":[-2.749,-2.749,0]},"t":74,"s":[501.76,501.76,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.751,0.751,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.086,0.086,0]},"t":75,"s":[501.757,501.757,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.864,0.864,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.125,0.125,0]},"t":76,"s":[501.655,501.655,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.727,0.727,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.214,0.214,0]},"t":77,"s":[501.452,501.452,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.827,0.827,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.12,0.12,0]},"t":78,"s":[501.324,501.324,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.875,0.875,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.161,0.161,0]},"t":79,"s":[501.031,501.031,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.758,0.758,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.25,0.25,0]},"t":80,"s":[500.718,500.718,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.843,0.843,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.127,0.127,0]},"t":81,"s":[500.562,500.562,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.88,0.88,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.178,0.178,0]},"t":82,"s":[500.264,500.264,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.779,0.779,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.275,0.275,0]},"t":83,"s":[500.001,500.001,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.858,0.858,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.134,0.134,0]},"t":84,"s":[499.887,499.887,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.888,0.888,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.202,0.202,0]},"t":85,"s":[499.699,499.699,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.823,0.823,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.327,0.327,0]},"t":86,"s":[499.566,499.566,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.911,0.911,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.157,0.157,0]},"t":87,"s":[499.521,499.521,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1.219,1.219,1]},"o":{"x":[0.167,0.167,0.167],"y":[1.236,1.236,0]},"t":88,"s":[499.47,499.47,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.597,0.597,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.06,0.06,0]},"t":89,"s":[499.466,499.466,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.794,0.794,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.105,0.105,0]},"t":90,"s":[499.48,499.48,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.868,0.868,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.14,0.14,0]},"t":91,"s":[499.531,499.531,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.738,0.738,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.227,0.227,0]},"t":92,"s":[499.607,499.607,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.832,0.832,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.122,0.122,0]},"t":93,"s":[499.651,499.651,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.877,0.877,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.166,0.166,0]},"t":94,"s":[499.745,499.745,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.763,0.763,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.257,0.257,0]},"t":95,"s":[499.841,499.841,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.846,0.846,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.129,0.129,0]},"t":96,"s":[499.886,499.886,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.882,0.882,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.182,0.182,0]},"t":97,"s":[499.971,499.971,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.786,0.786,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.283,0.283,0]},"t":98,"s":[500.042,500.042,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.864,0.864,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.136,0.136,0]},"t":99,"s":[500.072,500.072,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.892,0.892,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.214,0.214,0]},"t":100,"s":[500.119,500.119,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.857,0.857,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.367,0.367,0]},"t":101,"s":[500.149,500.149,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1.005,1.005,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.199,0.199,0]},"t":102,"s":[500.158,500.158,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.825,0.825,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.005,0.005,0]},"t":103,"s":[500.164,500.164,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.681,0.681,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.159,0.159,0]},"t":104,"s":[500.157,500.157,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.811,0.811,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.113,0.113,0]},"t":105,"s":[500.15,500.15,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.871,0.871,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.149,0.149,0]},"t":106,"s":[500.129,500.129,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.746,0.746,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.236,0.236,0]},"t":107,"s":[500.103,500.103,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.836,0.836,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.124,0.124,0]},"t":108,"s":[500.089,500.089,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.878,0.878,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.17,0.17,0]},"t":109,"s":[500.059,500.059,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.768,0.768,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.262,0.262,0]},"t":110,"s":[500.031,500.031,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.85,0.85,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.13,0.13,0]},"t":111,"s":[500.018,500.018,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.883,0.883,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.187,0.187,0]},"t":112,"s":[499.995,499.995,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.794,0.794,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.293,0.293,0]},"t":113,"s":[499.976,499.976,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.872,0.872,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.14,0.14,0]},"t":114,"s":[499.968,499.968,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.9,0.9,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.238,0.238,0]},"t":115,"s":[499.957,499.957,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.961,0.961,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.49,0.49,0]},"t":116,"s":[499.951,499.951,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.396,0.396,1]},"o":{"x":[0.167,0.167,0.167],"y":[-0.072,-0.072,0]},"t":117,"s":[499.95,499.95,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.855,0.855,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.097,0.097,0]},"t":118,"s":[499.951,499.951,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.711,0.711,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.195,0.195,0]},"t":119,"s":[499.955,499.955,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.821,0.821,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.117,0.117,0]},"t":120,"s":[499.958,499.958,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.873,0.873,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.156,0.156,0]},"t":121,"s":[499.965,499.965,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.753,0.753,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.244,0.244,0]},"t":122,"s":[499.974,499.974,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.84,0.84,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.126,0.126,0]},"t":123,"s":[499.979,499.979,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.845,0.845,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.174,0.174,0]},"t":124,"s":[499.987,499.987,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.881,0.881,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.18,0.18,0]},"t":125,"s":[499.995,499.995,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.783,0.783,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.28,0.28,0]},"t":126,"s":[500.002,500.002,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.861,0.861,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.135,0.135,0]},"t":127,"s":[500.005,500.005,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.89,0.89,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.209,0.209,0]},"t":128,"s":[500.01,500.01,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.84,0.84,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.347,0.347,0]},"t":129,"s":[500.013,500.013,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.948,0.948,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.174,0.174,0]},"t":130,"s":[500.014,500.014,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.779,0.779,1]},"o":{"x":[0.167,0.167,0.167],"y":[-0.139,-0.139,0]},"t":131,"s":[500.015,500.015,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.659,0.659,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.134,0.134,0]},"t":132,"s":[500.015,500.015,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.805,0.805,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.11,0.11,0]},"t":133,"s":[500.014,500.014,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.87,0.87,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.146,0.146,0]},"t":134,"s":[500.013,500.013,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.743,0.743,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.233,0.233,0]},"t":135,"s":[500.01,500.01,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.835,0.835,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.123,0.123,0]},"t":136,"s":[500.009,500.009,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.877,0.877,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.168,0.168,0]},"t":137,"s":[500.006,500.006,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.766,0.766,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.26,0.26,0]},"t":138,"s":[500.004,500.004,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.848,0.848,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.129,0.129,0]},"t":139,"s":[500.002,500.002,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.883,0.883,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.185,0.185,0]},"t":140,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.79,0.79,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.289,0.289,0]},"t":141,"s":[499.998,499.998,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.868,0.868,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.138,0.138,0]},"t":142,"s":[499.997,499.997,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.896,0.896,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.226,0.226,0]},"t":143,"s":[499.996,499.996,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.901,0.901,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.42,0.42,0]},"t":144,"s":[499.996,499.996,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1.753,1.753,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.533,0.533,0]},"t":145,"s":[499.995,499.995,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.848,0.848,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.075,0.075,0]},"t":146,"s":[499.995,499.995,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.702,0.702,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.184,0.184,0]},"t":147,"s":[499.996,499.996,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.817,0.817,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.116,0.116,0]},"t":148,"s":[499.996,499.996,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.873,0.873,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.153,0.153,0]},"t":149,"s":[499.997,499.997,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.75,0.75,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.241,0.241,0]},"t":150,"s":[499.997,499.997,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.838,0.838,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.125,0.125,0]},"t":151,"s":[499.998,499.998,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.879,0.879,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.172,0.172,0]},"t":152,"s":[499.999,499.999,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.771,0.771,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.266,0.266,0]},"t":153,"s":[499.999,499.999,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.852,0.852,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.131,0.131,0]},"t":154,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.885,0.885,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.191,0.191,0]},"t":155,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.8,0.8,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.3,0.3,0]},"t":156,"s":[500.001,500.001,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.879,0.879,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.143,0.143,0]},"t":157,"s":[500.001,500.001,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.908,0.908,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.265,0.265,0]},"t":158,"s":[500.001,500.001,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1.335,1.335,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.932,0.932,0]},"t":159,"s":[500.001,500.001,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.708,0.708,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.067,0.067,0]},"t":160,"s":[500.001,500.001,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.861,0.861,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.117,0.117,0]},"t":161,"s":[500.001,500.001,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.722,0.722,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.208,0.208,0]},"t":162,"s":[500.001,500.001,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.825,0.825,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.119,0.119,0]},"t":163,"s":[500.001,500.001,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.874,0.874,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.159,0.159,0]},"t":164,"s":[500.001,500.001,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.756,0.756,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.248,0.248,0]},"t":165,"s":[500.001,500.001,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.842,0.842,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.127,0.127,0]},"t":166,"s":[500.001,500.001,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.88,0.88,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.176,0.176,0]},"t":167,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.777,0.777,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.273,0.273,0]},"t":168,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.856,0.856,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.133,0.133,0]},"t":169,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.887,0.887,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.198,0.198,0]},"t":170,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.815,0.815,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.317,0.317,0]},"t":171,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.898,0.898,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.151,0.151,0]},"t":172,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.967,0.967,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.447,0.447,0]},"t":173,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.499,0.499,1]},"o":{"x":[0.167,0.167,0.167],"y":[-0.056,-0.056,0]},"t":174,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.782,0.782,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.1,0.1,0]},"t":175,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.867,0.867,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.135,0.135,0]},"t":176,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.734,0.734,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.223,0.223,0]},"t":177,"s":[500,500,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.121,0.121,0]},"t":178,"s":[500,500,100]},{"t":179,"s":[500,500,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-5.75,14.5],[-0.25,0.5],[5.75,-14.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":12,"s":[100]},{"t":23,"s":[1]}],"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[55.75,55.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[5.75,14.5],[-0.75,-1.5],[-5.75,-14.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":12,"s":[100]},{"t":23,"s":[1]}],"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[67.75,55.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[4.45,5.399],[0,0]],"o":[[0,0],[-4.45,-5.399],[0,0]],"v":[[10.085,11.858],[-1.557,1.119],[-10.085,-11.858]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":9,"s":[50]},{"t":20,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":9,"s":[50]},{"t":20,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[36.008,43.125],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-5.939,7.862],[0,0]],"o":[[0,0],[5.939,-7.862],[0,0]],"v":[[-12.519,16.573],[2.996,1.077],[12.519,-16.573]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[100]},{"t":17,"s":[1]}],"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[35.358,41.319],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[36.1,17.439],[36.1,22.202]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[0]},{"t":14,"s":[100]}],"ix":1},"e":{"a":0,"k":0,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":3,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[16.285,23.302],[55.919,23.302]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":11,"s":[100]}],"ix":1},"e":{"a":0,"k":0,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":3,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[54.051,60.342],[69.3,60.342]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[100]},{"t":26,"s":[1]}],"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":3,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":180,"st":0,"ct":1,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index d8fb6f394a6..cb41bb24fe1 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -221,7 +221,7 @@ Chat archived. Chats archived. Hide the archive by swiping left on it. - UNDO + Undo Delete from cache Delete and exit Hide @@ -235,6 +235,10 @@ Delete chat Deleted Account Select Chat + Choose Bot + Choose User + Choose Group + Choose Channel Select Chats Forward to... My Groups @@ -266,6 +270,12 @@ Wrong layout? Send Sticker Send GIF + Send Emoji + Copy Emoji + Set as Status + Emoji status set. + Remove Status + Emoji status removed. View Pack Pin to top Sorry, you can only pin %1$s to the top in the main list. More chats can be pinned in Chat Folders. @@ -325,6 +335,14 @@ Message unpinned Tap on the pencil to start a new chat Create a New Group to Import + Create a New Channel For This + No such channels + You don\'t have channels that meet the requirements for this bot + Create a New Group For This + No such groups + You don\'t have groups that meet the requirements for this bot + No such users + No users found that meet the requirements for this bot Import Messages Import Error Invalid file format. @@ -606,8 +624,16 @@ What can this user do? Read Messages Send Messages + Send Polls + Send Text Messages Send Media Send Polls + Send Photos + Send Videos + Send Music + Send Files + Send Voice Messages + Send Video Messages Send Stickers & GIFs Embed Links Change Chat Info @@ -615,8 +641,15 @@ Add Users can\'t read can\'t send messages - no media + can\'t send text messages no polls + no media + no photos + no videos + no music + no files + no voice + no round no stickers & GIFs no embed links can\'t change Info @@ -667,6 +700,7 @@ Statistics Add Bot Add bot as admin + Add bot as admin? Add as admin Add bot as Member @@ -1199,21 +1233,43 @@ Are you sure you want to stop recording and discard your video message? Discard The admins of this group have restricted you from sending media here until %1$s + The admins of this group have restricted you from sending audio here until %1$s + The admins of this group have restricted you from sending photo here until %1$s + The admins of this group have restricted you from sending video messages here until %1$s + The admins of this group have restricted you from sending voice messages here until %1$s + The admins of this group have restricted you from sending video here until %1$s + The admins of this group have restricted you from sending documents here until %1$s The admins of this group have restricted you from sending inline content here until %1$s The admins of this group have restricted you from sending stickers here until %1$s The admins of this group have restricted you from sending GIFs here until %1$s + The admins of this group have restricted you from sending text message here until %1$s The admins of this group have restricted you from writing here until %1$s The admins of this group have restricted you from sending media here. + The admins of this group have restricted you from sending audio here. + The admins of this group have restricted you from sending documents here. + The admins of this group have restricted you from sending photo here. + The admins of this group have restricted you from sending video messages here. + The admins of this group have restricted you from sending voice messages here. + The admins of this group have restricted you from sending video here. The admins of this group have restricted you from sending inline content here The admins of this group have restricted you from sending stickers. The admins of this group have restricted you from sending GIFs. + The admins of this group have restricted you from sending text message. The admins of this group have restricted you from writing here. **%1$s** doesn\'t accept voice messages. **%1$s** doesn\'t accept video messages. + Sending plain text isn\'t allowed in this group. + Sending documents isn\'t allowed in this group. Sending media isn\'t allowed in this group. + Sending music isn\'t allowed in this group. + Sending photo isn\'t allowed in this group. + Sending video isn\'t allowed in this group. + Sending voice isn\'t allowed in this group. + Sending round video isn\'t allowed in this group. Inline bots aren\'t allowed in this group. Stickers aren\'t allowed in this group. GIFs aren\'t allowed in this group. + Text message aren\'t allowed in this group. Writing messages isn\'t allowed in this group. Message preview Preview message @@ -1724,6 +1780,11 @@ Add %1$d emoji Add %1$d emoji Add %1$d emoji + Add emoji pack + Add %1$d emoji packs + Add %1$d emoji packs + Add %1$d emoji packs + Add %1$d emoji packs Remove emoji Remove %1$d emoji Remove %1$d emoji @@ -1756,6 +1817,7 @@ More Stickers Delete from Favorites Delete from Recent + Remove from Recent Clear recent stickers Add to Masks Stickers not found @@ -2103,6 +2165,8 @@ Pinned Messages Translate Messages Show Translate Button + Translate Entire Chat + Subscribe to **Telegram Premium** to translate all chat messages at once. Do Not Translate %1$d Languages %1$d Language @@ -2200,6 +2264,10 @@ Voice messages are tiny, so they\'re always downloaded automatically. No media No GIFs + Auto-Download Settings + You can change your auto-download settings for media to reduce data usage when connected via mobile network. + You can change your auto-download settings for media to reduce data usage when connected to Wi-Fi. + You can change your auto-download settings for media to reduce data usage when roaming. Reset Auto-Download Settings Reset settings Are you sure you want to reset auto-download settings? @@ -2456,7 +2524,7 @@ Profile Photos Miscellaneous Photos - Voice/Video messages + Voice messages Videos Music GIFs @@ -3233,6 +3301,7 @@ All media will stay in the Telegram cloud and can be re-downloaded if you need it again. Data Usage Storage Path + All Mobile Wi-Fi Roaming @@ -3241,14 +3310,44 @@ Received Bytes sent Bytes received + Files sent + Files received + **%s** files sent + **%s** file sent + **%s** files sent + **%s** files sent + **%s** files sent + **%s** files sent + **%s** files received + **%s** file received + **%s** files received + **%s** files received + **%s** files received + **%s** files received Files Calls Outgoing calls Incoming calls + %1$d outgoing calls + %1$d outgoing call + %1$d outgoing calls + %1$d outgoing calls + %1$d outgoing calls + %1$d outgoing calls + %1$d incoming calls + %1$d incoming call + %1$d incoming calls + %1$d incoming calls + %1$d incoming calls + %1$d incoming calls Total time Total + Total network usage + Tap on each section for detailed view. Reset Statistics Network usage since %1$s + Your network usage since %1$s + No network usage since %1$s Reset statistics Do you want to reset your usage statistics? @@ -3674,10 +3773,22 @@ Sorry, you can\'t ban this user because they are an admin in this group and you are not allowed to demote them. Sorry, the admins of this group have restricted you from sending stickers. Sorry, the admins of this group have restricted you from sending media. + Sorry, the admins of this group have restricted you from sending photo. + Sorry, the admins of this group have restricted you from sending video. Sorry, the admins of this group have restricted you from sending polls. + Sorry, the admins of this group have restricted you from sending voice messages. + Sorry, the admins of this group have restricted you from sending video messages. + Sorry, the admins of this group have restricted you from sending documents. + Sorry, the admins of this group have restricted you from sending music. Sorry, sending stickers is not allowed in this group. + Sorry, sending photo is not allowed in this group. + Sorry, sending video is not allowed in this group. Sorry, sending media is not allowed in this group. Sorry, sending polls is not allowed in this group. + Sorry, sending voice messages is not allowed in this group. + Sorry, sending video messages is not allowed in this group. + Sorry, sending documents is not allowed in this group. + Sorry, sending music is not allowed in this group. Sorry, you can\'t send voice messages to this user because of their privacy settings. Sorry, you can\'t send video messages to this user because of their privacy settings. Unable to forward @@ -4983,6 +5094,8 @@ More options Switch to night theme Switch to day theme + Close Trending stickers + Close Trending emoji Play Pause Download @@ -5598,6 +5711,9 @@ Animated Profile Pictures Video avatars animated in chat lists and chats to allow for additional self-expression. Subscribe for %s per month + Subscribe for %s per year + Upgrade for %s per year + Upgrade for %s per year Subscribe Subscription not available **Official app needed** @@ -5750,6 +5866,8 @@ Infinite Reactions Emoji Status Add any of thousands emojis next to your name to display current activity. + Real-Time Translation + Real-time translation of channels and chats into other languages. Microphone for voice messages Built-In Headset @@ -5995,6 +6113,10 @@ Set as My Photo Invite To Telegram You allowed this bot to message you when you added it to your attachment menu. + You shared un1 with un2 + You shared a user with un2 + You shared a chat with un2 + You shared a channel with un2 Hide with spoiler Remove spoiler Update Public Photo @@ -6030,7 +6152,7 @@ View Photo View Video Chats - Media + Media Files Music Voice @@ -6049,4 +6171,87 @@ Delete All Proxies Are you sure you want to delete all proxies? Send as %1$s + Review the list of devices where you are logged into your Telegram account. + Photos + Videos + + Music + Files + Voice Messages + Video Messages + Embed Links + Polls + Use an emoji + Auto-switch proxies + You can configure the timeout for connecting to the nearest active proxy if the current one stops working. + %1$d sec. + Requirements + The user should have a Premium subscription. + The user should not have a Premium subscription. + The channel should be public. + The channel should be private. + The group should be public. + The group should be private. + Bot should be in the channel. + Bot should be in the group. + You should be the owner of the channel. + You should not be the owner of the channel. + You should be the owner of the group. + You should not be the owner of the group. + The group should have topics turned on. + The group should have topics turned off. + You should have these admin rights: + You should have admin rights to + Set Channel Photo + Set Group Photo + Photo Editor + Choose background + Send %1$s to %2$s? + Are you sure you want to send **%1$s** to **%2$s**? + This will also add **%1$s** to **%2$s**. + This will also add **%1$s** to **%2$s** with the following rights: %3$s. + Maximum video size + Automatically save all new media from private chats to your phone\'s gallery. + Automatically save all new media from groups to your phone\'s gallery. + Automatically save all new media from channels to your phone\'s gallery. + Automatically save all new media from this chat to your phone\'s gallery. + Photos + Videos + All videos in private chats less than the selected size will be saved to your gallery. + All videos in groups less than the selected size will be saved to your gallery. + All videos in channels less than the selected size will be saved to your gallery. + All videos from this chat less than the selected size will be saved to your gallery. + Add Exception + Exception + Off + Videos up to %s + The admins of this group only allow to send %s. + Text not allowed + Choose emoji or sticker + Up to %s + Save exception + Edit Exception + Translate To + Detected Language + Don\'t translate %s + Don\'t translate %s + Translate to %s + Translate to %s + Show Original + **%s** is added to the Do Not Translate list. + Translation bar is now hidden for this channel. + Translation bar is now hidden for this group. + Translation bar is now hidden for this chat. + No emoji or stickers found + An internal error occurred. Please try again later. + Upgrade to Premium with a discount of **%1$d%%** + Upgrade to the annual payment plan of Telegram Premium now to enjoy the discount. + Save on your subscription up to **%1$d%%** + Sign up for the annual payment plan for Telegram Premium now to get the discount. + Pause music while recording + Set Profile Photo + Status + Free up to **%s** + Clear storage space on your phone + your current plan diff --git a/gradle.properties b/gradle.properties index cb66d17edf2..3061e15e9ac 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,8 +13,8 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true #Sat Mar 12 05:53:50 MSK 2016 -APP_VERSION_NAME=9.3.3 -APP_VERSION_CODE=3026 +APP_VERSION_NAME=9.4.0 +APP_VERSION_CODE=3098 APP_PACKAGE=org.telegram.messenger RELEASE_KEY_PASSWORD=android RELEASE_KEY_ALIAS=androidkey