diff --git a/TMessagesProj/src/main/assets/darkblue.attheme b/TMessagesProj/src/main/assets/darkblue.attheme index c533d74718..bb945993aa 100644 --- a/TMessagesProj/src/main/assets/darkblue.attheme +++ b/TMessagesProj/src/main/assets/darkblue.attheme @@ -429,4 +429,11 @@ chat_searchPanelText=-8796932 chat_inContactIcon=-1 code_comment=-2130706433 chat_outCodeBackground=857487708 -chat_inCodeBackground=856033549 \ No newline at end of file +chat_inCodeBackground=856033549 +code_keyword=-27776 +code_constant=-27776 +code_function=-27776 +code_string=-7806088 +code_operator=2147483647 +code_number=-10887465 +code_comment=2147483647 \ No newline at end of file diff --git a/TMessagesProj/src/main/assets/fonts/rmono.ttf b/TMessagesProj/src/main/assets/fonts/rmono.ttf index b158a334eb..6df2b25360 100644 Binary files a/TMessagesProj/src/main/assets/fonts/rmono.ttf and b/TMessagesProj/src/main/assets/fonts/rmono.ttf differ diff --git a/TMessagesProj/src/main/assets/night.attheme b/TMessagesProj/src/main/assets/night.attheme index 252f7771c6..4e2cdb2b02 100644 --- a/TMessagesProj/src/main/assets/night.attheme +++ b/TMessagesProj/src/main/assets/night.attheme @@ -454,4 +454,11 @@ chat_searchPanelText=-10767620 chat_inContactIcon=-1 code_comment=-2130706433 chat_outCodeBackground=859062986 -chat_inCodeBackground=855638016 \ No newline at end of file +chat_inCodeBackground=855638016 +code_keyword=-27776 +code_constant=-27776 +code_function=-27776 +code_string=-7806088 +code_operator=2147483647 +code_number=-10887465 +code_comment=2147483647 \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java index 53d5e691ff..d9f8626159 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java @@ -526,6 +526,35 @@ public void updateDrawState(TextPaint textPaint) { return spannableStringBuilder; } + public static SpannableStringBuilder replaceSingleLink(String str, int color) { + int startIndex = str.indexOf("**"); + int endIndex = str.indexOf("**", startIndex + 1); + str = str.replace("**", ""); + int index = -1; + int len = 0; + if (startIndex >= 0 && endIndex >= 0 && endIndex - startIndex > 2) { + len = endIndex - startIndex - 2; + index = startIndex; + } + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(str); + if (index >= 0) { + spannableStringBuilder.setSpan(new ClickableSpan() { + @Override + public void updateDrawState(@NonNull TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(false); + ds.setColor(color); + } + + @Override + public void onClick(@NonNull View view) { + + } + }, index, index + len, 0); + } + return spannableStringBuilder; + } + public static void recycleBitmaps(List bitmapToRecycle) { if (Build.VERSION.SDK_INT <= 23) { // cause to crash: @@ -2944,6 +2973,9 @@ public static void shakeViewSpring(View view, Runnable endCallback) { } public static void shakeViewSpring(View view, float shiftDp, Runnable endCallback) { + if (view == null) { + return; + } int shift = dp(shiftDp); if (view.getTag(R.id.spring_tag) != null) { ((SpringAnimation) view.getTag(R.id.spring_tag)).cancel(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java index 30b1b17f43..6255ba4d63 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java @@ -23,8 +23,8 @@ public class BuildVars { public static boolean LOGS_ENABLED = DEBUG_PRIVATE_VERSION; public static boolean USE_CLOUD_STRINGS = true; public static boolean NO_SCOPED_STORAGE = Build.VERSION.SDK_INT <= 29; - public static int BUILD_VERSION = 4075; - public static String BUILD_VERSION_STRING = "10.2.3"; + public static int BUILD_VERSION = 4082; + public static String BUILD_VERSION_STRING = "10.2.6"; public static int APP_ID = 4; public static String APP_HASH = "014b35b6184100b085b0d0572f9b5103"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/CodeHighlighting.java b/TMessagesProj/src/main/java/org/telegram/messenger/CodeHighlighting.java index 084b1eac6d..6d1db01560 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/CodeHighlighting.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/CodeHighlighting.java @@ -1,9 +1,13 @@ package org.telegram.messenger; +import static org.telegram.messenger.AndroidUtilities.dp; + import android.content.Context; +import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Typeface; import android.text.Editable; +import android.text.Layout; import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; @@ -12,6 +16,7 @@ import android.text.TextPaint; import android.text.TextUtils; import android.text.style.CharacterStyle; +import android.text.style.LeadingMarginSpan; import android.text.style.LineHeightSpan; import android.text.style.MetricAffectingSpan; import android.util.Log; @@ -52,7 +57,13 @@ public class CodeHighlighting { public static final int MATCH_COMMENT = 6; public static final int MATCH_FUNCTION = 7; - public static class Span extends MetricAffectingSpan { + public static int getTextSizeDecrement(int codeLength) { + if (codeLength > 120) return 5; + if (codeLength > 50) return 3; + return 2; + } + + public static class Span extends CharacterStyle { public final String lng; public final String code; @@ -67,36 +78,15 @@ public Span(boolean smallerSize, int type, TextStyleSpan.TextStyleRun style, Str this.lng = lng; this.code = code; - if (code == null) { - this.decrementSize = 2; - } else if (code.length() > 120) { - this.decrementSize = 5; - } else if (code.length() > 50) { - this.decrementSize = 3; - } else { - this.decrementSize = 2; - } + this.decrementSize = getTextSizeDecrement(code == null ? 0 : code.length()); this.currentType = type; this.style = style; } - @Override - public void updateMeasureState(TextPaint p) { - if (smallerSize) { - p.setTextSize(AndroidUtilities.dp(SharedConfig.fontSize - decrementSize)); - } - p.setFlags(p.getFlags() | Paint.SUBPIXEL_TEXT_FLAG); - if (style != null) { - style.applyStyle(p); - } else { - p.setTypeface(Typeface.MONOSPACE); - } - } - @Override public void updateDrawState(TextPaint p) { if (smallerSize) { - p.setTextSize(AndroidUtilities.dp(SharedConfig.fontSize - decrementSize)); + p.setTextSize(dp(SharedConfig.fontSize - decrementSize)); } if (currentType == 2) { p.setColor(0xffffffff); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java index 1bf6c85375..2945860ea5 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/DatabaseMigrationHelper.java @@ -1384,6 +1384,14 @@ public static int migrate(MessagesStorage messagesStorage, int version) throws E version = 135; } + if (version == 135) { +// database.executeFast("DROP TABLE stickersets").stepThis().dispose(); + database.executeFast("CREATE TABLE stickersets2(id INTEGER PRIMATE KEY, data BLOB, hash INTEGER, date INTEGER);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS stickersets2_id_index ON stickersets2(id);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 136").stepThis().dispose(); + version = 136; + } + return version; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLog.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLog.java index cbf4f3e1c2..03b0449107 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLog.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLog.java @@ -173,7 +173,7 @@ private static void checkGson() { //exclude file loading excludeRequests = new HashSet<>(); excludeRequests.add("TL_upload_getFile"); - excludeRequests.add("TL_upload_a"); + excludeRequests.add("TL_upload_getWebFile"); ExclusionStrategy strategy = new ExclusionStrategy() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java index 338cd4857c..7e7a78b5be 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java @@ -1192,19 +1192,36 @@ public TLRPC.TL_messages_stickerSet getStickerSet(TLRPC.InputStickerSet inputSti return null; } + private boolean cleanedupStickerSetCache; + private void cleanupStickerSetCache() { + if (cleanedupStickerSetCache) { + return; + } + cleanedupStickerSetCache = true; + getMessagesStorage().getStorageQueue().postRunnable(() -> { + try { + final long minDate = (System.currentTimeMillis() - 1000 * 60 * 60 * 24 * 7); + getMessagesStorage().getDatabase().executeFast("DELETE FROM stickersets2 WHERE date < " + minDate).stepThis().dispose(); + } catch (Exception e) { + FileLog.e(e); + } + }); + } + private void saveStickerSetIntoCache(TLRPC.TL_messages_stickerSet set) { if (set == null || set.set == null) { return; } getMessagesStorage().getStorageQueue().postRunnable(() -> { try { - SQLitePreparedStatement state = getMessagesStorage().getDatabase().executeFast("REPLACE INTO stickersets VALUES(?, ?, ?)"); + SQLitePreparedStatement state = getMessagesStorage().getDatabase().executeFast("REPLACE INTO stickersets2 VALUES(?, ?, ?, ?)"); state.requery(); NativeByteBuffer data = new NativeByteBuffer(set.getObjectSize()); set.serializeToStream(data); state.bindLong(1, set.set.id); state.bindByteBuffer(2, data); state.bindInteger(3, set.set.hash); + state.bindLong(4, System.currentTimeMillis()); state.step(); data.reuse(); state.dispose(); @@ -1212,6 +1229,7 @@ private void saveStickerSetIntoCache(TLRPC.TL_messages_stickerSet set) { FileLog.e(e); } }); + cleanupStickerSetCache(); } private TLRPC.TL_messages_stickerSet getCachedStickerSetInternal(long id, Integer hash) { @@ -1219,7 +1237,7 @@ private TLRPC.TL_messages_stickerSet getCachedStickerSetInternal(long id, Intege SQLiteCursor cursor = null; NativeByteBuffer data = null; try { - cursor = getMessagesStorage().getDatabase().queryFinalized("SELECT data, hash FROM stickersets WHERE id = " + id + " LIMIT 1"); + cursor = getMessagesStorage().getDatabase().queryFinalized("SELECT data, hash FROM stickersets2 WHERE id = " + id + " LIMIT 1"); if (cursor.next() && !cursor.isNull(0)) { data = cursor.byteBufferValue(0); if (data != null) { @@ -6272,11 +6290,15 @@ public ArrayList getEntities(CharSequence[] message, boolea content = substring(content, 0, content.length() - 1); } if (!TextUtils.isEmpty(content)) { + if (content.length() > 1 && content.charAt(0) == '\n') { + content = content.subSequence(1, content.length()); + index--; + } message[0] = AndroidUtilities.concat(startMessage, content, endMessage); TLRPC.TL_messageEntityPre entity = new TLRPC.TL_messageEntityPre(); entity.offset = start + (replacedFirst ? 0 : 1); entity.length = index - start - 3 - (language.length() + (!language.isEmpty() ? 1 : 0)) + (replacedFirst ? 0 : 1); - entity.language = language; + entity.language = TextUtils.isEmpty(language) || language.trim().length() == 0 ? "" : language; entities.add(entity); lastIndex -= 6; } @@ -6619,10 +6641,13 @@ public void saveDraft(long dialogId, int threadId, CharSequence message, ArrayLi TLRPC.Peer peer2 = getMessagesController().getPeer(dialogId); TLRPC.Peer thisPeer = quote.message.messageOwner.peer_id; if (peer2 != null && !MessageObject.peersEqual(peer2, thisPeer)) { - draftMessage.reply_to.flags |= 1; - draftMessage.reply_to.reply_to_peer_id = getMessagesController().getInputPeer(peer2); + draftMessage.reply_to.flags |= 2; + draftMessage.reply_to.reply_to_peer_id = getMessagesController().getInputPeer(thisPeer); } } + } else if (dialogId != MessageObject.getDialogId(replyToMessage)) { + draftMessage.reply_to.flags |= 2; + draftMessage.reply_to.reply_to_peer_id = getMessagesController().getInputPeer(getMessagesController().getPeer(MessageObject.getDialogId(replyToMessage))); } } if (entities != null && !entities.isEmpty()) { @@ -6633,10 +6658,20 @@ public void saveDraft(long dialogId, int threadId, CharSequence message, ArrayLi SparseArray threads = drafts.get(dialogId); TLRPC.DraftMessage currentDraft = threads == null ? null : threads.get(threadId); if (!clean) { - if ( - currentDraft != null && currentDraft.message.equals(draftMessage.message) && replyToEquals(currentDraft.reply_to, draftMessage.reply_to) && currentDraft.no_webpage == draftMessage.no_webpage || - currentDraft == null && TextUtils.isEmpty(draftMessage.message) && (draftMessage.reply_to == null || draftMessage.reply_to.reply_to_msg_id == 0) - ) { + boolean sameDraft; + if (currentDraft != null) { + sameDraft = ( + currentDraft.message.equals(draftMessage.message) && + replyToEquals(currentDraft.reply_to, draftMessage.reply_to) && + currentDraft.no_webpage == draftMessage.no_webpage + ); + } else { + sameDraft = ( + TextUtils.isEmpty(draftMessage.message) && + (draftMessage.reply_to == null || draftMessage.reply_to.reply_to_msg_id == 0) + ); + } + if (sameDraft) { return; } } @@ -6780,7 +6815,7 @@ public void saveDraft(long dialogId, int threadId, TLRPC.DraftMessage draft, TLR if (threads != null) { replyToMessage = threads.get(threadId); } - if (replyToMessage == null || replyToMessage.id != draft.reply_to.reply_to_msg_id || !MessageObject.peersEqual(replyToMessage.peer_id, getMessagesController().getPeer(draft.reply_to.reply_to_msg_id))) { + if (replyToMessage == null || replyToMessage.id != draft.reply_to.reply_to_msg_id || !MessageObject.peersEqual(draft.reply_to.reply_to_peer_id, replyToMessage.peer_id)) { replyToMessage = null; } } else if (draft != null && draft.reply_to == null) { @@ -6812,13 +6847,14 @@ public void saveDraft(long dialogId, int threadId, TLRPC.DraftMessage draft, TLR } editor.apply(); if (fromServer && (threadId == 0 || getMessagesController().isForum(dialogId))) { - if (draft != null && draft.reply_to != null && draft.reply_to.reply_to_msg_id != 0 && replyToMessage == null) { + if (draft != null && draft.reply_to != null && draft.reply_to.reply_to_msg_id != 0 && (replyToMessage == null || replyToMessage.reply_to instanceof TLRPC.TL_messageReplyHeader && replyToMessage.replyMessage == null)) { + final long replyDialogId = (draft.reply_to.flags & 2) != 0 ? DialogObject.getPeerDialogId(draft.reply_to.reply_to_peer_id) : dialogId; TLRPC.User user = null; TLRPC.Chat chat = null; - if (DialogObject.isUserDialog(dialogId)) { - user = getMessagesController().getUser(dialogId); + if (DialogObject.isUserDialog(replyDialogId)) { + user = getMessagesController().getUser(replyDialogId); } else { - chat = getMessagesController().getChat(-dialogId); + chat = getMessagesController().getChat(-replyDialogId); } if (user != null || chat != null) { long channelId = ChatObject.isChannel(chat) ? chat.id : 0; @@ -6827,7 +6863,7 @@ public void saveDraft(long dialogId, int threadId, TLRPC.DraftMessage draft, TLR getMessagesStorage().getStorageQueue().postRunnable(() -> { try { TLRPC.Message message = null; - SQLiteCursor cursor = getMessagesStorage().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data FROM messages_v2 WHERE mid = %d and uid = %d", messageId, dialogId)); + SQLiteCursor cursor = getMessagesStorage().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, replydata FROM messages_v2 WHERE mid = %d and uid = %d", messageId, replyDialogId)); if (cursor.next()) { NativeByteBuffer data = cursor.byteBufferValue(0); if (data != null) { @@ -6835,6 +6871,33 @@ public void saveDraft(long dialogId, int threadId, TLRPC.DraftMessage draft, TLR message.readAttachPath(data, getUserConfig().clientUserId); data.reuse(); } + if (message != null) { + ArrayList usersToLoad = new ArrayList<>(); + ArrayList chatsToLoad = new ArrayList<>(); + LongSparseArray>> replyMessageOwners = new LongSparseArray<>(); + LongSparseArray> dialogReplyMessagesIds = new LongSparseArray<>(); + try { + if (message.reply_to != null && message.reply_to.reply_to_msg_id != 0) { + if (!cursor.isNull(1)) { + NativeByteBuffer data2 = cursor.byteBufferValue(1); + if (data2 != null) { + message.replyMessage = TLRPC.Message.TLdeserialize(data2, data2.readInt32(false), false); + message.replyMessage.readAttachPath(data2, getUserConfig().clientUserId); + data2.reuse(); + if (message.replyMessage != null) { + MessagesStorage.addUsersAndChatsFromMessage(message.replyMessage, usersToLoad, chatsToLoad, null); + } + } + } + if (message.replyMessage == null) { + MessagesStorage.addReplyMessages(message, replyMessageOwners, dialogReplyMessagesIds); + } + } + } catch (Exception e) { + getMessagesStorage().checkSQLException(e); + } + getMessagesStorage().loadReplyMessages(replyMessageOwners, dialogReplyMessagesIds, usersToLoad, chatsToLoad, false); + } } cursor.dispose(); if (message == null) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java index 2d4ac02a0f..46a8471507 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -10,9 +10,10 @@ import static org.telegram.messenger.AndroidUtilities.dp; +import android.graphics.Canvas; import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.Rect; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.RectF; import android.graphics.Typeface; import android.graphics.drawable.BitmapDrawable; @@ -32,10 +33,10 @@ import android.text.style.URLSpan; import android.text.util.Linkify; import android.util.Base64; -import android.util.Pair; import androidx.annotation.NonNull; import androidx.collection.LongSparseArray; +import androidx.core.graphics.ColorUtils; import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.browser.Browser; @@ -56,6 +57,7 @@ import org.telegram.ui.Components.QuoteSpan; import org.telegram.ui.Components.Reactions.ReactionsLayoutInBubble; import org.telegram.ui.Components.Reactions.ReactionsUtils; +import org.telegram.ui.Components.Text; import org.telegram.ui.Components.TextStyleSpan; import org.telegram.ui.Components.TranscribeButton; import org.telegram.ui.Components.TypefaceSpan; @@ -683,6 +685,152 @@ public static class TextLayoutBlock { public boolean code; public boolean quote; + public String language; + public Text languageLayout; + public int languageHeight; // included in padTop + + public boolean hasCodeCopyButton; + public int copyIconColor; + public Drawable copyIcon; + public Text copyText; + public int copySelectorColor; + public Drawable copySelector; + public Paint copySeparator; + + public void layoutCode(String lng, int codeLength) { + hasCodeCopyButton = codeLength >= 75; + if (hasCodeCopyButton) { + copyText = new Text(LocaleController.getString(R.string.CopyCode).toUpperCase(), SharedConfig.fontSize - 3, AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM)); + copyIcon = ApplicationLoader.applicationContext.getResources().getDrawable(R.drawable.msg_copy).mutate(); + copyIcon.setColorFilter(new PorterDuffColorFilter(copyIconColor, PorterDuff.Mode.SRC_IN)); + copySelector = Theme.createRadSelectorDrawable(copySelectorColor, 0, 0, Math.min(5, SharedConfig.bubbleRadius), 0); + copySeparator = new Paint(Paint.ANTI_ALIAS_FLAG); + } + if (TextUtils.isEmpty(lng)) { + language = null; + languageLayout = null; + return; + } + language = lng; + languageLayout = new Text( + capitalizeLanguage(lng), + SharedConfig.fontSize - 1 - CodeHighlighting.getTextSizeDecrement(codeLength) / 2, + AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM) + ); + languageHeight = (int) (languageLayout.getTextSize() * 1.714f) + dp(4); + } + + public void drawCopyCodeButton(Canvas canvas, RectF bounds, int textColor, int backgroundColor, float alpha) { + if (!hasCodeCopyButton) { + return; + } + + final int selectorColor = Theme.multAlpha(textColor, .10f); + if (copySelectorColor != selectorColor) { + Theme.setSelectorDrawableColor(copySelector, copySelectorColor = selectorColor, true); + } + copySelector.setBounds((int) bounds.left + dp(3), (int) (bounds.bottom - dp(38)), (int) bounds.right, (int) bounds.bottom); + copySelector.setAlpha((int) (0xFF * alpha)); + copySelector.draw(canvas); + + copySeparator.setColor(ColorUtils.setAlphaComponent(backgroundColor, 0x26)); + canvas.drawRect(bounds.left + dp(10), bounds.bottom - dp(38) - AndroidUtilities.getShadowHeight(), bounds.right - dp(6.66f), bounds.bottom - dp(38), copySeparator); + + final float iconScale = .8f; + final float contentWidth = Math.min(bounds.width() - dp(12), copyIcon.getIntrinsicWidth() * iconScale + dp(5) + copyText.getCurrentWidth()); + float x = bounds.centerX() - contentWidth / 2f; + final float cy = bounds.bottom - dp(38) / 2f; + + if (copyIconColor != textColor) { + copyIcon.setColorFilter(new PorterDuffColorFilter(copyIconColor = textColor, PorterDuff.Mode.SRC_IN)); + } + copyIcon.setAlpha((int) (0xFF * alpha)); + copyIcon.setBounds( + (int) x, + (int) (cy - copyIcon.getIntrinsicHeight() * iconScale / 2f), + (int) (x + copyIcon.getIntrinsicWidth() * iconScale), + (int) (cy + copyIcon.getIntrinsicHeight() * iconScale / 2f) + ); + copyIcon.draw(canvas); + + x += copyIcon.getIntrinsicWidth() * iconScale + dp(5); + copyText + .ellipsize((int) (contentWidth - (copyIcon.getIntrinsicWidth() * iconScale + dp(5))) + dp(12)) + .draw(canvas, x, cy, textColor, alpha); + } + + private static String capitalizeLanguage(String lng) { + if (lng == null) return null; + String llng = lng.toLowerCase().replaceAll("\\W", ""); + switch (llng) { + case "js": + case "javascript": + return "JavaScript"; + case "ts": + case "typescript": + return "TypeScript"; + case "objc": + case "objectivec": + return "Objective-C"; + case "md": + case "markdown": + return "Markdown"; + case "rb": + case "ruby": + return "Ruby"; + case "py": + case "python": + return "Python"; + case "actionscript": return "ActionScript"; + case "autohotkey": return "AutoHotKey"; + case "cpp": return "C++"; + case "csharp": + case "cs": + return "C#"; + case "aspnet": return "ASP.NET"; + case "c": + case "arduino": + case "swift": + case "rust": + case "pascal": + case "kotlin": + case "lua": + case "docker": + case "dockerfile": + case "dart": + case "java": + return capitalizeFirst(lng); + case "http": + case "html": + case "css": + case "scss": + case "less": + case "asm": + case "nasm": + case "wasm": + case "xml": + case "yaml": + case "yml": + case "php": + case "json": + case "json5": + case "r": + case "ini": + case "glsl": + case "hlsl": + case "csv": + case "cobol": + case "jsx": + case "tsx": + return lng.toUpperCase(); + } + return lng; + } + + private static String capitalizeFirst(String str) { + return str.substring(0, 1).toUpperCase() + str.substring(1).toLowerCase(); + } + public boolean isRtl() { return (directionFlags & FLAG_RTL) != 0 && (directionFlags & FLAG_NOT_RTL) == 0; } @@ -1257,6 +1405,7 @@ public boolean contains(int messageId) { public boolean hasCodeAtTop, hasCodeAtBottom; public boolean hasQuote; public boolean hasSingleQuote; + public boolean hasSingleCode; public boolean hasQuoteAtBottom; public MessageObject(int accountNum, TL_stories.StoryItem storyItem) { @@ -5805,7 +5954,7 @@ public int getMaxMessageTextWidth() { } generatedWithDensity = AndroidUtilities.density; if (hasCode) { - maxWidth = generatedWithMinSize - dp(45); + maxWidth = generatedWithMinSize - dp(45 + 15); if (needDrawAvatarInternal() && !isOutOwner() && !messageOwner.isThreadMessage) { maxWidth -= dp(52); } @@ -5830,7 +5979,7 @@ public int getMaxMessageTextWidth() { maxWidth -= dp(52); } if (needDrawShareButton() && !isOutOwner()) { - maxWidth -= dp(20); + maxWidth -= dp(10); } if (getMedia(messageOwner) instanceof TLRPC.TL_messageMediaGame) { maxWidth -= dp(10); @@ -5927,6 +6076,7 @@ public void generateLayout(TLRPC.User fromUser) { hasCode = messageText instanceof Spanned && ((Spanned) messageText).getSpans(0, messageText.length(), CodeHighlighting.Span.class).length > 0; hasQuote = messageText instanceof Spanned && ((Spanned) messageText).getSpans(0, messageText.length(), QuoteSpan.QuoteStyleSpan.class).length > 0; hasSingleQuote = false; + hasSingleCode = false; if (messageText instanceof Spanned) { Spanned spanned = (Spanned) messageText; @@ -5935,6 +6085,9 @@ public void generateLayout(TLRPC.User fromUser) { quoteSpans[i].adaptLineHeight = false; } hasSingleQuote = quoteSpans.length == 1 && spanned.getSpanStart(quoteSpans[0]) == 0 && spanned.getSpanEnd(quoteSpans[0]) == spanned.length(); + + CodeHighlighting.Span[] codeSpans = spanned.getSpans(0, spanned.length(), CodeHighlighting.Span.class); + hasSingleCode = codeSpans.length == 1 && spanned.getSpanStart(codeSpans[0]) == 0 && spanned.getSpanEnd(codeSpans[0]) == spanned.length(); } @@ -5942,6 +6095,8 @@ public void generateLayout(TLRPC.User fromUser) { if (hasSingleQuote) { maxWidth -= AndroidUtilities.dp(32); + } else if (hasSingleCode) { + maxWidth -= AndroidUtilities.dp(15); } StaticLayout textLayout; @@ -5981,6 +6136,8 @@ public void generateLayout(TLRPC.User fromUser) { if (hasSingleQuote) { maxWidth += AndroidUtilities.dp(32); + } else if (hasSingleCode) { + maxWidth += AndroidUtilities.dp(15); } textHeight = 0; @@ -6029,6 +6186,7 @@ public void generateLayout(TLRPC.User fromUser) { hasCodeAtBottom = false; hasQuoteAtBottom = false; hasSingleQuote = false; + hasSingleCode = false; float offset = 0; for (int a = 0; a < textRanges.size(); a++) { TextLayoutBlock block = new TextLayoutBlock(); @@ -6049,17 +6207,19 @@ public void generateLayout(TLRPC.User fromUser) { hasCodeAtBottom = block.code; } hasSingleQuote = block.first && block.last && block.quote; + hasSingleCode = block.first && block.last && !block.quote && block.code; if (block.quote) { if (block.first && block.last) { - block.padTop = block.padBottom = AndroidUtilities.dp(6); + block.padTop = block.padBottom = dp(6); } else { - block.padTop = AndroidUtilities.dp(block.first ? 8 : 6); - block.padBottom = AndroidUtilities.dp(7); + block.padTop = dp(block.first ? 8 : 6); + block.padBottom = dp(7); } } else if (block.code) { - block.padTop = block.first ? 0 : AndroidUtilities.dp(5); - block.padBottom = block.last ? 0 : AndroidUtilities.dp(5); + block.layoutCode(range.language, range.end - range.start); + block.padTop = dp(4) + block.languageHeight + (block.first ? 0 : dp(5)); + block.padBottom = dp(4) + (block.last ? 0 : dp(7)) + (block.hasCodeCopyButton ? dp(38) : 0); } TextPaint layoutPaint = paint; @@ -6075,12 +6235,23 @@ public void generateLayout(TLRPC.User fromUser) { } CharSequence blockText = messageText.subSequence(range.start, range.end); + int blockMaxWidth = maxWidth; + if (block.quote) { + blockMaxWidth -= dp(24); + } else if (block.code) { + blockMaxWidth -= dp(15); + } if (blocksCount == 1) { - if (block.code && !block.quote && textLayout.getText() instanceof Spannable && !TextUtils.isEmpty(range.language)) { - SpannableString sb = CodeHighlighting.getHighlighted(blockText.toString(), range.language); - if (hasUrls && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + if (block.code && !block.quote && textLayout.getText() instanceof Spannable) { + SpannableString sb; + if (!TextUtils.isEmpty(range.language)) { + sb = CodeHighlighting.getHighlighted(blockText.toString(), range.language); + } else { + sb = new SpannableString(blockText.toString()); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { StaticLayout.Builder builder = - StaticLayout.Builder.obtain(sb, 0, sb.length(), layoutPaint, maxWidth - (block.quote ? dp(24) : 0) + dp(2)) + StaticLayout.Builder.obtain(sb, 0, sb.length(), layoutPaint, blockMaxWidth) .setLineSpacing(lineAdd, lineSpacing) .setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY) .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE) @@ -6093,7 +6264,7 @@ public void generateLayout(TLRPC.User fromUser) { } textLayout = builder.build(); } else { - textLayout = new StaticLayout(sb, 0, sb.length(), layoutPaint, maxWidth - (block.quote ? dp(24) : 0), align, lineSpacing, lineAdd, false); + textLayout = new StaticLayout(sb, 0, sb.length(), layoutPaint, blockMaxWidth, align, lineSpacing, lineAdd, false); } } @@ -6135,22 +6306,16 @@ public void generateLayout(TLRPC.User fromUser) { } else { sb = SpannableString.valueOf(blockText); } - if (hasUrls && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { StaticLayout.Builder builder = - StaticLayout.Builder.obtain(sb, 0, sb.length(), layoutPaint, maxWidth - (block.quote ? dp(24) : 0) + dp(2)) - .setLineSpacing(lineAdd, lineSpacing) - .setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY) - .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE) - .setAlignment(align); - if (emojiOnlyCount > 0) { - builder.setIncludePad(false); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - builder.setUseLineSpacingFromFallbacks(false); - } - } + StaticLayout.Builder.obtain(sb, 0, sb.length(), layoutPaint, blockMaxWidth) + .setLineSpacing(lineAdd, lineSpacing) + .setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY) + .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE) + .setAlignment(align); block.textLayout = builder.build(); } else { - block.textLayout = new StaticLayout(sb, 0, sb.length(), layoutPaint, maxWidth - (block.quote ? dp(24) : 0), align, lineSpacing, lineAdd, false); + block.textLayout = new StaticLayout(sb, 0, sb.length(), layoutPaint, blockMaxWidth, align, lineSpacing, lineAdd, false); } block.textYOffset = offset; @@ -6195,6 +6360,8 @@ public void generateLayout(TLRPC.User fromUser) { } if (block.quote) { lastLine += AndroidUtilities.dp(32); + } else if (block.code) { + lastLine += AndroidUtilities.dp(15); } int linesMaxWidth = (int) Math.ceil(lastLine); @@ -6233,6 +6400,8 @@ public void generateLayout(TLRPC.User fromUser) { if (block.quote) { lineWidth += AndroidUtilities.dp(32); + } else if (block.code) { + lineWidth += AndroidUtilities.dp(15); } try { @@ -6295,7 +6464,13 @@ public void generateLayout(TLRPC.User fromUser) { block.spoilers.clear(); if (!isSpoilersRevealed && !spoiledLoginCode) { - SpoilerEffect.addSpoilers(null, block.textLayout, -1, linesMaxWidthWithLeft, null, block.spoilers); + int right = linesMaxWidthWithLeft; + if (block.quote) { + right -= AndroidUtilities.dp(32); + } else if (block.code) { + right -= AndroidUtilities.dp(15); + } + SpoilerEffect.addSpoilers(null, block.textLayout, -1, right, null, block.spoilers); } } @@ -6311,11 +6486,8 @@ public static class TextLayoutBlocks { public boolean hasRtl; public float textXOffset; public final ArrayList textLayoutBlocks = new ArrayList<>(); - public boolean hasCode; - public boolean hasCodeAtTop, hasCodeAtBottom; - public boolean hasQuote; - public boolean hasSingleQuote; - public boolean hasQuoteAtBottom; + public boolean hasCode, hasCodeAtTop, hasCodeAtBottom, hasSingleCode; + public boolean hasQuote, hasQuoteAtBottom, hasSingleQuote; public TextLayoutBlocks(MessageObject messageObject, @NonNull CharSequence text, TextPaint textPaint, int width) { this.text = text; @@ -6324,6 +6496,7 @@ public TextLayoutBlocks(MessageObject messageObject, @NonNull CharSequence text, hasCode = text instanceof Spanned && ((Spanned) text).getSpans(0, text.length(), CodeHighlighting.Span.class).length > 0; hasQuote = text instanceof Spanned && ((Spanned) text).getSpans(0, text.length(), QuoteSpan.QuoteStyleSpan.class).length > 0; hasSingleQuote = false; + hasSingleCode = false; if (text instanceof Spanned) { Spanned spanned = (Spanned) text; @@ -6332,12 +6505,17 @@ public TextLayoutBlocks(MessageObject messageObject, @NonNull CharSequence text, quoteSpans[i].adaptLineHeight = false; } hasSingleQuote = quoteSpans.length == 1 && spanned.getSpanStart(quoteSpans[0]) == 0 && spanned.getSpanEnd(quoteSpans[0]) == spanned.length(); + + CodeHighlighting.Span[] codeSpans = spanned.getSpans(0, spanned.length(), CodeHighlighting.Span.class); + hasSingleCode = codeSpans.length == 1 && spanned.getSpanStart(codeSpans[0]) == 0 && spanned.getSpanEnd(codeSpans[0]) == spanned.length(); } StaticLayout textLayout; if (hasSingleQuote) { width -= AndroidUtilities.dp(32); + } else if (hasSingleCode) { + width -= AndroidUtilities.dp(15); } final float lineSpacing = 1f; @@ -6362,6 +6540,8 @@ public TextLayoutBlocks(MessageObject messageObject, @NonNull CharSequence text, if (hasSingleQuote) { width += AndroidUtilities.dp(32); + } else if (hasSingleCode) { + width += AndroidUtilities.dp(15); } textHeight = 0; @@ -6428,14 +6608,15 @@ public TextLayoutBlocks(MessageObject messageObject, @NonNull CharSequence text, if (block.quote) { if (block.first && block.last) { - block.padTop = block.padBottom = AndroidUtilities.dp(6); + block.padTop = block.padBottom = dp(6); } else { - block.padTop = AndroidUtilities.dp(block.first ? 8 : 6); - block.padBottom = AndroidUtilities.dp(7); + block.padTop = dp(block.first ? 8 : 6); + block.padBottom = dp(7); } } else if (block.code) { - block.padTop = block.first ? 0 : AndroidUtilities.dp(5); - block.padBottom = block.last ? 0 : AndroidUtilities.dp(5); + block.layoutCode(range.language, range.end - range.start); + block.padTop = dp(4) + block.languageHeight + (block.first ? 0 : dp(5)); + block.padBottom = dp(4) + (block.last ? 0 : dp(7)) + (block.hasCodeCopyButton ? dp(38) : 0); } TextPaint layoutPaint = textPaint; @@ -6450,19 +6631,30 @@ public TextLayoutBlocks(MessageObject messageObject, @NonNull CharSequence text, } } + int blockMaxWidth = width; + if (block.quote) { + blockMaxWidth -= dp(32); + } else if (block.code) { + blockMaxWidth -= dp(15); + } if (blocksCount == 1) { - if (block.code && !block.quote && textLayout.getText() instanceof Spannable && !TextUtils.isEmpty(range.language)) { - SpannableString sb = CodeHighlighting.getHighlighted(text.subSequence(range.start, range.end).toString(), range.language); + if (block.code && !block.quote && textLayout.getText() instanceof Spannable) { + SpannableString sb; + if (!TextUtils.isEmpty(range.language)) { + sb = CodeHighlighting.getHighlighted(text.subSequence(range.start, range.end).toString(), range.language); + } else { + sb = new SpannableString(text.subSequence(range.start, range.end)); + } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { StaticLayout.Builder builder = - StaticLayout.Builder.obtain(sb, 0, text.length(), layoutPaint, width) + StaticLayout.Builder.obtain(sb, 0, text.length(), layoutPaint, blockMaxWidth) .setLineSpacing(lineAdd, lineSpacing) .setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY) .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE) .setAlignment(align); textLayout = builder.build(); } else { - textLayout = new StaticLayout(sb, layoutPaint, width, align, lineSpacing, lineAdd, false); + textLayout = new StaticLayout(sb, layoutPaint, blockMaxWidth, align, lineSpacing, lineAdd, false); } } @@ -6488,7 +6680,7 @@ public TextLayoutBlocks(MessageObject messageObject, @NonNull CharSequence text, } else { sb = SpannableString.valueOf(text.subSequence(startCharacter, endCharacter)); } - block.textLayout = new StaticLayout(sb, 0, sb.length(), layoutPaint, width - (block.quote ? dp(24) : 0), align, lineSpacing, lineAdd, false); + block.textLayout = new StaticLayout(sb, 0, sb.length(), layoutPaint, blockMaxWidth, align, lineSpacing, lineAdd, false); block.textYOffset = offset; if (a != 0) { @@ -6571,6 +6763,8 @@ public TextLayoutBlocks(MessageObject messageObject, @NonNull CharSequence text, if (block.quote) { lineWidth += AndroidUtilities.dp(32); + } else if (block.code) { + lineWidth += AndroidUtilities.dp(15); } try { @@ -6627,14 +6821,17 @@ public TextLayoutBlocks(MessageObject messageObject, @NonNull CharSequence text, } textWidth = Math.max(textWidth, Math.min(width, linesMaxWidth)); -// if (block.quote && hasSingleQuote) { -// textWidth += AndroidUtilities.dp(32); -// } } linesOffset += currentBlockLinesCount; if (messageObject != null && !messageObject.isSpoilersRevealed && !messageObject.spoiledLoginCode) { - SpoilerEffect.addSpoilers(null, block.textLayout, -1, linesMaxWidthWithLeft, null, block.spoilers); + int right = linesMaxWidthWithLeft; + if (block.quote) { + right -= AndroidUtilities.dp(32); + } else if (block.code) { + right -= AndroidUtilities.dp(15); + } + SpoilerEffect.addSpoilers(null, block.textLayout, -1, right, null, block.spoilers); } } } @@ -6753,6 +6950,25 @@ public static boolean peersEqual(TLRPC.InputPeer a, TLRPC.InputPeer b) { return false; } + public static boolean peersEqual(TLRPC.InputPeer a, TLRPC.Peer b) { + if (a == null && b == null) { + return true; + } + if (a == null || b == null) { + return false; + } + if (a instanceof TLRPC.TL_inputPeerChat && b instanceof TLRPC.TL_peerChat) { + return a.chat_id == b.chat_id; + } + if (a instanceof TLRPC.TL_inputPeerChannel && b instanceof TLRPC.TL_peerChannel) { + return a.channel_id == b.channel_id; + } + if (a instanceof TLRPC.TL_inputPeerUser && b instanceof TLRPC.TL_peerUser) { + return a.user_id == b.user_id; + } + return false; + } + public static boolean peersEqual(TLRPC.Peer a, TLRPC.Peer b) { if (a == null && b == null) { return true; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index 6d73789592..b3b6dabcbb 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -14956,6 +14956,9 @@ public void processUpdates(final TLRPC.Updates updates, boolean fromQueue) { } else { break; } + if (updates.updates.size() <= 0) { + break; + } updates.updates.remove(a); a--; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index 15a7f70ca7..1994e4a33c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -98,7 +98,7 @@ public class MessagesStorage extends BaseController { private static SparseArray Instance = new SparseArray(); private static final Object lockObject = new Object(); - public final static int LAST_DB_VERSION = 135; + public final static int LAST_DB_VERSION = 136; private boolean databaseMigrationInProgress; public boolean showClearDatabaseAlert; private LongSparseIntArray dialogIsForum = new LongSparseIntArray(); @@ -598,7 +598,6 @@ public static void createTables(SQLiteDatabase database) throws SQLiteException database.executeFast("CREATE TABLE stickers_v2(id INTEGER PRIMARY KEY, data BLOB, date INTEGER, hash INTEGER);").stepThis().dispose(); database.executeFast("CREATE TABLE stickers_featured(id INTEGER PRIMARY KEY, data BLOB, unread BLOB, date INTEGER, hash INTEGER, premium INTEGER, emoji INTEGER);").stepThis().dispose(); database.executeFast("CREATE TABLE stickers_dice(emoji TEXT PRIMARY KEY, data BLOB, date INTEGER);").stepThis().dispose(); - database.executeFast("CREATE TABLE stickersets(id INTEGER PRIMATE KEY, data BLOB, hash INTEGER);").stepThis().dispose(); database.executeFast("CREATE TABLE hashtag_recent_v2(id TEXT PRIMARY KEY, date INTEGER);").stepThis().dispose(); database.executeFast("CREATE TABLE webpage_pending_v2(id INTEGER, mid INTEGER, uid INTEGER, PRIMARY KEY (id, mid, uid));").stepThis().dispose(); database.executeFast("CREATE TABLE sent_files_v2(uid TEXT, type INTEGER, data BLOB, parent TEXT, PRIMARY KEY (uid, type))").stepThis().dispose(); @@ -610,6 +609,9 @@ public static void createTables(SQLiteDatabase database) throws SQLiteException database.executeFast("CREATE TABLE requested_holes(uid INTEGER, seq_out_start INTEGER, seq_out_end INTEGER, PRIMARY KEY (uid, seq_out_start, seq_out_end));").stepThis().dispose(); database.executeFast("CREATE TABLE sharing_locations(uid INTEGER PRIMARY KEY, mid INTEGER, date INTEGER, period INTEGER, message BLOB, proximity INTEGER);").stepThis().dispose(); + database.executeFast("CREATE TABLE stickersets2(id INTEGER PRIMATE KEY, data BLOB, hash INTEGER, date INTEGER);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS stickersets2_id_index ON stickersets2(id);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS stickers_featured_emoji_index ON stickers_featured(emoji);").stepThis().dispose(); database.executeFast("CREATE TABLE shortcut_widget(id INTEGER, did INTEGER, ord INTEGER, PRIMARY KEY (id, did));").stepThis().dispose(); @@ -1327,7 +1329,7 @@ public void clearLocalDatabase() { database.executeFast("DELETE FROM attach_menu_bots").stepThis().dispose(); database.executeFast("DELETE FROM animated_emoji").stepThis().dispose(); database.executeFast("DELETE FROM stickers_v2").stepThis().dispose(); - database.executeFast("DELETE FROM stickersets").stepThis().dispose(); + database.executeFast("DELETE FROM stickersets2").stepThis().dispose(); database.executeFast("DELETE FROM messages_holes_topics").stepThis().dispose(); database.executeFast("DELETE FROM messages_topics").stepThis().dispose(); database.executeFast("DELETE FROM topics").stepThis().dispose(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/utils/CustomHtml.java b/TMessagesProj/src/main/java/org/telegram/messenger/utils/CustomHtml.java index d44d91f5af..b6cc39c6d0 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/utils/CustomHtml.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/utils/CustomHtml.java @@ -1,6 +1,7 @@ package org.telegram.messenger.utils; import android.text.Spanned; +import android.text.TextUtils; import org.telegram.messenger.CodeHighlighting; import org.telegram.ui.Components.AnimatedEmojiSpan; @@ -164,7 +165,11 @@ private static void toHTML_4_wrapMonoscape2(StringBuilder out, Spanned text, int for (int j = 0; j < spans.length; ++j) { CodeHighlighting.Span span = spans[j]; if (span != null) { - out.append("
");
+                        if (TextUtils.isEmpty(span.lng)) {
+                            out.append("
");
+                        } else {
+                            out.append("
");
+                        }
                     }
                 }
             }
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 b6cb3bf36c..8ae7eab061 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java
@@ -1760,9 +1760,9 @@ public boolean fillAccentColors(SparseIntArray currentColorsNoAccent, SparseIntA
             if (isDarkTheme && currentColors.get(key_chat_outBubbleGradient1) != 0) {
                 int outBubbleAverage = averageColor(currentColors, key_chat_outBubbleGradient1, key_chat_outBubbleGradient2, key_chat_outBubbleGradient3);
                 Color.colorToHSV(outBubbleAverage, tempHSV);
-                tempHSV[1] = Utilities.clamp(tempHSV[1] + .3f, 1, 0);
-                tempHSV[2] = Utilities.clamp(tempHSV[2] + -.4f, 1, 0);
-                currentColors.put(key_chat_outCodeBackground, Color.HSVToColor(0x70, tempHSV));
+                tempHSV[1] = Utilities.clamp(tempHSV[1] + .1f, 1, 0);
+                tempHSV[2] = Utilities.clamp(tempHSV[2] - .8f, 1, 0);
+                currentColors.put(key_chat_outCodeBackground, Color.HSVToColor(0x40, tempHSV));
             } else {
                 currentColors.put(key_chat_outCodeBackground, codeBackground(outBubble, isDarkTheme));
             }
@@ -1826,13 +1826,16 @@ private int linkSelectionBackground(int linkColor, int bgColor, boolean isDarkTh
         private int codeBackground(int bubbleColor, boolean isDarkTheme) {
             Color.colorToHSV(bubbleColor, tempHSV);
             int alpha = 0x20;
-            if (tempHSV[1] <= 0 || tempHSV[2] >= 1 || tempHSV[2] <= 0) {
-                tempHSV[2] = Math.max(0, Math.min(1, tempHSV[2] + (isDarkTheme ? .3f : -.2f)));
+            if (isDarkTheme) {
+                alpha = 0x40;
+                tempHSV[1] = Utilities.clamp(tempHSV[1] - .08f, 1f, 0f);
+                tempHSV[2] = .03f;
             } else {
-                tempHSV[1] = Math.max(0, Math.min(1, tempHSV[1] + (isDarkTheme ? -.3f : .28f)));
-                tempHSV[2] = Math.max(0, Math.min(1, tempHSV[2] + (isDarkTheme ? +.1f : -.1f)));
-                if (isDarkTheme) {
-                    alpha = 0x60;
+                if (tempHSV[1] <= 0 || tempHSV[2] >= 1 || tempHSV[2] <= 0) {
+                    tempHSV[2] = Math.max(0, Math.min(1, tempHSV[2] + -.2f));
+                } else {
+                    tempHSV[1] = Math.max(0, Math.min(1, tempHSV[1] + .28f));
+                    tempHSV[2] = Math.max(0, Math.min(1, tempHSV[2] + -.1f));
                 }
             }
             return Color.HSVToColor(alpha, tempHSV);
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 2352e82ace..502fa7470c 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java
@@ -34,13 +34,11 @@
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
-import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Region;
 import android.graphics.Shader;
 import android.graphics.Typeface;
-import android.graphics.Xfermode;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
@@ -61,9 +59,7 @@
 import android.text.style.CharacterStyle;
 import android.text.style.ClickableSpan;
 import android.text.style.LeadingMarginSpan;
-import android.text.style.LineHeightSpan;
 import android.text.style.URLSpan;
-import android.util.Log;
 import android.util.Property;
 import android.util.SparseArray;
 import android.util.StateSet;
@@ -127,7 +123,6 @@
 import org.telegram.tgnet.TLObject;
 import org.telegram.tgnet.TLRPC;
 import org.telegram.tgnet.tl.TL_stories;
-import org.telegram.ui.ActionBar.AdjustPanLayoutHelper;
 import org.telegram.ui.ActionBar.Theme;
 import org.telegram.ui.ChatActivity;
 import org.telegram.ui.Components.AnimatedEmojiDrawable;
@@ -454,6 +449,10 @@ default boolean isReplyOrSelf() {
         default void didPressExtendedMediaPreview(ChatMessageCell cell, TLRPC.KeyboardButton button) {
         }
 
+        default void didPressUserStatus(ChatMessageCell cell, TLRPC.User user, TLRPC.Document document) {
+
+        }
+
         default void didPressUserAvatar(ChatMessageCell cell, TLRPC.User user, float touchX, float touchY) {
         }
 
@@ -501,7 +500,7 @@ default CharacterStyle getProgressLoadingLink(ChatMessageCell cell) {
         default void didPressUrl(ChatMessageCell cell, CharacterStyle url, boolean longPress) {
         }
 
-        default void didPressCode(ChatMessageCell cell, CharacterStyle span, boolean longPress) {
+        default void didPressCodeCopy(ChatMessageCell cell, MessageObject.TextLayoutBlock block) {
 
         }
 
@@ -887,6 +886,14 @@ public boolean isCellAttachedToWindow() {
     private Path instantLinkArrowPath;
     private Paint instantLinkArrowPaint;
 
+    private int nameLayoutSelectorColor;
+    private Drawable nameLayoutSelector;
+    private boolean nameLayoutPressed;
+
+    private int nameStatusSelectorColor;
+    private Drawable nameStatusSelector;
+    private boolean nameStatusPressed;
+
     private RoundVideoPlayingDrawable roundVideoPlayingDrawable;
 
     private StaticLayout docTitleLayout;
@@ -959,6 +966,7 @@ public boolean isCellAttachedToWindow() {
 
     private AnimatedEmojiSpan pressedEmoji;
     private LinkSpanDrawable pressedLink;
+    private MessageObject.TextLayoutBlock pressedCopyCode;
     private LinkSpanDrawable.LinkCollector links = new LinkSpanDrawable.LinkCollector(this);
     private int pressedLinkType;
     private boolean linkPreviewPressed;
@@ -1113,6 +1121,7 @@ class LoadingDrawableLocation {
     private int backgroundDrawableBottom;
     private int viaWidth;
     private int viaNameWidth;
+    private boolean viaOnly;
     private TypefaceSpan viaSpan1;
     private TypefaceSpan viaSpan2;
     private int availableTimeWidth;
@@ -1265,7 +1274,7 @@ class LoadingDrawableLocation {
     private TLRPC.FileLocation currentPhoto;
     private String currentNameString;
     private Object currentNameStatus;
-    private AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable currentNameStatusDrawable;
+    public AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable currentNameStatusDrawable;
 
     private TLRPC.User currentForwardUser;
     private TLRPC.User currentViaBotUser;
@@ -1606,11 +1615,111 @@ private int[] getRealSpanStartAndEnd(Spannable buffer, CharacterStyle link) {
         return new int[]{start, end};
     }
 
+    private boolean checkNameMotionEvent(MotionEvent event) {
+        if (!drawNameLayout || nameLayout == null || nameLayoutSelector == null || currentUser == null && currentChat == null) {
+            nameLayoutPressed = false;
+            return false;
+        }
+        final boolean pressed = nameLayoutSelector.getBounds().contains((int) event.getX(), (int) event.getY());
+        if (event.getAction() == MotionEvent.ACTION_DOWN) {
+            nameLayoutPressed = pressed;
+            if (nameLayoutPressed) {
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+                    nameLayoutSelector.setHotspot((int) event.getX(), (int) event.getY());
+                }
+                nameLayoutSelector.setState(pressedState);
+            }
+        } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
+            if (event.getAction() == MotionEvent.ACTION_UP && nameLayoutPressed) {
+                if (delegate != null) {
+                    if (viaOnly) {
+                        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);
+                        }
+                    } else if (currentUser != null) {
+                        delegate.didPressUserAvatar(this, currentUser, event.getX(), event.getY());
+                    } else if (currentChat != null) {
+                        int id;
+                        TLRPC.Chat chat = currentChat;
+                        if (currentMessageObject.messageOwner.fwd_from != null) {
+                            if ((currentMessageObject.messageOwner.fwd_from.flags & 16) != 0) {
+                                id = currentMessageObject.messageOwner.fwd_from.saved_from_msg_id;
+                            } else {
+                                id = currentMessageObject.messageOwner.fwd_from.channel_post;
+                                chat = currentForwardChannel;
+                            }
+                        } else {
+                            id = 0;
+                        }
+                        delegate.didPressChannelAvatar(this, chat != null ? chat : currentChat, id, lastTouchX, lastTouchY);
+                    }
+                }
+            }
+            nameLayoutSelector.setState(StateSet.NOTHING);
+            nameLayoutPressed = false;
+        }
+        return nameLayoutPressed;
+    }
+
+    private boolean checkNameStatusMotionEvent(MotionEvent event) {
+        if (!drawNameLayout || nameLayout == null || nameLayoutSelector == null || currentUser == null && currentChat == null || currentNameStatus == null || currentNameStatusDrawable == null) {
+            nameStatusPressed = false;
+            return false;
+        }
+        final boolean pressed = nameStatusSelector.getBounds().contains((int) event.getX(), (int) event.getY());
+        if (event.getAction() == MotionEvent.ACTION_DOWN) {
+            nameStatusPressed = pressed;
+            if (nameStatusPressed) {
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+                    nameStatusSelector.setHotspot((int) event.getX(), (int) event.getY());
+                }
+                nameStatusSelector.setState(pressedState);
+            }
+        } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
+            if (event.getAction() == MotionEvent.ACTION_UP && nameStatusPressed) {
+                if (delegate != null) {
+                    if (currentUser != null) {
+                        TLRPC.Document document = null;
+                        if (currentNameStatusDrawable.getDrawable() instanceof AnimatedEmojiDrawable) {
+                            document = ((AnimatedEmojiDrawable) currentNameStatusDrawable.getDrawable()).getDocument();
+                        }
+                        delegate.didPressUserStatus(this, currentUser, document);
+                        invalidateOutbounds();
+                    }
+                }
+            }
+            nameStatusSelector.setState(StateSet.NOTHING);
+            nameStatusPressed = false;
+        }
+        return nameStatusPressed;
+    }
+
+    private void resetCodeSelectors() {
+        if (currentMessageObject != null && currentMessageObject.textLayoutBlocks != null) {
+            for (int i = 0; i < currentMessageObject.textLayoutBlocks.size(); ++i) {
+                MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(i);
+                if (block.copySelector != null) {
+                    block.copySelector.setState(StateSet.NOTHING);
+                }
+            }
+        }
+        if (captionLayout != null) {
+            for (int i = 0; i < captionLayout.textLayoutBlocks.size(); ++i) {
+                MessageObject.TextLayoutBlock block = captionLayout.textLayoutBlocks.get(i);
+                if (block.copySelector != null) {
+                    block.copySelector.setState(StateSet.NOTHING);
+                }
+            }
+        }
+    }
+
     private boolean checkTextBlockMotionEvent(MotionEvent event) {
         if (!(currentMessageObject.type == MessageObject.TYPE_TEXT || currentMessageObject.type == MessageObject.TYPE_EMOJIS || currentMessageObject.type == MessageObject.TYPE_STORY_MENTION) || currentMessageObject.textLayoutBlocks == null || currentMessageObject.textLayoutBlocks.isEmpty() || !(currentMessageObject.messageText instanceof Spannable)) {
             return false;
         }
-        if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_UP && (pressedLinkType == 1)) {
+        if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_UP && (pressedLinkType == 1 || pressedCopyCode != null)) {
             int x = (int) event.getX();
             int y = (int) event.getY();
             if (x >= textX && y >= textY && x <= textX + currentMessageObject.textWidth && y <= textY + currentMessageObject.textHeight) {
@@ -1626,6 +1735,24 @@ private boolean checkTextBlockMotionEvent(MotionEvent event) {
                     MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(blockNum);
                     x -= textX - (block.isRtl() ? currentMessageObject.textXOffset : 0);
                     y -= block.textYOffset;
+
+                    if (!block.quote && block.code && x > 0 && x <= currentMessageObject.textWidth && y >= block.padTop + block.height + block.padBottom - dp(38) && y <= block.padTop + block.height + block.padBottom) {
+                        if (event.getAction() == MotionEvent.ACTION_UP) {
+                            if (block == pressedCopyCode && delegate != null) {
+                                delegate.didPressCodeCopy(this, block);
+                            }
+                            resetCodeSelectors();
+                            pressedCopyCode = null;
+                        } else {
+                            pressedCopyCode = block;
+                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+                                block.copySelector.setHotspot(x, y);
+                            }
+                            block.copySelector.setState(pressedState);
+                        }
+                        return true;
+                    }
+
                     final int line = block.textLayout.getLineForVertical(y);
                     final int off = block.charactersOffset + block.textLayout.getOffsetForHorizontal(line, x);
 
@@ -1745,6 +1872,9 @@ private boolean checkTextBlockMotionEvent(MotionEvent event) {
             } else {
                 resetPressedLink(1);
             }
+        } else if (event.getAction() == MotionEvent.ACTION_UP) {
+            pressedCopyCode = null;
+            resetCodeSelectors();
         }
         return false;
     }
@@ -1753,7 +1883,7 @@ private boolean checkCaptionMotionEvent(MotionEvent event) {
         if (!(currentCaption instanceof Spannable) || captionLayout == null) {
             return false;
         }
-        if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_UP && (pressedLinkType == 1)) {
+        if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_UP && (pressedLinkType == 1 || pressedCopyCode != null)) {
             int x = (int) event.getX();
             int y = (int) event.getY();
             if (x >= captionX && y >= captionY && x <= captionX + captionLayout.textWidth && y <= captionY + captionLayout.textHeight) {
@@ -1769,6 +1899,24 @@ private boolean checkCaptionMotionEvent(MotionEvent event) {
                     MessageObject.TextLayoutBlock block = captionLayout.textLayoutBlocks.get(blockNum);
                     x -= captionX - (block.isRtl() ? captionLayout.textXOffset : 0);
                     y -= block.textYOffset;
+
+                    if (!block.quote && block.code && x > 0 && x <= captionLayout.textWidth && y >= block.padTop + block.height + block.padBottom - dp(38) && y <= block.padTop + block.height + block.padBottom) {
+                        if (event.getAction() == MotionEvent.ACTION_UP) {
+                            if (block == pressedCopyCode && delegate != null) {
+                                delegate.didPressCodeCopy(this, block);
+                            }
+                            resetCodeSelectors();
+                            pressedCopyCode = null;
+                        } else {
+                            pressedCopyCode = block;
+                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+                                block.copySelector.setHotspot(x, y);
+                            }
+                            block.copySelector.setState(pressedState);
+                        }
+                        return true;
+                    }
+
                     final int line = block.textLayout.getLineForVertical(y);
                     final int off = block.charactersOffset + block.textLayout.getOffsetForHorizontal(line, x);
 
@@ -1888,6 +2036,9 @@ private boolean checkCaptionMotionEvent(MotionEvent event) {
             } else {
                 resetPressedLink(1);
             }
+        } else if (event.getAction() == MotionEvent.ACTION_UP) {
+            pressedCopyCode = null;
+            resetCodeSelectors();
         }
         return false;
     }
@@ -3107,6 +3258,12 @@ public boolean onTouchEvent(MotionEvent event) {
         if (!result) {
             result = checkTextBlockMotionEvent(event);
         }
+        if (!result) {
+            result = checkNameMotionEvent(event);
+        }
+        if (!result) {
+            result = checkNameStatusMotionEvent(event);
+        }
         if (!result) {
             result = checkPinchToZoom(event);
         }
@@ -3185,6 +3342,13 @@ public boolean onTouchEvent(MotionEvent event) {
                     linkPreviewSelector.setState(StateSet.NOTHING);
                 }
             }
+            if (nameStatusSelector != null) {
+                nameStatusSelector.setState(StateSet.NOTHING);
+            }
+            if (nameLayoutSelector != null) {
+                nameLayoutSelector.setState(StateSet.NOTHING);
+            }
+            resetCodeSelectors();
             if (linkPreviewBounce != null) {
                 linkPreviewBounce.setPressed(false);
             }
@@ -4615,6 +4779,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe
             replyTextHeight = 0;
             viaWidth = 0;
             viaNameWidth = 0;
+            viaOnly = false;
             addedCaptionHeight = 0;
             currentReplyPhoto = null;
             currentUser = null;
@@ -4623,6 +4788,7 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe
             instantViewLayout = null;
             drawNameLayout = false;
             linkPreviewAbove = false;
+            isSmallImage = false;
             lastLoadingSizeTotal = 0;
             if (scheduledInvalidate) {
                 AndroidUtilities.cancelRunOnUIThread(invalidateRunnable);
@@ -5138,12 +5304,13 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe
                 }
 
                 setMessageObjectInternal(messageObject);
+                giveawayMessageCell.setMessageContent(messageObject, getParentWidth(), forwardedNameWidth);
 
                 backgroundWidth = messageObject.textWidth + getExtraTextX() * 2 + (hasGamePreview || hasInvoicePreview ? AndroidUtilities.dp(10) : 0);
                 totalHeight = messageObject.textHeight + AndroidUtilities.dp(19.5f) + namesOffset;
 
                 if (!reactionsLayoutInBubble.isSmall) {
-                    reactionsLayoutInBubble.measure(maxWidth, Gravity.LEFT);
+                    reactionsLayoutInBubble.measure(messageObject.isGiveaway() ? giveawayMessageCell.getMeasuredWidth() : maxWidth, Gravity.LEFT);
                     if (!reactionsLayoutInBubble.isEmpty) {
                         reactionsLayoutInBubble.totalHeight = reactionsLayoutInBubble.height + AndroidUtilities.dp(8);
                         if (reactionsLayoutInBubble.width > backgroundWidth) {
@@ -5172,8 +5339,6 @@ private void setMessageContent(MessageObject messageObject, MessageObject.Groupe
                 }
                 int maxWebWidth = 0;
 
-                giveawayMessageCell.setMessageContent(messageObject, getParentWidth(), forwardedNameWidth);
-
                 if (hasLinkPreview || hasGamePreview || hasInvoicePreview) {
                     int linkPreviewMaxWidth;
                     if (AndroidUtilities.isTablet()) {
@@ -8483,6 +8648,13 @@ public void invalidate() {
             replySelector.setState(new int[]{});
             invalidate();
         }
+        if (nameStatusSelector != null) {
+            nameStatusSelector.setState(StateSet.NOTHING);
+        }
+        if (nameLayoutSelector != null) {
+            nameLayoutSelector.setState(StateSet.NOTHING);
+        }
+        resetCodeSelectors();
         if (replyBounce != null) {
             replyBounce.setPressed(false);
         }
@@ -9036,6 +9208,7 @@ private void calcBackgroundWidth(int maxWidth, int timeMore, int maxChildWidth)
         if (
             currentMessageObject.hasCodeAtBottom && (reactionsLayoutInBubble.isEmpty || reactionsLayoutInBubble.isSmall) ||
             currentMessageObject.hasQuoteAtBottom && (reactionsLayoutInBubble.isEmpty || reactionsLayoutInBubble.isSmall)
+            || currentMessageObject.isGiveaway()
         ) {
             newLineForTime = true;
             newLineForTimeDp = 18;
@@ -9324,7 +9497,7 @@ public boolean setHighlightedSpan(CharacterStyle span) {
 
     @Override
     protected boolean verifyDrawable(Drawable who) {
-        return super.verifyDrawable(who) || who == selectorDrawable[0] || who == selectorDrawable[1] || who == linkPreviewSelector;
+        return super.verifyDrawable(who) || who == selectorDrawable[0] || who == selectorDrawable[1] || who == linkPreviewSelector || who == nameLayoutSelector || who == replySelector;
     }
 
     @Override
@@ -11857,6 +12030,7 @@ public void drawMessageText(float textX, float textY, Canvas canvas, ArrayList= 0) {
-            final float maxWidth;
-            if (caption) {
-                if (currentMessagesGroup != null) {
-                    float endX = textX - getExtraTextX();
-                    if (currentMessagesGroup != null && !currentMessageObject.isMusic() && !currentMessageObject.isDocument()) {
-                        int dWidth = getGroupPhotosWidth();
-                        if ((currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) == 0) {
-                            endX += Math.ceil(currentPosition.pw / 1000.0f * dWidth);
-                        } else {
-                            int firstLineWidth = 0;
-                            for (int i = 0; i < currentMessagesGroup.posArray.size(); i++) {
-                                MessageObject.GroupedMessagePosition position = currentMessagesGroup.posArray.get(i);
-                                if (position.minY == 0) {
-                                    firstLineWidth += Math.ceil((position.pw + position.leftSpanOffset) / 1000.0f * dWidth);
-                                } else {
-                                    break;
-                                }
-                            }
-                            endX += firstLineWidth - AndroidUtilities.dp(9);
-                        }
+            float right;
+            if (currentMessagesGroup == null || currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) != 0) {
+                right = getBackgroundDrawableRight() + transitionParams.deltaRight;
+            } else {
+                int end, dWidth;
+                if (AndroidUtilities.isTablet()) {
+                    dWidth = AndroidUtilities.getMinTabletSide();
+                } else {
+                    dWidth = getParentWidth();
+                }
+                int firstLineWidth = 0;
+                for (int a = 0; a < currentMessagesGroup.posArray.size(); a++) {
+                    MessageObject.GroupedMessagePosition position = currentMessagesGroup.posArray.get(a);
+                    if (position.minY == 0) {
+                        firstLineWidth += Math.ceil((position.pw + position.leftSpanOffset) / 1000.0f * dWidth);
                     } else {
-                        endX += backgroundWidth - (mediaBackground ? 0 : AndroidUtilities.dp(9));
-                    }
-                    if (currentPosition != null && (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) == 0 && !currentMessagesGroup.hasSibling) {
-                        endX += AndroidUtilities.dp(14);
+                        break;
                     }
-                    maxWidth = endX - textX - AndroidUtilities.dp(6 + 4 + (currentMessageObject.isOutOwner() && !drawPinnedBottom ? 6 : 0));
+                }
+                if (!mediaBackground && currentMessageObject.isOutOwner()) {
+                    end = backgroundDrawableLeft + firstLineWidth - AndroidUtilities.dp(6);
                 } else {
-                    maxWidth = captionFullWidth - AndroidUtilities.dp(3 + (currentMessageObject.isOutOwner() && !drawPinnedBottom ? 6 : 0)) - 2 * getExtraTextX();
+                    end = backgroundDrawableLeft + firstLineWidth;
                 }
-            } else {
-                maxWidth = getCurrentBackgroundRight() - AndroidUtilities.dp(11 + (currentMessageObject.isOutOwner() && !drawPinnedBottom ? 6 : 0)) - getExtraTextX() - textX;
+                end -= getExtraTextX() + AndroidUtilities.dp(8 + (isAvatarVisible ? 48 : 0));
+                right = end;
             }
+            right -= AndroidUtilities.dp(10 + (currentMessageObject.isOutOwner() && !mediaBackground && !drawPinnedBottom ? 6 : 0)) + getExtraTextX();
+            final float maxWidth = right - textX;
             int restore = Integer.MIN_VALUE;
             int oldAlpha = 0;
             int oldLinkAlpha = 0;
@@ -12024,7 +12194,8 @@ public void drawMessageText(float textX, float textY, Canvas canvas, ArrayList maxWidth * .7f ? maxWidth : block.maxRight + AndroidUtilities.dp(24));
-                    AndroidUtilities.rectTmp.set((block.isRtl() ? rtlOffset - AndroidUtilities.dp(10) : 0), -block.padTop + AndroidUtilities.dp(block.first ? 3 + 1.66f : 3), (block.isRtl() ? rtlOffset - AndroidUtilities.dp(10) : 0) + width, block.height + AndroidUtilities.dp(4));
+                    AndroidUtilities.rectTmp.set(0, -block.padTop + AndroidUtilities.dp(block.first ? 3 + 1.66f : 3), width, block.height + AndroidUtilities.dp(4));
+                    AndroidUtilities.rectTmp.offset((block.isRtl() ? rtlOffset - AndroidUtilities.dp(10) : 0), 0);
                     quoteLine.drawBackground(canvas, AndroidUtilities.rectTmp, 5, 5, 5, alpha);
                     quoteLine.drawLine(canvas, AndroidUtilities.rectTmp, alpha);
 
@@ -12035,10 +12206,10 @@ public void drawMessageText(float textX, float textY, Canvas canvas, ArrayList 0) {
+                            float wasBottom = AndroidUtilities.rectTmp.bottom;
+                            AndroidUtilities.rectTmp.bottom = AndroidUtilities.rectTmp.top + block.languageHeight;
+                            quoteLine.drawBackground(canvas, AndroidUtilities.rectTmp, 5, rightRad, 0, (Theme.isCurrentThemeDark() ? .60f : .80f) * alpha);
+                            AndroidUtilities.rectTmp.bottom = wasBottom;
+                        }
+                        quoteLine.drawLine(canvas, AndroidUtilities.rectTmp, alpha);
 
-                        AndroidUtilities.rectTmp.set(-AndroidUtilities.dp(4), -AndroidUtilities.dp(2), maxWidth + AndroidUtilities.dp(4), block.height + AndroidUtilities.dp(2));
-                        if (replyRoundRectPath == null) {
-                            replyRoundRectPath = new Path();
-                        } else {
-                            replyRoundRectPath.rewind();
-                        }
-                        if (replyBackgroundRadii == null) {
-                            replyBackgroundRadii = new float[8];
-                        }
-                        final int rad = dp(SharedConfig.bubbleRadius);
-                        final int nearRad = dp(Math.min(6, SharedConfig.bubbleRadius));
-                        final int defrad = dp(Math.min(5, SharedConfig.bubbleRadius));
-                        replyBackgroundRadii[0] = replyBackgroundRadii[1] = block.first && namesOffset <= 0 && !caption ? ((currentMessageObject.isOutOwner() || !pinnedTop) ? rad / 3f * 2f : nearRad) : defrad;
-                        replyBackgroundRadii[2] = replyBackgroundRadii[3] = block.first && namesOffset <= 0 && !caption ? ((!currentMessageObject.isOutOwner() || !pinnedTop) ? rad / 3f * 2f : nearRad) : defrad;
-                        replyBackgroundRadii[4] = replyBackgroundRadii[5] = replyBackgroundRadii[6] = replyBackgroundRadii[7] = defrad;
-                        replyRoundRectPath.addRoundRect(AndroidUtilities.rectTmp, replyBackgroundRadii, Path.Direction.CW);
-                        canvas.save();
-                        canvas.translate((block.isRtl() ? rtlOffset - (block.quote ? AndroidUtilities.dp(10) : 0) : 0), 0);
-                        canvas.drawPath(replyRoundRectPath, Theme.chat_msgCodeBgPaint);
-                        canvas.restore();
+                        if (block.hasCodeCopyButton) {
+                            block.drawCopyCodeButton(canvas, AndroidUtilities.rectTmp, quoteLine.getColor(), quoteLine.getBackgroundColor(), alpha);
+                        }
+
+                        canvas.translate(dp(10), 0);
+                        if (block.languageLayout != null) {
+                            block.languageLayout.ellipsize((int) (maxWidth - dp(8 + 4))).draw(canvas, 0, -dp(6) - block.languageHeight / 2f, quoteLine.getColor(), alpha);
+                        }
                     }
                 }
                 if (a == linkSelectionBlockNum && quoteHighlight == null && !urlPathSelection.isEmpty() && !drawOnlyText) {
@@ -13549,7 +13727,7 @@ private void updateCurrentUserAndChat() {
                 } else {
                     TLRPC.EncryptedChat echat = messagesController.getEncryptedChat(DialogObject.getEncryptedChatId(currentMessageObject.getDialogId()));
                     if (echat != null) {
-                        currentUser = messagesController.getUser(echat.participant_id);
+                        currentUser = messagesController.getUser(echat.user_id);
                     }
                 }
             } else if (DialogObject.isUserDialog(fromId) && !currentMessageObject.messageOwner.post) {
@@ -13668,9 +13846,14 @@ private void setMessageObjectInternal(MessageObject messageObject) {
                 if (currentNameString.length() > 0) {
                     SpannableStringBuilder stringBuilder = new SpannableStringBuilder(String.format("%s %s %s", nameStringFinal, viaBotString, viaUsername));
                     stringBuilder.setSpan(viaSpan1 = new TypefaceSpan(Typeface.DEFAULT, 0, color), nameStringFinal.length() + 1, nameStringFinal.length() + 1 + viaBotString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                    if (currentNameStatus != null) {
+                        viaNameWidth += dp(4 + 20 + 4);
+                        stringBuilder.setSpan(new DialogCell.FixedWidthSpan(dp(4 + 20 + 4)), nameStringFinal.length(), nameStringFinal.length() + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                    }
                     stringBuilder.setSpan(viaSpan2 = new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"), 0, color), nameStringFinal.length() + 2 + viaBotString.length(), stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                     nameStringFinal = stringBuilder;
                 } else {
+                    viaOnly = true;
                     SpannableStringBuilder stringBuilder = new SpannableStringBuilder(String.format("%s %s", viaBotString, viaUsername));
                     stringBuilder.setSpan(viaSpan1 = new TypefaceSpan(Typeface.DEFAULT, 0, color), 0, viaBotString.length() + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                     stringBuilder.setSpan(viaSpan2 = new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"), 0, color), 1 + viaBotString.length(), stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
@@ -13890,7 +14073,7 @@ protected void onClick() {
                 int maxWidth = getMaxNameWidth();
                 if (!messageObject.shouldDrawWithoutBackground()) {
                     maxWidth -= AndroidUtilities.dp(messageObject.isOutOwner() ? 20 : 10);
-                    if (messageObject.type != MessageObject.TYPE_TEXT) {
+                    if (messageObject.type != MessageObject.TYPE_TEXT || messageObject.needDrawShareButton()) {
                         maxWidth -= AndroidUtilities.dp(10);
                     }
                 } else if (messageObject.type == MessageObject.TYPE_ROUND_VIDEO) {
@@ -13989,8 +14172,11 @@ protected void onClick() {
                     if (DialogObject.isEncryptedDialog(messageObject.getDialogId())) {
                         if (messageObject.replyMessageObject != null && messageObject.replyMessageObject.isOutOwner()) {
                             name = UserObject.getUserName(UserConfig.getInstance(currentAccount).getCurrentUser());
-                        } else if (currentUser != null) {
-                            name = UserObject.getUserName(currentUser);
+                        } else {
+                            TLRPC.EncryptedChat echat = MessagesController.getInstance(currentAccount).getEncryptedChat(DialogObject.getEncryptedChatId(currentMessageObject.getDialogId()));
+                            if (echat != null) {
+                                name = UserObject.getUserName(MessagesController.getInstance(currentAccount).getUser(echat.user_id));
+                            }
                         }
                     } else if (hasReplyQuote && !DialogObject.isEncryptedDialog(messageObject.getDialogId())) {
                         name = messageObject.getReplyQuoteNameWithIcon();
@@ -15290,9 +15476,9 @@ public void drawOutboundsContent(Canvas canvas) {
                 nx = nameX;
             }
             currentNameStatusDrawable.setBounds(
-                (int) (Math.abs(nx) + nameLayoutWidth + AndroidUtilities.dp(2)),
+                (int) (Math.abs(nx) + (viaNameWidth > 0 ? viaNameWidth - dp(4 + 28) : nameLayoutWidth) + AndroidUtilities.dp(2)),
                 (int) (nameY + nameLayout.getHeight() / 2 - AndroidUtilities.dp(10)),
-                (int) (Math.abs(nx) + nameLayoutWidth + AndroidUtilities.dp(22)),
+                (int) (Math.abs(nx) + (viaNameWidth > 0 ? viaNameWidth - dp(4 + 28) : nameLayoutWidth) + AndroidUtilities.dp(22)),
                 (int) (nameY + nameLayout.getHeight() / 2 + AndroidUtilities.dp(10))
             );
             currentNameStatusDrawable.setColor(ColorUtils.setAlphaComponent(color, 115));
@@ -15828,6 +16014,40 @@ public void drawNamesLayout(Canvas canvas, float alpha) {
             } else {
                 nx = nameX;
             }
+
+            if (!currentMessageObject.isSponsored()) {
+                int selectorColor = Theme.multAlpha(Theme.chat_namePaint.getColor(), .12f);
+                if (nameLayoutSelector == null) {
+                    nameLayoutSelector = Theme.createRadSelectorDrawable(nameLayoutSelectorColor = selectorColor, 6, 6);
+                    nameLayoutSelector.setCallback(this);
+                } else if (nameLayoutSelectorColor != selectorColor) {
+                    Theme.setSelectorDrawableColor(nameLayoutSelector, nameLayoutSelectorColor = selectorColor, true);
+                }
+                nameLayoutSelector.setBounds(
+                    (int) (nx - dp(4)),
+                    (int) (nameY - dp(1.33f)),
+                    (int) (nx + (viaNameWidth > 0 ? viaNameWidth - dp(4 + 28) : nameLayoutWidth) + dp(4)),
+                    (int) (nameY + nameLayout.getHeight() + dp(1.33f))
+                );
+                nameLayoutSelector.draw(canvas);
+
+                if (currentNameStatus != null) {
+                    if (nameStatusSelector == null) {
+                        nameStatusSelector = Theme.createRadSelectorDrawable(nameStatusSelectorColor = selectorColor, 6, 6);
+                        nameStatusSelector.setCallback(this);
+                    } else if (nameStatusSelectorColor != selectorColor) {
+                        Theme.setSelectorDrawableColor(nameStatusSelector, nameStatusSelectorColor = selectorColor, true);
+                    }
+                    nameStatusSelector.setBounds(
+                        (int) (nx + (viaNameWidth > 0 ? viaNameWidth - dp(4 + 28) : nameLayoutWidth)),
+                        (int) (nameY - dp(1.33f + 2)),
+                        (int) (nx + (viaNameWidth > 0 ? viaNameWidth - dp(4 + 28) : nameLayoutWidth) + dp(4 + 12 + 4 + 4)),
+                        (int) (nameY + nameLayout.getHeight() + dp(1.33f + 2))
+                    );
+                    nameStatusSelector.draw(canvas);
+                }
+            }
+
             canvas.translate(nx, nameY);
             nameLayout.draw(canvas);
             canvas.restore();
@@ -16353,7 +16573,7 @@ public void drawNamesLayout(Canvas canvas, float alpha) {
                 if (needReplyImage) {
                     replyImageReceiver.setAlpha(replyForwardAlpha);
                     replyImageSz = Math.min(replySelectorRect.height() - AndroidUtilities.dp(10), AndroidUtilities.dp(isReplyQuote ? 3 : 7) + Theme.chat_replyNamePaint.getTextSize() + Theme.chat_replyTextPaint.getTextSize());
-                    replyImageReceiver.setImageCoords(replySelectorRect.left + AndroidUtilities.dp(8), replySelectorRect.top + AndroidUtilities.dp(5), replyImageSz, replyImageSz);
+                    replyImageReceiver.setImageCoords(replySelectorRect.left + AndroidUtilities.dp(8), replySelectorRect.top + AndroidUtilities.dp((isReplyQuote && replyTextLayout != null && replyTextLayout.getLineCount() <= 1 ? 2 : 0) + 5), replyImageSz, replyImageSz);
                     replyImageReceiver.draw(canvas);
 
                     if (currentMessageObject != null && currentMessageObject.hasValidReplyMessageObject() && currentMessageObject.replyMessageObject.hasMediaSpoilers()) {
@@ -16421,7 +16641,7 @@ public void drawNamesLayout(Canvas canvas, float alpha) {
                     if (needReplyImage && (!isReplyQuote || replyTextRTL)) {
                         left += replyImageSz + AndroidUtilities.dp(3);
                     }
-                    if (replyTextRTL) {
+                    if (replyTextRTL && transitionParams.animateReplyTextOffset > 0) {
                         left = replySelectorRect.right - AndroidUtilities.dp(8) - transitionParams.animateReplyTextLayout.getWidth();
                     }
                     canvas.translate(left, replyStartY + offsetY - AndroidUtilities.dp(1) + Theme.chat_replyNamePaint.getTextSize() + AndroidUtilities.dp(5));
@@ -16442,7 +16662,7 @@ public void drawNamesLayout(Canvas canvas, float alpha) {
                     if (needReplyImage && (!isReplyQuote || replyTextRTL)) {
                         left += replyImageSz + AndroidUtilities.dp(3);
                     }
-                    if (replyTextRTL) {
+                    if (replyTextRTL && replyTextOffset > 0) {
                         left = replySelectorRect.right - AndroidUtilities.dp(8) - replyTextLayout.getWidth();
                     }
                     canvas.translate(left, replyStartY + offsetY - AndroidUtilities.dp(1) + Theme.chat_replyNamePaint.getTextSize() + AndroidUtilities.dp(5));
@@ -21080,4 +21300,12 @@ private ColorMatrixColorFilter getFancyBlurFilter() {
         }
         return fancyBlurFilter;
     }
+
+    public int getNameStatusX() {
+        return (int) (nameX + (viaNameWidth > 0 ? viaNameWidth - dp(4 + 28) : nameLayoutWidth) + dp(2) + dp(4 + 12 + 4) / 2);
+    }
+
+    public int getNameStatusY() {
+        return (int) (nameY + (nameLayout == null ? 0 : nameLayout.getHeight()) / 2);
+    }
 }
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 6297cfaad8..e1a9da2467 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java
@@ -2182,6 +2182,15 @@ public void buildLayout() {
 
         try {
             CharSequence messageStringFinal;
+            // Removing links and bold spans to get rid of underlining and boldness
+            if (messageString instanceof Spannable) {
+                Spannable messageStringSpannable = (Spannable) messageString;
+                for (Object span : messageStringSpannable.getSpans(0, messageStringSpannable.length(), Object.class)) {
+                    if (span instanceof ClickableSpan || span instanceof CodeHighlighting.Span || span instanceof CodeHighlighting.ColorSpan || span instanceof QuoteSpan || span instanceof QuoteSpan.QuoteStyleSpan || (span instanceof StyleSpan && ((StyleSpan) span).getStyle() == android.graphics.Typeface.BOLD)) {
+                        messageStringSpannable.removeSpan(span);
+                    }
+                }
+            }
             if ((useForceThreeLines || SharedConfig.useThreeLinesLayout) && currentDialogFolderId != 0 && currentDialogFolderDialogsCount > 1) {
                 messageStringFinal = messageNameString;
                 messageNameString = null;
@@ -2195,15 +2204,6 @@ public void buildLayout() {
             } else {
                 messageStringFinal = messageString;
             }
-            // Removing links and bold spans to get rid of underlining and boldness
-            if (messageStringFinal instanceof Spannable) {
-                Spannable messageStringSpannable = (Spannable) messageStringFinal;
-                for (Object span : messageStringSpannable.getSpans(0, messageStringSpannable.length(), Object.class)) {
-                    if (span instanceof ClickableSpan || span instanceof CodeHighlighting.Span || span instanceof CodeHighlighting.ColorSpan || span instanceof QuoteSpan || span instanceof QuoteSpan.QuoteStyleSpan || (span instanceof StyleSpan && ((StyleSpan) span).getStyle() == android.graphics.Typeface.BOLD)) {
-                        messageStringSpannable.removeSpan(span);
-                    }
-                }
-            }
 
             Layout.Alignment align = isForum && LocaleController.isRTL ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_NORMAL;
             if (useForceThreeLines || SharedConfig.useThreeLinesLayout) {
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/RecurrentPaymentsAcceptCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/RecurrentPaymentsAcceptCell.java
index 27d397506c..b34c7f7412 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/RecurrentPaymentsAcceptCell.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/RecurrentPaymentsAcceptCell.java
@@ -46,6 +46,10 @@ public TextView getTextView() {
         return textView;
     }
 
+    public CheckBoxSquare getCheckBox() {
+        return checkBox;
+    }
+
     public void setText(CharSequence text) {
         textView.setText(text);
     }
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java
index 3c48eb55e5..39d933783f 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java
@@ -1,6 +1,7 @@
 package org.telegram.ui.Cells;
 
 import static com.google.zxing.common.detector.MathUtils.distance;
+import static org.telegram.messenger.AndroidUtilities.dp;
 import static org.telegram.ui.ActionBar.FloatingToolbar.STYLE_THEME;
 import static org.telegram.ui.ActionBar.Theme.key_chat_inTextSelectionHighlight;
 
@@ -168,7 +169,7 @@ public void run() {
             if (scrolling && (parentRecyclerView != null || parentNestedScrollView != null)) {
                 int dy;
                 if (multiselect && selectedView == null) {
-                    dy = AndroidUtilities.dp(8);
+                    dy = dp(8);
                 } else if (selectedView != null) {
                     dy = getLineHeight() >> 1;
                 } else {
@@ -230,7 +231,7 @@ public void run() {
                 }
                 int endLine = layoutBlock.layout.getLineCount() - 1;
                 x -= maybeTextX;
-                if (x < layoutBlock.layout.getLineRight(endLine) + AndroidUtilities.dp(4) && x > layoutBlock.layout.getLineLeft(endLine)) {
+                if (x < layoutBlock.layout.getLineRight(endLine) + dp(4) && x > layoutBlock.layout.getLineLeft(endLine)) {
                     offset = text.length() - 1;
                 }
             }
@@ -319,7 +320,7 @@ public void run() {
     public TextSelectionHelper() {
         longpressDelay = ViewConfiguration.getLongPressTimeout();
         touchSlop = ViewConfiguration.get(ApplicationLoader.applicationContext).getScaledTouchSlop();
-        selectionPaint.setPathEffect(new CornerPathEffect(cornerRadius = AndroidUtilities.dp(6)));
+        selectionPaint.setPathEffect(new CornerPathEffect(cornerRadius = dp(6)));
     }
 
     public void setInvalidateParent() {
@@ -359,9 +360,9 @@ public boolean onTouchEvent(MotionEvent event) {
                 capturedX = (int) event.getX();
                 capturedY = (int) event.getY();
                 tryCapture = false;
-                textArea.inset(-AndroidUtilities.dp(8), -AndroidUtilities.dp(8));
+                textArea.inset(-dp(8), -dp(8));
                 if (textArea.contains(capturedX, capturedY) && maybeSelectedView != null) {
-                    textArea.inset(AndroidUtilities.dp(8), AndroidUtilities.dp(8));
+                    textArea.inset(dp(8), dp(8));
                     int x = capturedX;
                     int y = capturedY;
                     if (x > textArea.right) x = textArea.right - 1;
@@ -379,7 +380,7 @@ public boolean onTouchEvent(MotionEvent event) {
                         }
                         int endLine = layoutBlock.layout.getLineCount() - 1;
                         x -= maybeTextX;
-                        if (x < layoutBlock.layout.getLineRight(endLine) + AndroidUtilities.dp(4) && x > layoutBlock.layout.getLineLeft(endLine)) {
+                        if (x < layoutBlock.layout.getLineRight(endLine) + dp(4) && x > layoutBlock.layout.getLineLeft(endLine)) {
                             offset = text.length() - 1;
                         }
                     }
@@ -432,11 +433,11 @@ private void showMagnifier(int x) {
                 return;
             }
 
-            int line = layout.getLineForOffset(offset);
+            int line = layout.getLineForOffset(Utilities.clamp(offset - layoutBlock.charOffset, layout.getText().length(), 0));
 
             int lineHeight = layout.getLineBottom(line) - layout.getLineTop(line);
             int[] coordsInParent = getCoordsInParent();
-            int newY = (int) (layout.getLineTop(line) + textY + coordsInParent[1]) - lineHeight - AndroidUtilities.dp(8);
+            int newY = (int) (layout.getLineTop(line) + textY + coordsInParent[1]) - lineHeight - dp(8);
             newY += layoutBlock.yOffset;
 
             int startLine;
@@ -490,7 +491,7 @@ private void showMagnifier(int x) {
             }
 
             magnifier.show(
-                magnifierXanimated, magnifierYanimated + lineHeight * 1.5f + AndroidUtilities.dp(8)
+                magnifierXanimated, magnifierYanimated + lineHeight * 1.5f + dp(8)
             );
             magnifier.update();
         }
@@ -556,7 +557,7 @@ private void showActions() {
                     if (popupLayout == null) {
                         popupRect = new android.graphics.Rect();
                         popupLayout = new ActionBarPopupWindow.ActionBarPopupWindowLayout(textSelectionOverlay.getContext());
-                        popupLayout.setPadding(AndroidUtilities.dp(1), AndroidUtilities.dp(1), AndroidUtilities.dp(1), AndroidUtilities.dp(1));
+                        popupLayout.setPadding(dp(1), dp(1), dp(1), dp(1));
                         popupLayout.setBackgroundDrawable(textSelectionOverlay.getContext().getResources().getDrawable(R.drawable.menu_copy));
                         popupLayout.setAnimationEnabled(false);
                         popupLayout.setOnTouchListener((v, event) -> {
@@ -572,7 +573,7 @@ private void showActions() {
                         deleteView = new TextView(textSelectionOverlay.getContext());
                         deleteView.setBackgroundDrawable(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector), 2));
                         deleteView.setGravity(Gravity.CENTER_VERTICAL);
-                        deleteView.setPadding(AndroidUtilities.dp(20), 0, AndroidUtilities.dp(20), 0);
+                        deleteView.setPadding(dp(20), 0, dp(20), 0);
                         deleteView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
                         deleteView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
                         deleteView.setText(textSelectionOverlay.getContext().getString(android.R.string.copy));
@@ -597,11 +598,11 @@ private void showActions() {
                         int lineHeight = -getLineHeight();
                         int[] coords = offsetToCord(selectionStart);
                         int[] coordsInParent = getCoordsInParent();
-                        y = (int) (coords[1] + textY + coordsInParent[1]) + lineHeight / 2 - AndroidUtilities.dp(4);
+                        y = (int) (coords[1] + textY + coordsInParent[1]) + lineHeight / 2 - dp(4);
                         if (y < 0) y = 0;
                     }
 
-                    popupWindow.showAtLocation(textSelectionOverlay, Gravity.TOP, 0, y - AndroidUtilities.dp(48));
+                    popupWindow.showAtLocation(textSelectionOverlay, Gravity.TOP, 0, y - dp(48));
                     popupWindow.startAnimation();
                 }
             }
@@ -1129,7 +1130,7 @@ public boolean onTouchEvent(MotionEvent event) {
         @Override
         protected void onDraw(Canvas canvas) {
             if (!isInSelectionMode()) return;
-            int handleViewSize = AndroidUtilities.dp(22);
+            int handleViewSize = dp(22);
 
             int count = 0;
             int top = topOffset;
@@ -1182,7 +1183,7 @@ protected void onDraw(Canvas canvas) {
                                         xOffset + x, yOffset + y - handleViewSize,
                                         xOffset + x + handleViewSize, yOffset + y + handleViewSize
                                 );
-                                endArea.inset(-AndroidUtilities.dp(8), -AndroidUtilities.dp(8));
+                                endArea.inset(-dp(8), -dp(8));
                                 count++;
                             } else {
                                 canvas.save();
@@ -1198,7 +1199,7 @@ protected void onDraw(Canvas canvas) {
                                         xOffset + x - handleViewSize, yOffset + y - handleViewSize,
                                         xOffset + x, yOffset + y + handleViewSize
                                 );
-                                endArea.inset(-AndroidUtilities.dp(8), -AndroidUtilities.dp(8));
+                                endArea.inset(-dp(8), -dp(8));
                             }
                         } else {
                             endArea.setEmpty();
@@ -1244,7 +1245,7 @@ protected void onDraw(Canvas canvas) {
                                         xOffset + x - handleViewSize, yOffset + y - handleViewSize,
                                         xOffset + x, yOffset + y + handleViewSize
                                 );
-                                startArea.inset(-AndroidUtilities.dp(8), -AndroidUtilities.dp(8));
+                                startArea.inset(-dp(8), -dp(8));
                                 count++;
                             } else {
                                 canvas.save();
@@ -1260,7 +1261,7 @@ protected void onDraw(Canvas canvas) {
                                         xOffset + x, yOffset + y - handleViewSize,
                                         xOffset + x + handleViewSize, yOffset + y + handleViewSize
                                 );
-                                startArea.inset(-AndroidUtilities.dp(8), -AndroidUtilities.dp(8));
+                                startArea.inset(-dp(8), -dp(8));
                             }
                         } else {
                             if (y + yOffset > 0 && y + yOffset - getLineHeight() < parentView.getMeasuredHeight()) {
@@ -1546,7 +1547,7 @@ public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
                         int lineHeight = -getLineHeight();
                         int[] coords = offsetToCord(selectionStart);
                         x1 = coords[0] + textX;
-                        y1 = (int) (coords[1] + textY + coordsInParent[1]) + lineHeight / 2 - AndroidUtilities.dp(4);
+                        y1 = (int) (coords[1] + textY + coordsInParent[1]) + lineHeight / 2 - dp(4);
                         if (y1 < 1) y1 = 1;
                     }
 
@@ -2077,7 +2078,13 @@ public void draw(MessageObject messageObject, MessageObject.TextLayoutBlock bloc
                         selectionPaint.setColor(getThemedColor(key_chat_inTextSelectionHighlight));
                         selectionHandlePaint.setColor(getThemedColor(key_chat_inTextSelectionHighlight));
                     }
-                    drawSelection(canvas, block.textLayout, selectionStart, selectionEnd, true, true, block.quote ? AndroidUtilities.dp(10) : 0);
+                    int offsetX = 0;
+                    if (block.quote) {
+                        offsetX = dp(10);
+                    } else if (block.code) {
+                        offsetX = dp(0);
+                    }
+                    drawSelection(canvas, block.textLayout, selectionStart, selectionEnd, true, true, offsetX);
                 }
             }
         }
@@ -2103,7 +2110,13 @@ public void drawCaption(MessageObject messageObject, MessageObject.TextLayoutBlo
                     selectionPaint.setColor(getThemedColor(key_chat_inTextSelectionHighlight));
                     selectionHandlePaint.setColor(getThemedColor(key_chat_inTextSelectionHighlight));
                 }
-                drawSelection(canvas, block.textLayout, selectionStart, selectionEnd, true, true, block.quote ? AndroidUtilities.dp(10) : 0);
+                int offsetX = 0;
+                if (block.quote) {
+                    offsetX = dp(10);
+                } else if (block.code) {
+                    offsetX = dp(0);
+                }
+                drawSelection(canvas, block.textLayout, selectionStart, selectionEnd, true, true, offsetX);
             }
         }
 
@@ -2186,7 +2199,14 @@ private void fillLayoutForCoords(int x, int y, ChatMessageCell cell, LayoutBlock
                     if (y >= block.textYOffset && y <= block.textYOffset + block.padTop + block.height) {
                         layoutBlock.layout = block.textLayout;
                         layoutBlock.yOffset = block.textYOffset + block.padTop;
-                        layoutBlock.xOffset = -(block.isRtl() ? (int) Math.ceil(captionLayout.textXOffset) - (block.quote ? AndroidUtilities.dp(10) : 0) : 0);
+                        int offsetX = 0;
+                        if (block.quote) {
+                            offsetX = dp(10);
+                        }
+                        layoutBlock.xOffset = -(block.isRtl() ? (int) Math.ceil(captionLayout.textXOffset) - offsetX : 0);
+                        if (block.code && !block.quote) {
+                            layoutBlock.xOffset += dp(8);
+                        }
                         layoutBlock.charOffset = block.charactersOffset;
                         return;
                     }
@@ -2199,7 +2219,16 @@ private void fillLayoutForCoords(int x, int y, ChatMessageCell cell, LayoutBlock
                 if (y >= block.textYOffset && y <= block.textYOffset + block.padTop + block.height) {
                     layoutBlock.layout = block.textLayout;
                     layoutBlock.yOffset = block.textYOffset + block.padTop;
-                    layoutBlock.xOffset = -(block.isRtl() ? (int) Math.ceil(messageObject.textXOffset) - (block.quote ? AndroidUtilities.dp(10) : 0) : 0);
+                    int offsetX = 0;
+                    if (block.quote) {
+                        offsetX = dp(10);
+                    } else if (block.code) {
+                        offsetX = dp(0);
+                    }
+                    layoutBlock.xOffset = -(block.isRtl() ? (int) Math.ceil(messageObject.textXOffset) - offsetX : 0);
+                    if (block.code && !block.quote) {
+                        layoutBlock.xOffset += dp(8);
+                    }
                     layoutBlock.charOffset = block.charactersOffset;
                     return;
                 }
@@ -2225,9 +2254,18 @@ protected void fillLayoutForOffset(int offset, LayoutBlock layoutBlock, boolean
             if (selectedView.hasCaptionLayout()) {
                 MessageObject.TextLayoutBlocks captionLayout = selectedView.getCaptionLayout();
                 if (captionLayout.textLayoutBlocks.size() == 1) {
-                    layoutBlock.layout = captionLayout.textLayoutBlocks.get(0).textLayout;
-                    layoutBlock.yOffset = 0;
-                    layoutBlock.xOffset = -(captionLayout.textLayoutBlocks.get(0).isRtl() ? (int) Math.ceil(captionLayout.textXOffset) - (captionLayout.textLayoutBlocks.get(0).quote ? AndroidUtilities.dp(10) : 0) : 0);
+                    MessageObject.TextLayoutBlock block = captionLayout.textLayoutBlocks.get(0);
+                    layoutBlock.layout = block.textLayout;
+                    layoutBlock.yOffset = block.padTop;
+                    MessageObject.TextLayoutBlock firstBlock = captionLayout.textLayoutBlocks.get(0);
+                    int offsetX = 0;
+                    if (firstBlock.quote) {
+                        offsetX = dp(10);
+                    }
+                    layoutBlock.xOffset = -(firstBlock.isRtl() ? (int) Math.ceil(captionLayout.textXOffset) - offsetX : 0);
+                    if (firstBlock.code && !firstBlock.quote) {
+                        layoutBlock.xOffset += dp(8);
+                    }
                     layoutBlock.charOffset = 0;
                     return;
                 }
@@ -2238,7 +2276,14 @@ protected void fillLayoutForOffset(int offset, LayoutBlock layoutBlock, boolean
                     if (blockOffset >= 0 && blockOffset <= block.textLayout.getText().length()) {
                         layoutBlock.layout = block.textLayout;
                         layoutBlock.yOffset = block.textYOffset + block.padTop;
-                        layoutBlock.xOffset = -(block.isRtl() ? (int) Math.ceil(captionLayout.textXOffset) - (block.quote ? AndroidUtilities.dp(10) : 0) : 0);
+                        int offsetX = 0;
+                        if (block.quote) {
+                            offsetX = dp(10);
+                        }
+                        layoutBlock.xOffset = -(block.isRtl() ? (int) Math.ceil(captionLayout.textXOffset) - offsetX : 0);
+                        if (block.code && !block.quote) {
+                            layoutBlock.xOffset += dp(8);
+                        }
                         layoutBlock.charOffset = block.charactersOffset;
                         return;
                     }
@@ -2253,9 +2298,18 @@ protected void fillLayoutForOffset(int offset, LayoutBlock layoutBlock, boolean
             }
 
             if (messageObject.textLayoutBlocks.size() == 1) {
-                layoutBlock.layout = messageObject.textLayoutBlocks.get(0).textLayout;
-                layoutBlock.yOffset = 0;
-                layoutBlock.xOffset = -(messageObject.textLayoutBlocks.get(0).isRtl() ? (int) Math.ceil(messageObject.textXOffset) - (messageObject.textLayoutBlocks.get(0).quote ? AndroidUtilities.dp(10) : 0) : 0);
+                MessageObject.TextLayoutBlock textLayoutBlock = messageObject.textLayoutBlocks.get(0);
+                layoutBlock.layout = textLayoutBlock.textLayout;
+                layoutBlock.yOffset = textLayoutBlock.padTop;
+                MessageObject.TextLayoutBlock firstBlock = messageObject.textLayoutBlocks.get(0);
+                int offsetX = 0;
+                if (firstBlock.quote) {
+                    offsetX = dp(10);
+                }
+                layoutBlock.xOffset = -(firstBlock.isRtl() ? (int) Math.ceil(messageObject.textXOffset) - offsetX : 0);
+                if (firstBlock.code && !firstBlock.quote) {
+                    layoutBlock.xOffset += dp(8);
+                }
                 layoutBlock.charOffset = 0;
                 return;
             }
@@ -2266,7 +2320,14 @@ protected void fillLayoutForOffset(int offset, LayoutBlock layoutBlock, boolean
                 if (blockOffset >= 0 && blockOffset <= block.textLayout.getText().length()) {
                     layoutBlock.layout = block.textLayout;
                     layoutBlock.yOffset = block.textYOffset + block.padTop;
-                    layoutBlock.xOffset = -(block.isRtl() ? (int) Math.ceil(messageObject.textXOffset) - (block.quote ? AndroidUtilities.dp(10) : 0) : 0);
+                    int offsetX = 0;
+                    if (block.quote) {
+                        offsetX = dp(10);
+                    }
+                    layoutBlock.xOffset = -(block.isRtl() ? (int) Math.ceil(messageObject.textXOffset) - offsetX : 0);
+                    if (block.code && !block.quote) {
+                        layoutBlock.xOffset += dp(8);
+                    }
                     layoutBlock.charOffset = block.charactersOffset;
                     return;
                 }
@@ -2592,7 +2653,7 @@ private int findClosestLayoutIndex(int x, int y, ArticleSelectableView maybeSele
                 int row = arrayList.get(minIndex).getRow();
 
                 if (row > 0) {
-                    if (minDistance < AndroidUtilities.dp(24)) {
+                    if (minDistance < dp(24)) {
                         int minDistanceX = Integer.MAX_VALUE;
                         int minIndexX = minIndex;
 
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelBoostLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelBoostLayout.java
index 3ef7b9c672..9d2cb29566 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelBoostLayout.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelBoostLayout.java
@@ -289,8 +289,8 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi
                 ItemInternal item = items.get(position);
                 TL_stories.TL_prepaidGiveaway prepaidGiveaway = item.prepaidGiveaway;
                 GiveawayCell giveawayCell = (GiveawayCell) holder.itemView;
-                String name = LocaleController.formatString("TelegramPremiumCount", R.string.TelegramPremiumCount, prepaidGiveaway.quantity);
-                String info = LocaleController.formatString("SubscriptionsCount", R.string.SubscriptionsCount, LocaleController.formatPluralString("GiftMonths", prepaidGiveaway.months));
+                String name = LocaleController.formatPluralString("BoostingTelegramPremiumCountPlural", prepaidGiveaway.quantity);
+                String info = LocaleController.formatPluralString("BoostingSubscriptionsCountPlural", prepaidGiveaway.quantity, LocaleController.formatPluralString("PrepaidGiveawayMonths", prepaidGiveaway.months));
                 giveawayCell.setData(prepaidGiveaway, name, info, 0, !item.isLast);
                 giveawayCell.setImage(prepaidGiveaway);
                 giveawayCell.setAvatarPadding(5);
@@ -352,6 +352,7 @@ public ChannelBoostLayout(BaseFragment fragment, long dialogId, Theme.ResourcesP
                     giftCode.months = (boost.expires - boost.date) / 30 / 86400;
                     if (boost.unclaimed) {
                         giftCode.to_id = NO_USER_ID;
+                        giftCode.flags = -1;
                     } else {
                         giftCode.boost = boost;
                     }
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java
index 775c845ba9..9cb43aab0e 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java
@@ -138,12 +138,14 @@
 import org.telegram.messenger.CodeHighlighting;
 import org.telegram.messenger.ContactsController;
 import org.telegram.messenger.DialogObject;
+import org.telegram.messenger.DocumentObject;
 import org.telegram.messenger.DownloadController;
 import org.telegram.messenger.Emoji;
 import org.telegram.messenger.EmojiData;
 import org.telegram.messenger.FileLoader;
 import org.telegram.messenger.FileLog;
 import org.telegram.messenger.FlagSecureReason;
+import org.telegram.messenger.ImageLoader;
 import org.telegram.messenger.ImageLocation;
 import org.telegram.messenger.ImageReceiver;
 //import org.telegram.messenger.LanguageDetector;
@@ -161,6 +163,8 @@
 import org.telegram.messenger.SecretChatHelper;
 import org.telegram.messenger.SendMessagesHelper;
 import org.telegram.messenger.SharedConfig;
+import org.telegram.messenger.SvgHelper;
+import org.telegram.messenger.TranslateController;
 import org.telegram.messenger.UserConfig;
 import org.telegram.messenger.UserObject;
 import org.telegram.messenger.Utilities;
@@ -9479,7 +9483,7 @@ private void updateChatListViewTopPadding() {
         float pendingViewH = 0;
         View pendingRequestsView = pendingRequestsDelegate != null ? pendingRequestsDelegate.getView() : null;
         if (pendingRequestsView != null && pendingRequestsView.getVisibility() == View.VISIBLE) {
-            pendingViewH = Math.max(0, pendingRequestsView.getHeight() + pendingRequestsDelegate.getViewEnterOffset());
+            pendingViewH = Math.max(0, pendingRequestsView.getHeight() + pendingRequestsDelegate.getViewEnterOffset() - AndroidUtilities.dp(4));
         }
         float oldPadding = chatListViewPaddingTop;
         chatListViewPaddingTop = AndroidUtilities.dp(4) + contentPaddingTop + topPanelViewH + pinnedViewH + pendingViewH;
@@ -11463,7 +11467,7 @@ public void startDocumentSelectActivity() {
 
     @Override
     public boolean dismissDialogOnPause(Dialog dialog) {
-        return dialog != chatAttachAlert && dialog != chatThemeBottomSheet && super.dismissDialogOnPause(dialog);
+        return dialog != chatAttachAlert && dialog != chatThemeBottomSheet && !(dialog instanceof BotWebViewSheet) && super.dismissDialogOnPause(dialog);
     }
 
     private boolean disableLinkPreview = NekoConfig.disableLinkPreviewByDefault.Bool();
@@ -29575,6 +29579,9 @@ private void didPressMessageUrl(CharacterStyle url, boolean longPress, MessageOb
                 if (!messageObject.isMusic() && messageObject.replyMessageObject != null) {
                     messageObject = messagesDict[messageObject.replyMessageObject.getDialogId() == dialog_id ? 0 : 1].get(messageObject.replyMessageObject.getId());
                 }
+                if (messageObject == null) {
+                    return;
+                }
                 float progress = seekTime / (float) messageObject.getDuration();
                 MediaController mediaController = getMediaController();
                 if (mediaController.isPlayingMessage(messageObject)) {
@@ -31364,6 +31371,69 @@ public void didPressSponsoredClose() {
             showDialog(new PremiumFeatureBottomSheet(ChatActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_ADS, true));
         }
 
+        @Override
+        public void didPressUserStatus(ChatMessageCell cell, TLRPC.User user, TLRPC.Document document) {
+            if (cell == null) {
+                return;
+            }
+            PremiumPreviewBottomSheet premiumPreviewBottomSheet = new PremiumPreviewBottomSheet(ChatActivity.this, currentAccount, user, themeDelegate);
+            int[] coords = new int[2];
+            cell.getLocationOnScreen(coords);
+            premiumPreviewBottomSheet.startEnterFromX = cell.getNameStatusX();
+            premiumPreviewBottomSheet.startEnterFromY = cell.getNameStatusY();
+            premiumPreviewBottomSheet.startEnterFromScale = cell.getScaleX();
+            premiumPreviewBottomSheet.startEnterFromX1 = cell.getLeft();
+            premiumPreviewBottomSheet.startEnterFromY1 = cell.getTop();
+            premiumPreviewBottomSheet.startEnterFromView = cell;
+            int colorId = user != null ? (int) (user.id % 7) : 0;
+            if (user != null && (user.flags2 & 128) != 0) {
+                colorId = user.color;
+            }
+            if (colorId < 7) {
+                premiumPreviewBottomSheet.accentColor = getThemedColor(Theme.keys_avatar_nameInMessage[colorId]);
+            } else {
+                final MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors;
+                final MessagesController.PeerColor peerColor = peerColors != null ? peerColors.getColor(colorId) : null;
+                premiumPreviewBottomSheet.accentColor = peerColor != null ? peerColor.getColor1() : null;
+            }
+            if (cell.currentNameStatusDrawable != null && cell.currentNameStatusDrawable.getDrawable() instanceof AnimatedEmojiDrawable) {
+                premiumPreviewBottomSheet.startEnterFromScale *= 0.95f;
+                if (document != null) {
+                    BackupImageView icon = new BackupImageView(getContext());
+                    String filter = "160_160";
+                    ImageLocation mediaLocation;
+                    String mediaFilter;
+                    SvgHelper.SvgDrawable thumbDrawable = DocumentObject.getSvgThumb(document.thumbs, Theme.key_windowBackgroundWhiteGrayIcon, 0.2f);
+                    TLRPC.PhotoSize thumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 90);
+                    if ("video/webm".equals(document.mime_type)) {
+                        mediaLocation = ImageLocation.getForDocument(document);
+                        mediaFilter = filter + "_" + ImageLoader.AUTOPLAY_FILTER;
+                        if (thumbDrawable != null) {
+                            thumbDrawable.overrideWidthAndHeight(512, 512);
+                        }
+                    } else {
+                        if (thumbDrawable != null && MessageObject.isAnimatedStickerDocument(document, false)) {
+                            thumbDrawable.overrideWidthAndHeight(512, 512);
+                        }
+                        mediaLocation = ImageLocation.getForDocument(document);
+                        mediaFilter = filter;
+                    }
+                    icon.setLayerNum(7);
+                    icon.setRoundRadius(AndroidUtilities.dp(4));
+                    icon.setImage(mediaLocation, mediaFilter, ImageLocation.getForDocument(thumb, document), "140_140", thumbDrawable, document);
+                    if (MessageObject.isTextColorEmoji(document)) {
+                        icon.setColorFilter(new PorterDuffColorFilter(premiumPreviewBottomSheet.accentColor != null ? premiumPreviewBottomSheet.accentColor : getThemedColor(Theme.key_windowBackgroundWhiteBlueIcon), PorterDuff.Mode.SRC_IN));
+                        premiumPreviewBottomSheet.statusStickerSet = MessageObject.getInputStickerSet(document);
+                    } else {
+                        premiumPreviewBottomSheet.statusStickerSet = MessageObject.getInputStickerSet(document);
+                    }
+                    premiumPreviewBottomSheet.overrideTitleIcon = icon;
+                    premiumPreviewBottomSheet.isEmojiStatus = true;
+                }
+            }
+            showDialog(premiumPreviewBottomSheet);
+        }
+
         @Override
         public void didPressUserAvatar(ChatMessageCell cell, TLRPC.User user, float touchX, float touchY) {
             if (actionBar.isActionModeShowed() || reportType >= 0) {
@@ -31520,7 +31590,11 @@ private void openDialog(ChatMessageCell cell, TLRPC.User user) {
 
         private void openChat(ChatMessageCell cell, TLRPC.Chat chat, int postId) {
             if (currentChat != null && chat.id == currentChat.id) {
-                scrollToMessageId(postId, cell.getMessageObject().getId(), true, 0, true, 0);
+                if (avatarContainer != null && postId == 0) {
+                    avatarContainer.openProfile(false);
+                } else {
+                    scrollToMessageId(postId, cell.getMessageObject().getId(), true, 0, true, 0);
+                }
             } else if (currentChat == null || chat.id != currentChat.id || isThreadChat()) {
                 Bundle args = new Bundle();
                 args.putLong("chat_id", chat.id);
@@ -31823,16 +31897,16 @@ public void didPressUrl(ChatMessageCell cell, final CharacterStyle url, boolean
         }
 
         @Override
-        public void didPressCode(ChatMessageCell cell, CharacterStyle _span, boolean longPress) {
-            if (!(_span instanceof CodeHighlighting.Span)) {
+        public void didPressCodeCopy(ChatMessageCell cell, MessageObject.TextLayoutBlock block) {
+            if (block == null || block.textLayout == null || block.textLayout.getText() == null) {
                 return;
             }
-            final CodeHighlighting.Span span = (CodeHighlighting.Span) _span;
-            SpannableStringBuilder text = new SpannableStringBuilder(span.code);
-            text.setSpan(new CodeHighlighting.Span(false, 0, null, span.lng, span.code), 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
-            AndroidUtilities.addToClipboard(text);
-            createUndoView();
-            undoView.showWithAction(0, UndoView.ACTION_TEXT_COPIED, null);
+
+            String string = block.textLayout.getText().toString();
+            SpannableString code = new SpannableString(string);
+            code.setSpan(new CodeHighlighting.Span(false, 0, null, block.language, string), 0, code.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+            AndroidUtilities.addToClipboard(code);
+            BulletinFactory.of(ChatActivity.this).createCopyBulletin(LocaleController.getString(R.string.CodeCopied)).show();
         }
 
         @Override
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java
index 9688e9bf64..a7857a0b0d 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java
@@ -376,7 +376,7 @@ private void updateRows() {
             if (slowmodeInfoRow == -1 && gigaHeaderRow == -1 || removedUsersRow != -1) {
                 participantsDividerRow = rowCount++;
             }
-            if (ChatObject.canBlockUsers(currentChat) && (ChatObject.isChannel(currentChat) || currentChat.creator)) {
+            if (ChatObject.canBlockUsers(currentChat) && getParticipantsCount() > 1 && (ChatObject.isChannel(currentChat) || currentChat.creator)) {
                 addNewRow = rowCount++;
             }
 
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 85931eec64..489e53d303 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java
@@ -23,6 +23,7 @@
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.BitmapDrawable;
 import android.os.Build;
+import android.util.Log;
 import android.view.View;
 
 import org.telegram.messenger.AndroidUtilities;
@@ -32,6 +33,7 @@
 import org.telegram.messenger.DispatchQueuePoolBackground;
 import org.telegram.messenger.FileLoader;
 import org.telegram.messenger.FileLog;
+import org.telegram.messenger.ImageLoader;
 import org.telegram.messenger.ImageLocation;
 import org.telegram.messenger.ImageReceiver;
 import org.telegram.messenger.SharedConfig;
@@ -353,6 +355,7 @@ public void checkRepeat() {
         }
     }
 
+    private int decoderTryCount = 0;
     private Runnable loadFrameRunnable = new Runnable() {
         @Override
         public void run() {
@@ -364,7 +367,7 @@ public void run() {
                         nativePtr = 0;
                     }
                     updateScaleFactor();
-                    decoderCreated = true;
+                    decoderCreated = !isWebmSticker || nativePtr != 0 || (decoderTryCount++) > 15;
                 }
                 try {
                     if (bitmapsCache != null) {
@@ -1077,7 +1080,7 @@ public long getStartTime() {
     }
 
     public boolean isRecycled() {
-        return isRecycled;
+        return isRecycled || decoderTryCount >= 15;
     }
 
     public Bitmap getNextFrame() {
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 f70b563b1e..d0b595a9dd 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFloat.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFloat.java
@@ -197,6 +197,10 @@ public float getTransitionProgressInterpolated() {
         }
     }
 
+    public float getTargetValue() {
+        return targetValue;
+    }
+
     public void setParent(View parent) {
         this.parent = parent;
     }
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarConstructorFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarConstructorFragment.java
index f2a0534864..e02b8cffd8 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarConstructorFragment.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarConstructorFragment.java
@@ -10,6 +10,7 @@
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.ColorFilter;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.PorterDuff;
@@ -400,7 +401,7 @@ protected void dispatchDraw(Canvas canvas) {
         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) {
+        selectAnimatedEmojiDialog = new SelectAnimatedEmojiDialog(this, getContext(), false, null, SelectAnimatedEmojiDialog.TYPE_AVATAR_CONSTRUCTOR, true, null, 16, Theme.isCurrentThemeDark() ? Color.WHITE : getThemedColor(Theme.key_windowBackgroundWhiteBlueIcon)) {
 
             private boolean firstLayout = true;
 
@@ -685,6 +686,7 @@ public class PreviewView extends FrameLayout {
         float changeBackgroundProgress = 1f;
         BackgroundGradient backgroundGradient;
 
+        private ColorFilter colorFilter = new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN);
         AnimatedFloat expandProgress = new AnimatedFloat(this, 200, CubicBezierInterpolator.EASE_OUT);
         boolean expanded;
         float overrideExpandProgress = -1f;
@@ -791,8 +793,8 @@ protected void dispatchDraw(Canvas canvas) {
                     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.setColorFilter(colorFilter);
                 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));
@@ -842,6 +844,9 @@ public ImageReceiver getImageReceiver() {
             ImageReceiver imageReceiver = backupImageView.getImageReceiver();
             if (backupImageView.animatedEmojiDrawable != null) {
                 imageReceiver = backupImageView.animatedEmojiDrawable.getImageReceiver();
+                if (imageReceiver != null) {
+                    imageReceiver.setColorFilter(colorFilter);
+                }
             }
             return imageReceiver;
         }
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotCommandsMenuView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotCommandsMenuView.java
index ee5d3ca7fe..e0e983c46a 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotCommandsMenuView.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotCommandsMenuView.java
@@ -334,7 +334,7 @@ public static class BotCommandView extends LinearLayout {
         public BotCommandView(@NonNull Context context) {
             super(context);
             setOrientation(HORIZONTAL);
-            setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0);
+            setPadding(AndroidUtilities.dp(16), AndroidUtilities.dp(8), AndroidUtilities.dp(16), AndroidUtilities.dp(8));
 
             description = new TextView(context) {
                 @Override
@@ -347,7 +347,7 @@ public void setText(CharSequence text, BufferType type) {
             description.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
             description.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText));
             description.setTag(Theme.key_windowBackgroundWhiteBlackText);
-            description.setLines(1);
+            description.setMaxLines(2);
             description.setEllipsize(TextUtils.TruncateAt.END);
             addView(description, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f, Gravity.CENTER_VERTICAL, 0, 0, AndroidUtilities.dp(8), 0));
 
@@ -358,11 +358,6 @@ public void setText(CharSequence text, BufferType type) {
             addView(command, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0f, Gravity.CENTER_VERTICAL));
         }
 
-        @Override
-        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(36), MeasureSpec.EXACTLY));
-        }
-
         public String getCommand() {
             return commandStr;
         }
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 c5ba50b48f..b5f33613dd 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotWebViewSheet.java
@@ -822,7 +822,8 @@ public void onDetachedFromWindow() {
     public static JSONObject makeThemeParams(Theme.ResourcesProvider resourcesProvider) {
         try {
             JSONObject jsonObject = new JSONObject();
-            jsonObject.put("bg_color", Theme.getColor(Theme.key_dialogBackground, resourcesProvider));
+            final int backgroundColor = Theme.getColor(Theme.key_dialogBackground, resourcesProvider);
+            jsonObject.put("bg_color", backgroundColor);
             jsonObject.put("section_bg_color", Theme.getColor(Theme.key_windowBackgroundWhite, resourcesProvider));
             jsonObject.put("secondary_bg_color", Theme.getColor(Theme.key_windowBackgroundGray, resourcesProvider));
             jsonObject.put("text_color", Theme.getColor(Theme.key_windowBackgroundWhiteBlackText, resourcesProvider));
@@ -831,10 +832,10 @@ public static JSONObject makeThemeParams(Theme.ResourcesProvider resourcesProvid
             jsonObject.put("button_color", Theme.getColor(Theme.key_featuredStickers_addButton, resourcesProvider));
             jsonObject.put("button_text_color", Theme.getColor(Theme.key_featuredStickers_buttonText, resourcesProvider));
             jsonObject.put("header_bg_color", Theme.getColor(Theme.key_actionBarDefault, resourcesProvider));
-            jsonObject.put("accent_text_color", Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4, resourcesProvider));
-            jsonObject.put("section_header_text_color", Theme.getColor(Theme.key_windowBackgroundWhiteBlueHeader, resourcesProvider));
-            jsonObject.put("subtitle_text_color", Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2, resourcesProvider));
-            jsonObject.put("destructive_text_color", Theme.getColor(Theme.key_text_RedRegular, resourcesProvider));
+            jsonObject.put("accent_text_color", Theme.blendOver(backgroundColor, Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4, resourcesProvider)));
+            jsonObject.put("section_header_text_color", Theme.blendOver(backgroundColor, Theme.getColor(Theme.key_windowBackgroundWhiteBlueHeader, resourcesProvider)));
+            jsonObject.put("subtitle_text_color", Theme.blendOver(backgroundColor, Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2, resourcesProvider)));
+            jsonObject.put("destructive_text_color", Theme.blendOver(backgroundColor, Theme.getColor(Theme.key_text_RedRegular, resourcesProvider)));
             return jsonObject;
         } catch (Exception e) {
             FileLog.e(e);
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 fcb288d4e5..dcd65305ef 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java
@@ -2574,7 +2574,7 @@ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         containerView.addView(writeButtonContainer, LayoutHelper.createFrame(60, 60, Gravity.RIGHT | Gravity.BOTTOM, 0, 0, 6, 10));
 
         writeButton = new ImageView(context);
-        writeButtonDrawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), getThemedColor(Theme.key_dialogFloatingButton), getThemedColor(Build.VERSION.SDK_INT >= 21 ? Theme.key_dialogFloatingButtonPressed : Theme.key_dialogFloatingButton));
+        writeButtonDrawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), getThemedColor(Theme.key_chat_attachCheckBoxBackground), getThemedColor(Build.VERSION.SDK_INT >= 21 ? Theme.key_dialogFloatingButtonPressed : Theme.key_chat_attachCheckBoxBackground));
         if (Build.VERSION.SDK_INT < 21) {
             Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.floating_shadow_profile).mutate();
             shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.SRC_IN));
@@ -2787,7 +2787,7 @@ protected void onDraw(Canvas canvas) {
                 rect.set(cx - size / 2, 0, cx + size / 2, getMeasuredHeight());
                 canvas.drawRoundRect(rect, AndroidUtilities.dp(12), AndroidUtilities.dp(12), paint);
 
-                paint.setColor(getThemedColor(Theme.key_dialogRoundCheckBox));
+                paint.setColor(getThemedColor(Theme.key_chat_attachCheckBoxBackground));
                 rect.set(cx - size / 2 + AndroidUtilities.dp(2), AndroidUtilities.dp(2), cx + size / 2 - AndroidUtilities.dp(2), getMeasuredHeight() - AndroidUtilities.dp(2));
                 canvas.drawRoundRect(rect, AndroidUtilities.dp(10), AndroidUtilities.dp(10), paint);
 
@@ -3771,8 +3771,8 @@ public void checkColors() {
             }
         }
 
-        Theme.setSelectorDrawableColor(writeButtonDrawable, getThemedColor(Theme.key_dialogFloatingButton), false);
-        Theme.setSelectorDrawableColor(writeButtonDrawable, getThemedColor(Build.VERSION.SDK_INT >= 21 ? Theme.key_dialogFloatingButtonPressed : Theme.key_dialogFloatingButton), true);
+        Theme.setSelectorDrawableColor(writeButtonDrawable, getThemedColor(Theme.key_chat_attachCheckBoxBackground), false);
+        Theme.setSelectorDrawableColor(writeButtonDrawable, getThemedColor(Build.VERSION.SDK_INT >= 21 ? Theme.key_dialogFloatingButtonPressed : Theme.key_chat_attachCheckBoxBackground), true);
         writeButton.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_dialogFloatingIcon), PorterDuff.Mode.SRC_IN));
 
         actionBarShadow.setBackgroundColor(getThemedColor(Theme.key_dialogShadowLine));
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 545a55c374..49cf1ed1af 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java
@@ -1461,6 +1461,10 @@ public void showAvatarConstructorFragment(AvatarConstructorPreviewCell view, TLR
                     boolean isAnimatedSticker = MessageObject.isAnimatedStickerDocument(document, true);
                     mediaEntity.subType |= isAnimatedSticker ? 1 : 4;
                 }
+                if (MessageObject.isTextColorEmoji(document)) {
+                    mediaEntity.color = 0xFFFFFFFF;
+                    mediaEntity.subType |= 8;
+                }
 
                 photoEntry.editedInfo.mediaEntities = new ArrayList<>();
                 photoEntry.editedInfo.mediaEntities.add(mediaEntity);
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextBoldCursor.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextBoldCursor.java
index f47911c221..242a487a68 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextBoldCursor.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextBoldCursor.java
@@ -863,12 +863,12 @@ protected void onDraw(Canvas canvas) {
                 throw new RuntimeException(e);
             }
         }
-        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT_WATCH) {
+        if (!EditTextEffects.allowHackingTextCanvas()) {
             ignoreTopCount = 1;
             ignoreBottomCount = 1;
         }
         canvas.save();
-        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT_WATCH) {
+        if (!EditTextEffects.allowHackingTextCanvas()) {
             canvas.translate(0, topPadding);
         }
         try {
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEffects.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEffects.java
index d5c225dcc0..d8688f2d64 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEffects.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextEffects.java
@@ -271,7 +271,19 @@ public float getOffsetY() {
         return offsetY;
     }
 
-    public boolean wrapCanvasToFixClipping = Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH;
+    private static Boolean allowHackingTextCanvasCache;
+    public static boolean allowHackingTextCanvas() {
+        if (allowHackingTextCanvasCache == null) {
+            allowHackingTextCanvasCache = Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH && (
+                Build.MANUFACTURER == null ||
+                !Build.MANUFACTURER.equalsIgnoreCase("HONOR") &&
+                !Build.MANUFACTURER.equalsIgnoreCase("HUAWEI")
+            );
+        }
+        return allowHackingTextCanvasCache;
+    }
+
+    public boolean wrapCanvasToFixClipping = allowHackingTextCanvas();
     private NoClipCanvas wrappedCanvas;
 
     @Override
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 9c5ea76175..2b7c472d68 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkSpanDrawable.java
@@ -563,6 +563,10 @@ public ClickableSpan hit(int x, int y) {
             return null;
         }
 
+        public int overrideColor() {
+            return Theme.getColor(Theme.key_chat_linkSelectBackground, resourcesProvider);
+        }
+
         @Override
         public boolean onTouchEvent(MotionEvent event) {
             if (links != null) {
@@ -571,6 +575,7 @@ public boolean onTouchEvent(MotionEvent event) {
                 if ((span = hit((int) event.getX(), (int) event.getY())) != null) {
                     if (event.getAction() == MotionEvent.ACTION_DOWN) {
                         final LinkSpanDrawable link = new LinkSpanDrawable(span, resourcesProvider, event.getX(), event.getY());
+                        link.setColor(overrideColor());
                         pressedLink = link;
                         links.addLink(pressedLink);
                         Spannable buffer = new SpannableString(textLayout.getText());
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/NoClipCanvas.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/NoClipCanvas.java
index e092330edc..8e6674fc55 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/NoClipCanvas.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/NoClipCanvas.java
@@ -613,4 +613,15 @@ public boolean quickReject(@NonNull Path path, @NonNull EdgeType type) {
     public boolean quickReject(float left, float top, float right, float bottom, @NonNull EdgeType type) {
         return canvas.quickReject(left, top, right, bottom, type);
     }
+
+    @Override
+    public void concat(@Nullable Matrix matrix) {
+        canvas.concat(matrix);
+    }
+
+    @Override
+    public boolean isOpaque() {
+        return canvas.isOpaque();
+    }
+
 }
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java
index d5dfeea33a..3c6b797b75 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java
@@ -770,8 +770,7 @@ public void didReceivedNotification(int id, int account, Object... args) {
             canApplyBoost.setMyBoosts(myBoosts);
             onBoostSuccess();
 
-            String str = LocaleController.formatString("BoostingReassignedFrom", R.string.BoostingReassignedFrom,
-                    LocaleController.formatPluralString("BoostingSubscriptionsCount", size),
+            String str = LocaleController.formatPluralString("BoostingReassignedFromPlural", size,
                     LocaleController.formatPluralString("BoostingFromOtherChannel", channels));
             BulletinFactory bulletinFactory = BulletinFactory.of(container, resourcesProvider);
             bulletinFactory.createSimpleBulletinWithIconSize(R.raw.forward, str, 30).setDuration(4000).show(true);
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 705f7ad2b3..806ccf2957 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
@@ -33,6 +33,7 @@
 
 import org.telegram.messenger.AndroidUtilities;
 import org.telegram.messenger.ContactsController;
+import org.telegram.messenger.Emoji;
 import org.telegram.messenger.LocaleController;
 import org.telegram.messenger.MediaDataController;
 import org.telegram.messenger.NotificationCenter;
@@ -43,6 +44,7 @@
 import org.telegram.ui.ActionBar.BaseFragment;
 import org.telegram.ui.ActionBar.SimpleTextView;
 import org.telegram.ui.ActionBar.Theme;
+import org.telegram.ui.Cells.ChatMessageCell;
 import org.telegram.ui.Cells.ShadowSectionCell;
 import org.telegram.ui.Components.AnimatedEmojiDrawable;
 import org.telegram.ui.Components.AnimatedEmojiSpan;
@@ -89,12 +91,13 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i
     ViewGroup iconContainer;
     BaseFragment fragment;
 
+    public Integer accentColor;
     public float startEnterFromX;
     public float startEnterFromY;
     public float startEnterFromX1;
     public float startEnterFromY1;
     public float startEnterFromScale;
-    public SimpleTextView startEnterFromView;
+    public View startEnterFromView;
     public View overrideTitleIcon;
     public TLRPC.InputStickerSet statusStickerSet;
     public boolean isEmojiStatus;
@@ -267,7 +270,10 @@ public void setTitle(boolean animated) {
         if (statusStickerSet != null) {
             final String stickerSetPlaceholder = "";
             String string = LocaleController.formatString(R.string.TelegramPremiumUserStatusDialogTitle, ContactsController.formatName(user.first_name, user.last_name), stickerSetPlaceholder);
-            CharSequence charSequence = AndroidUtilities.replaceSingleTag(string, Theme.key_windowBackgroundWhiteBlueButton, AndroidUtilities.REPLACING_TAG_TYPE_LINK, null);
+            CharSequence charSequence = AndroidUtilities.replaceSingleLink(string, accentColor == null ? getThemedColor(Theme.key_windowBackgroundWhiteBlueButton) : accentColor);
+            try {
+                charSequence = Emoji.replaceEmoji(charSequence, titleView[0].getPaint().getFontMetricsInt(), false);
+            } catch (Exception ignore) {}
             SpannableStringBuilder title = charSequence instanceof SpannableStringBuilder ? ((SpannableStringBuilder) charSequence) : new SpannableStringBuilder(charSequence);
             int index = charSequence.toString().indexOf(stickerSetPlaceholder);
             if (index >= 0) {
@@ -303,6 +309,9 @@ public void setTitle(boolean animated) {
                     public void updateDrawState(@NonNull TextPaint ds) {
                         super.updateDrawState(ds);
                         ds.setUnderlineText(false);
+                        if (accentColor != null) {
+                            ds.setColor(accentColor);
+                        }
                     }
                     @Override
                     public void onClick(@NonNull View view) {}
@@ -358,24 +367,27 @@ protected void onCloseByLink() {
             subtitleView.setText(AndroidUtilities.replaceTags(LocaleController.formatString(R.string.TelegramPremiumUserStatusDialogSubtitle, ContactsController.formatName(user.first_name, user.last_name))));
         } else if (giftTier != null) {
             if (isOutboundGift) {
-                titleView[0].setText(AndroidUtilities.replaceSingleTag(LocaleController.formatString(R.string.TelegramPremiumUserGiftedPremiumOutboundDialogTitleWithPlural, user != null ? user.first_name : "", LocaleController.formatPluralString("GiftMonths", giftTier.getMonths())), Theme.key_windowBackgroundWhiteBlueButton,  AndroidUtilities.REPLACING_TAG_TYPE_LINK, null));
-                subtitleView.setText(AndroidUtilities.replaceSingleTag(LocaleController.formatString(R.string.TelegramPremiumUserGiftedPremiumOutboundDialogSubtitle, user != null ? user.first_name : ""), Theme.key_windowBackgroundWhiteBlueButton,  AndroidUtilities.REPLACING_TAG_TYPE_LINK, null));
+                titleView[0].setText(AndroidUtilities.replaceSingleLink(LocaleController.formatString(R.string.TelegramPremiumUserGiftedPremiumOutboundDialogTitleWithPlural, user != null ? user.first_name : "", LocaleController.formatPluralString("GiftMonths", giftTier.getMonths())), accentColor == null ? getThemedColor(Theme.key_windowBackgroundWhiteBlueButton) : accentColor));
+                subtitleView.setText(AndroidUtilities.replaceSingleLink(LocaleController.formatString(R.string.TelegramPremiumUserGiftedPremiumOutboundDialogSubtitle, user != null ? user.first_name : ""), accentColor == null ? getThemedColor(Theme.key_windowBackgroundWhiteBlueButton) : accentColor));
             } else if (user == null || TextUtils.isEmpty(user.first_name) || user.id == 777000) {
-                titleView[0].setText(AndroidUtilities.replaceSingleTag(LocaleController.formatString(R.string.TelegramPremiumUserGiftedPremiumDialogTitleWithPluralSomeone, LocaleController.formatPluralString("GiftMonths", giftTier.getMonths())), Theme.key_windowBackgroundWhiteBlueButton,  AndroidUtilities.REPLACING_TAG_TYPE_LINK, null));
+                titleView[0].setText(AndroidUtilities.replaceSingleLink(LocaleController.formatString(R.string.TelegramPremiumUserGiftedPremiumDialogTitleWithPluralSomeone, LocaleController.formatPluralString("GiftMonths", giftTier.getMonths())), accentColor == null ? getThemedColor(Theme.key_windowBackgroundWhiteBlueButton) : accentColor));
                 subtitleView.setText(AndroidUtilities.replaceTags(LocaleController.getString(R.string.TelegramPremiumUserGiftedPremiumDialogSubtitle)));
             } else {
-                titleView[0].setText(AndroidUtilities.replaceSingleTag(LocaleController.formatString(R.string.TelegramPremiumUserGiftedPremiumDialogTitleWithPlural, user.first_name, LocaleController.formatPluralString("GiftMonths", giftTier.getMonths())), Theme.key_windowBackgroundWhiteBlueButton,  AndroidUtilities.REPLACING_TAG_TYPE_LINK, null));
+                titleView[0].setText(AndroidUtilities.replaceSingleLink(LocaleController.formatString(R.string.TelegramPremiumUserGiftedPremiumDialogTitleWithPlural, user.first_name, LocaleController.formatPluralString("GiftMonths", giftTier.getMonths())), accentColor == null ? getThemedColor(Theme.key_windowBackgroundWhiteBlueButton) : accentColor));
                 subtitleView.setText(AndroidUtilities.replaceTags(LocaleController.getString(R.string.TelegramPremiumUserGiftedPremiumDialogSubtitle)));
             }
         } else {
-            if(user == null) {
+            if (user == null) {
                 titleView[0].setText(LocaleController.getString(R.string.TelegramPremium));
                 subtitleView.setText(AndroidUtilities.replaceTags(LocaleController.getString(R.string.TelegramPremiumSubscribedSubtitle)));
             } else {
-                titleView[0].setText(AndroidUtilities.replaceSingleTag(LocaleController.formatString(R.string.TelegramPremiumUserDialogTitle, ContactsController.formatName(user.first_name, user.last_name)), Theme.key_windowBackgroundWhiteBlueButton, AndroidUtilities.REPLACING_TAG_TYPE_LINK, null));
+                titleView[0].setText(AndroidUtilities.replaceSingleLink(LocaleController.formatString(R.string.TelegramPremiumUserDialogTitle, ContactsController.formatName(user.first_name, user.last_name)), accentColor == null ? getThemedColor(Theme.key_windowBackgroundWhiteBlueButton) : accentColor));
                 subtitleView.setText(AndroidUtilities.replaceTags(LocaleController.getString(R.string.TelegramPremiumUserDialogSubtitle)));
             }
         }
+        try {
+            titleView[0].setText(Emoji.replaceEmoji(titleView[0].getText(), titleView[0].getPaint().getFontMetricsInt(), false));
+        } catch (Exception ignore) {}
     }
 
     @Override
@@ -441,7 +453,7 @@ protected void onDetachedFromWindow() {
                         titleViewContainer = new FrameLayout(context);
                         titleViewContainer.setClipChildren(false);
 
-                        final ColorFilter colorFilter = new PorterDuffColorFilter(getThemedColor(Theme.key_windowBackgroundWhiteBlueIcon), PorterDuff.Mode.SRC_IN);
+                        final ColorFilter colorFilter = new PorterDuffColorFilter(accentColor == null ? getThemedColor(Theme.key_windowBackgroundWhiteBlueIcon) : accentColor, PorterDuff.Mode.SRC_IN);
                         titleView = new LinkSpanDrawable.LinksTextView[2];
                         for (int a = 0; a < 2; ++a) {
                             titleView[a] = new LinkSpanDrawable.LinksTextView(context, resourcesProvider) {
@@ -468,6 +480,11 @@ protected void dispatchDraw(Canvas canvas) {
                                 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
                                     super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(99999999, MeasureSpec.AT_MOST));
                                 }
+
+                                @Override
+                                public int overrideColor() {
+                                    return accentColor != null ? Theme.multAlpha(accentColor, .10f) : super.overrideColor();
+                                }
                             };
                             titleView[a].setVisibility(a == 0 ? View.VISIBLE : View.GONE);
                             titleView[a].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
@@ -654,7 +671,16 @@ protected void mainContainerDispatchDraw(Canvas canvas) {
 
             float[] points = new float[]{startEnterFromX, startEnterFromY};
             startEnterFromView.getMatrix().mapPoints(points);
-            Drawable startEnterFromDrawable = startEnterFromView.getRightDrawable();
+            Drawable startEnterFromDrawable = null;
+            if (startEnterFromView instanceof SimpleTextView) {
+                startEnterFromDrawable = ((SimpleTextView) startEnterFromView).getRightDrawable();
+            } else if (startEnterFromView instanceof ChatMessageCell) {
+                startEnterFromDrawable = ((ChatMessageCell) startEnterFromView).currentNameStatusDrawable;
+            }
+            if (startEnterFromDrawable == null) {
+                canvas.restore();
+                return;
+            }
             float cxFrom = -coords[0] + startEnterFromX1 + points[0];
             float cyFrom = -coords[1] + startEnterFromY1 + points[1];
 
@@ -718,8 +744,23 @@ protected boolean onCustomOpenAnimation() {
         enterTransitionProgress = 0f;
         enterTransitionInProgress = true;
         iconContainer.invalidate();
-        startEnterFromView.getRightDrawable().setAlpha(0);
-        startEnterFromView.invalidate();
+        final Drawable startEnterFromDrawable;
+        if (startEnterFromView instanceof SimpleTextView) {
+            startEnterFromDrawable = ((SimpleTextView) startEnterFromView).getRightDrawable();
+        } else if (startEnterFromView instanceof ChatMessageCell) {
+            startEnterFromDrawable = ((ChatMessageCell) startEnterFromView).currentNameStatusDrawable;
+            ((ChatMessageCell) startEnterFromView).invalidateOutbounds();
+        } else {
+            startEnterFromDrawable = null;
+        }
+        if (startEnterFromDrawable != null) {
+            startEnterFromDrawable.setAlpha(0);
+        }
+        if (startEnterFromView instanceof ChatMessageCell) {
+            ((ChatMessageCell) startEnterFromView).invalidateOutbounds();
+        } else {
+            startEnterFromView.invalidate();
+        }
         if (iconTextureView != null) {
             iconTextureView.startEnterAnimation(-360, 100);
         }
@@ -733,13 +774,18 @@ public void onAnimationEnd(Animator animation) {
                 enterTransitionInProgress = false;
                 enterTransitionProgress = 1f;
                 iconContainer.invalidate();
-                ValueAnimator iconAlphaBack = ValueAnimator.ofInt(0, 255);
-                Drawable drawable = startEnterFromView.getRightDrawable();
-                iconAlphaBack.addUpdateListener(animation1 -> {
-                    drawable.setAlpha((Integer) animation1.getAnimatedValue());
-                    startEnterFromView.invalidate();
-                });
-                iconAlphaBack.start();
+                if (startEnterFromDrawable != null) {
+                    ValueAnimator iconAlphaBack = ValueAnimator.ofInt(0, 255);
+                    iconAlphaBack.addUpdateListener(animation1 -> {
+                        startEnterFromDrawable.setAlpha((Integer) animation1.getAnimatedValue());
+                        if (startEnterFromView instanceof ChatMessageCell) {
+                            ((ChatMessageCell) startEnterFromView).invalidateOutbounds();
+                        } else {
+                            startEnterFromView.invalidate();
+                        }
+                    });
+                    iconAlphaBack.start();
+                }
                 super.onAnimationEnd(animation);
             }
         });
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostCounterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostCounterView.java
index 16f93e85c4..04019e1a1f 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostCounterView.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostCounterView.java
@@ -39,7 +39,7 @@ public BoostCounterView(Context context, Theme.ResourcesProvider resourcesProvid
         countText.setTypeface(AndroidUtilities.getTypeface(AndroidUtilities.TYPEFACE_ROBOTO_MEDIUM));
         countText.setTextColor(Color.WHITE);
         countText.setText("");
-        countText.setGravity(Gravity.CENTER_HORIZONTAL);
+        countText.setGravity(Gravity.CENTER);
 
         bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
         bgPaint.setColor(0xFF967bff);
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostDialogs.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostDialogs.java
index 77a60a586f..d08db75a14 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostDialogs.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostDialogs.java
@@ -429,7 +429,7 @@ public static boolean checkReduceUsers(Context context, Theme.ResourcesProvider
 
             AlertDialog.Builder builder = new AlertDialog.Builder(context, resourcesProvider);
             builder.setTitle(getString("BoostingReduceQuantity", R.string.BoostingReduceQuantity));
-            builder.setMessage(replaceTags(formatString("BoostingReduceUsersText", R.string.BoostingReduceUsersText, current, downTo)));
+            builder.setMessage(replaceTags(formatPluralString("BoostingReduceUsersTextPlural", current, downTo)));
             builder.setPositiveButton(getString("OK", R.string.OK), (dialogInterface, i) -> {
 
             });
@@ -439,11 +439,11 @@ public static boolean checkReduceUsers(Context context, Theme.ResourcesProvider
         return false;
     }
 
-    public static boolean checkReduceQuantity(Context context, Theme.ResourcesProvider resourcesProvider, List list, TLRPC.TL_premiumGiftCodeOption selected, Utilities.Callback onSuccess) {
+    public static boolean checkReduceQuantity(List sliderValues, Context context, Theme.ResourcesProvider resourcesProvider, List list, TLRPC.TL_premiumGiftCodeOption selected, Utilities.Callback onSuccess) {
         if (selected.store_product == null) {
             List result = new ArrayList<>();
             for (TLRPC.TL_premiumGiftCodeOption item : list) {
-                if (item.months == selected.months && item.store_product != null) {
+                if (item.months == selected.months && item.store_product != null && sliderValues.contains(item.users)) {
                     result.add(item);
                 }
             }
@@ -462,7 +462,7 @@ public static boolean checkReduceQuantity(Context context, Theme.ResourcesProvid
             int downTo = suggestion.users;
             AlertDialog.Builder builder = new AlertDialog.Builder(context, resourcesProvider);
             builder.setTitle(getString("BoostingReduceQuantity", R.string.BoostingReduceQuantity));
-            builder.setMessage(replaceTags(formatString("BoostingReduceQuantityText", R.string.BoostingReduceQuantityText, current, months, downTo)));
+            builder.setMessage(replaceTags(formatPluralString("BoostingReduceQuantityTextPlural", current, months, downTo)));
             builder.setPositiveButton(getString("Reduce", R.string.Reduce), (dialogInterface, i) -> onSuccess.run(finalSuggestion));
             builder.setNegativeButton(getString("Cancel", R.string.Cancel), (dialogInterface, i) -> {
 
@@ -473,9 +473,7 @@ public static boolean checkReduceQuantity(Context context, Theme.ResourcesProvid
         return false;
     }
 
-    public static void showAbout(long chatId, long msgDate, TLRPC.TL_payments_giveawayInfo giveawayInfo, TLRPC.TL_messageMediaGiveaway giveaway, Context context, Theme.ResourcesProvider resourcesProvider) {
-        TLRPC.Chat chat = MessagesController.getInstance(UserConfig.selectedAccount).getChat(-chatId);
-        String from = chat != null ? chat.title : "";
+    public static void showAbout(String from, long msgDate, TLRPC.TL_payments_giveawayInfo giveawayInfo, TLRPC.TL_messageMediaGiveaway giveaway, Context context, Theme.ResourcesProvider resourcesProvider) {
         int quantity = giveaway.quantity;
         String months = formatPluralString("BoldMonths", giveaway.months);
         String endDate = LocaleController.getInstance().formatterGiveawayMonthDay.format(new Date(giveaway.until_date * 1000L));
@@ -492,13 +490,15 @@ public static void showAbout(long chatId, long msgDate, TLRPC.TL_payments_giveaw
 
         if (giveaway.only_new_subscribers) {
             if (isSeveralChats) {
-                stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayHowItWorksSubTextDateSeveral", quantity, endDate, quantity, from, giveaway.channels.size() - 1, fromTime, fromDate)));
+                String andStr = formatPluralString("BoostingGiveawayHowItWorksSubTextDateSeveral2", giveaway.channels.size() - 1, fromTime, fromDate);
+                stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayHowItWorksSubTextDateSeveral1", quantity, endDate, quantity, from, andStr)));
             } else {
                 stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayHowItWorksSubTextDate", quantity, endDate, quantity, from, fromTime, fromDate)));
             }
         } else {
             if (isSeveralChats) {
-                stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayHowItWorksSubTextSeveral", quantity, endDate, quantity, from, giveaway.channels.size() - 1)));
+                String andStr = formatPluralString("BoostingGiveawayHowItWorksSubTextSeveral2", giveaway.channels.size() - 1);
+                stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayHowItWorksSubTextSeveral1", quantity, endDate, quantity, from, andStr)));
             } else {
                 stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayHowItWorksSubText", quantity, endDate, quantity, from)));
             }
@@ -508,7 +508,7 @@ public static void showAbout(long chatId, long msgDate, TLRPC.TL_payments_giveaw
 
         if (giveawayInfo.participating) {
             if (isSeveralChats) {
-                stringBuilder.append(replaceTags(formatString("BoostingGiveawayParticipantMulti", R.string.BoostingGiveawayParticipantMulti, from, giveaway.channels.size() - 1)));
+                stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayParticipantMultiPlural", giveaway.channels.size() - 1, from)));
             } else {
                 stringBuilder.append(replaceTags(formatString("BoostingGiveawayParticipant", R.string.BoostingGiveawayParticipant, from)));
             }
@@ -523,7 +523,7 @@ public static void showAbout(long chatId, long msgDate, TLRPC.TL_payments_giveaw
             stringBuilder.append(replaceTags(formatString("BoostingGiveawayNotEligible", R.string.BoostingGiveawayNotEligible, date)));
         } else {
             if (isSeveralChats) {
-                stringBuilder.append(replaceTags(formatString("BoostingGiveawayTakePartMulti", R.string.BoostingGiveawayTakePartMulti, from, giveaway.channels.size() - 1, endDate)));
+                stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayTakePartMultiPlural", giveaway.channels.size() - 1, from, endDate)));
             } else {
                 stringBuilder.append(replaceTags(formatString("BoostingGiveawayTakePart", R.string.BoostingGiveawayTakePart, from, endDate)));
             }
@@ -536,9 +536,7 @@ public static void showAbout(long chatId, long msgDate, TLRPC.TL_payments_giveaw
         builder.show();
     }
 
-    public static void showAboutEnd(long chatId, long msgDate, TLRPC.TL_payments_giveawayInfoResults giveawayInfo, TLRPC.TL_messageMediaGiveaway giveaway, Context context, Theme.ResourcesProvider resourcesProvider) {
-        TLRPC.Chat chat = MessagesController.getInstance(UserConfig.selectedAccount).getChat(-chatId);
-        String from = chat != null ? chat.title : "";
+    public static void showAboutEnd(String from, long msgDate, TLRPC.TL_payments_giveawayInfoResults giveawayInfo, TLRPC.TL_messageMediaGiveaway giveaway, Context context, Theme.ResourcesProvider resourcesProvider) {
         int quantity = giveaway.quantity;
         String months = formatPluralString("BoldMonths", giveaway.months);
         String endDate = LocaleController.getInstance().formatterGiveawayMonthDay.format(new Date(giveaway.until_date * 1000L));
@@ -555,13 +553,15 @@ public static void showAboutEnd(long chatId, long msgDate, TLRPC.TL_payments_giv
 
         if (giveaway.only_new_subscribers) {
             if (isSeveralChats) {
-                stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayHowItWorksSubTextDateSeveralEnd", quantity, endDate, quantity, from, giveaway.channels.size() - 1, fromTime, fromDate)));
+                String andStr = formatPluralString("BoostingGiveawayHowItWorksSubTextDateSeveral2", giveaway.channels.size() - 1, fromTime, fromDate);
+                stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayHowItWorksSubTextDateSeveralEnd1", quantity, endDate, quantity, from, andStr)));
             } else {
                 stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayHowItWorksSubTextDateEnd", quantity, endDate, quantity, from, fromTime, fromDate)));
             }
         } else {
             if (isSeveralChats) {
-                stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayHowItWorksSubTextSeveralEnd", quantity, endDate, quantity, from, giveaway.channels.size() - 1)));
+                String andStr = formatPluralString("BoostingGiveawayHowItWorksSubTextSeveral2", giveaway.channels.size() - 1);
+                stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayHowItWorksSubTextSeveralEnd1", quantity, endDate, quantity, from, andStr)));
             } else {
                 stringBuilder.append(replaceTags(formatPluralString("BoostingGiveawayHowItWorksSubTextEnd", quantity, endDate, quantity, from)));
             }
@@ -583,7 +583,7 @@ public static void showAboutEnd(long chatId, long msgDate, TLRPC.TL_payments_giv
             bottomTextView.setText(str);
             bottomTextView.setTextColor(Theme.getColor(Theme.key_text_RedRegular, resourcesProvider));
             bottomTextView.setBackground(Theme.createRoundRectDrawable(dp(10), dp(10), Theme.multAlpha(Theme.getColor(Theme.key_text_RedRegular, resourcesProvider), 0.1f)));
-            bottomTextView.setPadding(0, dp(12), 0, dp(12));
+            bottomTextView.setPadding(dp(8), dp(12), dp(8), dp(12));
             builder.addBottomView(bottomTextView);
             builder.setMessage(stringBuilder);
             builder.setPositiveButton(getString("Close", R.string.Close), (dialogInterface, i) -> {
@@ -639,7 +639,7 @@ public static void openGiveAwayStatusDialog(MessageObject messageObject, Browser
         progress.init();
         progress.onCancel(() -> isCanceled.set(true));
         final TLRPC.TL_messageMediaGiveaway giveaway = (TLRPC.TL_messageMediaGiveaway) messageObject.messageOwner.media;
-        final long chatId = messageObject.getFromChatId();
+        final String fromName = getGiveawayCreatorName(messageObject);
         final long msgDate = messageObject.messageOwner.date * 1000L;
         BoostRepository.getGiveawayInfo(messageObject, result -> {
             if (isCanceled.get()) {
@@ -648,10 +648,10 @@ public static void openGiveAwayStatusDialog(MessageObject messageObject, Browser
             progress.end();
             if (result instanceof TLRPC.TL_payments_giveawayInfo) {
                 TLRPC.TL_payments_giveawayInfo giveawayInfo = (TLRPC.TL_payments_giveawayInfo) result;
-                showAbout(chatId, msgDate, giveawayInfo, giveaway, context, resourcesProvider);
+                showAbout(fromName, msgDate, giveawayInfo, giveaway, context, resourcesProvider);
             } else if (result instanceof TLRPC.TL_payments_giveawayInfoResults) {
                 TLRPC.TL_payments_giveawayInfoResults giveawayInfoResults = (TLRPC.TL_payments_giveawayInfoResults) result;
-                showAboutEnd(chatId, msgDate, giveawayInfoResults, giveaway, context, resourcesProvider);
+                showAboutEnd(fromName, msgDate, giveawayInfoResults, giveaway, context, resourcesProvider);
             }
         }, error -> {
             if (isCanceled.get()) {
@@ -661,18 +661,34 @@ public static void openGiveAwayStatusDialog(MessageObject messageObject, Browser
         });
     }
 
+    private static String getGiveawayCreatorName(MessageObject messageObject) {
+        if (messageObject == null) {
+            return "";
+        }
+        String forwardedName = messageObject.getForwardedName();
+        final String name;
+        if (forwardedName == null) {
+            final long chatId = messageObject.getFromChatId();
+            TLRPC.Chat chat = MessagesController.getInstance(UserConfig.selectedAccount).getChat(-chatId);
+            name = chat != null ? chat.title : "";
+        } else {
+            name = forwardedName;
+        }
+        return name;
+    }
+
     public static void showBulletinAbout(MessageObject messageObject) {
         if (messageObject == null) {
             return;
         }
         BoostRepository.getGiveawayInfo(messageObject, result -> {
             final TLRPC.TL_messageMediaGiveaway giveaway = (TLRPC.TL_messageMediaGiveaway) messageObject.messageOwner.media;
-            final long chatId = messageObject.getFromChatId();
             final long msgDate = messageObject.messageOwner.date * 1000L;
             BaseFragment fragment = LaunchActivity.getLastFragment();
             if (fragment == null) {
                 return;
             }
+            final String fromName = getGiveawayCreatorName(messageObject);
             final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(fragment.getParentActivity(), fragment.getResourceProvider());
 
             if (result instanceof TLRPC.TL_payments_giveawayInfoResults) {
@@ -697,10 +713,10 @@ public static void showBulletinAbout(MessageObject messageObject) {
                     .setUndoAction(() -> {
                         if (result instanceof TLRPC.TL_payments_giveawayInfo) {
                             TLRPC.TL_payments_giveawayInfo giveawayInfo = (TLRPC.TL_payments_giveawayInfo) result;
-                            showAbout(chatId, msgDate, giveawayInfo, giveaway, fragment.getParentActivity(), fragment.getResourceProvider());
+                            showAbout(fromName, msgDate, giveawayInfo, giveaway, fragment.getParentActivity(), fragment.getResourceProvider());
                         } else if (result instanceof TLRPC.TL_payments_giveawayInfoResults) {
                             TLRPC.TL_payments_giveawayInfoResults giveawayInfoResults = (TLRPC.TL_payments_giveawayInfoResults) result;
-                            showAboutEnd(chatId, msgDate, giveawayInfoResults, giveaway, fragment.getParentActivity(), fragment.getResourceProvider());
+                            showAboutEnd(fromName, msgDate, giveawayInfoResults, giveaway, fragment.getParentActivity(), fragment.getResourceProvider());
                         }
                     }));
             Bulletin.make(fragment, layout, Bulletin.DURATION_LONG).show();
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostPagerBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostPagerBottomSheet.java
index b1da6f0929..2977b64338 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostPagerBottomSheet.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostPagerBottomSheet.java
@@ -143,6 +143,14 @@ protected void dispatchDraw(Canvas canvas) {
                 }
             }
 
+            @Override
+            protected float getAvailableTranslationX() {
+                if (isTablet || isLandscapeOrientation) {
+                    return getMeasuredWidth();
+                }
+                return super.getAvailableTranslationX();
+            }
+
             @Override
             protected boolean canScroll(MotionEvent e) {
                 return viewPager.getCurrentPosition() == 1;
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostRepository.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostRepository.java
index 4203da492c..99c341ae2a 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostRepository.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/BoostRepository.java
@@ -16,6 +16,7 @@
 import org.telegram.messenger.MessagesStorage;
 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;
@@ -206,6 +207,9 @@ public static void loadCountries(Utilities.Callback {
+                            if (BoostRepository.isGoogleBillingAvailable() && BoostDialogs.checkReduceQuantity(sliderValues, getContext(), resourcesProvider, giftCodeOptions, option, arg -> {
                                 selectedSliderIndex = sliderValues.indexOf(arg.users);
                                 updateRows(true, true);
                                 updateActionButton(true);
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/GiftInfoBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/GiftInfoBottomSheet.java
index 8eb2aca2e2..119a2625eb 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/GiftInfoBottomSheet.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/GiftInfoBottomSheet.java
@@ -29,6 +29,9 @@
 public class GiftInfoBottomSheet extends BottomSheetWithRecyclerListView {
 
     public static void show(BaseFragment fragment, String slug, Browser.Progress progress) {
+        if (fragment == null) {
+            return;
+        }
         final AtomicBoolean isCanceled = new AtomicBoolean(false);
         if (progress != null) {
             progress.init();
@@ -38,12 +41,11 @@ public static void show(BaseFragment fragment, String slug, Browser.Progress pro
             if (isCanceled.get()) {
                 return;
             }
-            GiftInfoBottomSheet alert = new GiftInfoBottomSheet(fragment, false, true, giftCode, slug);
-            if (fragment != null && fragment.getParentActivity() != null) {
-                fragment.showDialog(alert);
-            } else {
-                alert.show();
+            if (fragment.getParentActivity() == null) {
+                return;
             }
+            GiftInfoBottomSheet alert = new GiftInfoBottomSheet(fragment, false, true, giftCode, slug);
+            fragment.showDialog(alert);
             if (progress != null) {
                 progress.end();
             }
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/ReassignBoostBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/ReassignBoostBottomSheet.java
index 01ab8b38cd..991cc28ced 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/ReassignBoostBottomSheet.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/ReassignBoostBottomSheet.java
@@ -158,7 +158,7 @@ protected void onDraw(Canvas canvas) {
             if (view instanceof SelectorUserCell) {
                 SelectorUserCell cell = ((SelectorUserCell) view);
                 if (cell.getBoost().cooldown_until_date > 0) {
-                    SpannableStringBuilder text = AndroidUtilities.replaceTags(LocaleController.formatString("BoostingWaitWarning", R.string.BoostingWaitWarning, BoostRepository.boostsPerSentGift()));
+                    SpannableStringBuilder text = AndroidUtilities.replaceTags(LocaleController.formatPluralString("BoostingWaitWarningPlural", BoostRepository.boostsPerSentGift()));
                     BulletinFactory.of(container, resourcesProvider).createSimpleBulletin(R.raw.chats_infotip, text, 5).show(true);
                     return;
                 }
@@ -364,7 +364,7 @@ public TopCell(Context context) {
         }
 
         public void setData(TLRPC.Chat chat) {
-            description.setText(AndroidUtilities.replaceTags(LocaleController.formatString("BoostingReassignBoostText", R.string.BoostingReassignBoostText, chat == null ? "" : chat.title, BoostRepository.boostsPerSentGift())));
+            description.setText(AndroidUtilities.replaceTags(LocaleController.formatPluralString("BoostingReassignBoostTextPlural", BoostRepository.boostsPerSentGift(), chat == null ? "" : chat.title)));
         }
 
         public void showBoosts(List selectedBoosts, TLRPC.Chat currentChat) {
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/SelectorBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/SelectorBottomSheet.java
index 60d88c1f4b..8ae9dba297 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/SelectorBottomSheet.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/SelectorBottomSheet.java
@@ -276,7 +276,7 @@ public void scrollToTop(boolean animate) {
             linearSmoothScroller.setOffset(AndroidUtilities.dp(38));
             recyclerListView.getLayoutManager().startSmoothScroll(linearSmoothScroller);
         } else {
-            recyclerListView.scrollToPosition(1);
+            recyclerListView.scrollToPosition(0);
         }
     }
 
@@ -409,13 +409,14 @@ public void prepare(List selectedObjects, int type) {
         updateList(false, true);
         headerView.setText(getTitle());
         updateActionButton(false);
+        scrollToTop(false);
     }
 
     private void updateSection() {
         String text;
         switch (type) {
             case TYPE_CHANNEL:
-                text = LocaleController.formatString("BoostingSelectUpTo", R.string.BoostingSelectUpTo, BoostRepository.giveawayAddPeersMax());
+                text = LocaleController.formatPluralString("BoostingSelectUpToPlural", (int) BoostRepository.giveawayAddPeersMax());
                 sectionCell.setLayerHeight(32);
                 break;
             case TYPE_USER:
@@ -423,7 +424,7 @@ private void updateSection() {
                 sectionCell.setLayerHeight(32);
                 break;
             case TYPE_COUNTRY:
-                text = LocaleController.formatString("BoostingSelectUpTo", R.string.BoostingSelectUpToCountries, BoostRepository.giveawayCountriesMax());
+                text = LocaleController.formatPluralString("BoostingSelectUpToCountriesPlural", (int) BoostRepository.giveawayCountriesMax());
                 sectionCell.setLayerHeight(1);
                 break;
             default:
@@ -436,13 +437,13 @@ private void showMaximumUsersToast() {
         String text = "";
         switch (type) {
             case TYPE_CHANNEL:
-                text = LocaleController.formatString("BoostingSelectUpToWarningChannels", R.string.BoostingSelectUpToWarningChannels, BoostRepository.giveawayAddPeersMax());
+                text = LocaleController.formatPluralString("BoostingSelectUpToWarningChannelsPlural", (int) BoostRepository.giveawayAddPeersMax());
                 break;
             case TYPE_USER:
                 text = LocaleController.getString("BoostingSelectUpToWarningUsers", R.string.BoostingSelectUpToWarningUsers);
                 break;
             case TYPE_COUNTRY:
-                text = LocaleController.formatString("BoostingSelectUpToWarningCountries", R.string.BoostingSelectUpToWarningCountries, BoostRepository.giveawayCountriesMax());
+                text = LocaleController.formatPluralString("BoostingSelectUpToWarningCountriesPlural", (int) BoostRepository.giveawayCountriesMax());
                 break;
         }
         if (selectedObjectsListener != null) {
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/GiftInfoAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/GiftInfoAdapter.java
index 68226d836b..386348ff9d 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/GiftInfoAdapter.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/adapters/GiftInfoAdapter.java
@@ -140,7 +140,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi
             case HOLDER_TYPE_LINK: {
                 LinkCell cell = (LinkCell) holder.itemView;
                 cell.setSlug(slug);
-                if (giftCode.boost != null) {
+                if (giftCode.boost != null && slug == null) {
                     cell.hideSlug(this::onHiddenLinkClicked);
                 }
                 //unclaimed and slug visible only for giveaway creator
@@ -230,7 +230,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi
                         dismiss();
                     }
                 });
-                if (giftCode.boost != null || giftCode.to_id == NO_USER_ID) {
+                if (giftCode.boost != null || giftCode.flags == -1) {
                     cell.setCloseStyle();
                     cell.setOnClickListener(v -> dismiss());
                 }
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/BoostTypeSingleCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/BoostTypeSingleCell.java
index 5bbc92f80b..13e5c8febd 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/BoostTypeSingleCell.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/BoostTypeSingleCell.java
@@ -25,7 +25,7 @@ public void setGiveaway(TL_stories.TL_prepaidGiveaway prepaidGiveaway) {
         subtitleTextView.setTextColor(Theme.getColor(Theme.key_dialogTextGray3, resourcesProvider));
         avatarDrawable.setAvatarType(AvatarDrawable.AVATAR_TYPE_GIFT);
         titleTextView.setText(LocaleController.formatString("BoostingPreparedGiveawayOne", R.string.BoostingPreparedGiveawayOne));
-        String subtitle = LocaleController.formatString("BoostingPreparedGiveawaySubscriptions", R.string.BoostingPreparedGiveawaySubscriptions, prepaidGiveaway.quantity, LocaleController.formatPluralString("Months", prepaidGiveaway.months));
+        String subtitle = LocaleController.formatPluralString("BoostingPreparedGiveawaySubscriptionsPlural", prepaidGiveaway.quantity, LocaleController.formatPluralString("Months", prepaidGiveaway.months));
         setSubtitle(subtitle);
         if (prepaidGiveaway.months == 12) {
             avatarDrawable.setColor(0xFFff8560, 0xFFd55246);
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/SubtitleWithCounterCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/SubtitleWithCounterCell.java
index cfc67861f8..5481493599 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/SubtitleWithCounterCell.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/SubtitleWithCounterCell.java
@@ -34,7 +34,7 @@ public SubtitleWithCounterCell(@NonNull Context context, Theme.ResourcesProvider
     }
 
     public void updateCounter(boolean animated, int count) {
-        CharSequence text = LocaleController.formatPluralString("BoostingSubscriptionsCount", count, count);
+        CharSequence text = LocaleController.formatPluralString("BoostingBoostsCountTitle", count, count);
         counterTextView.setText(text, animated);
     }
 }
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/msg/GiveawayMessageCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/msg/GiveawayMessageCell.java
index 17ac9963b7..6acfa288a3 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/msg/GiveawayMessageCell.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/msg/GiveawayMessageCell.java
@@ -2,6 +2,8 @@
 
 import static org.telegram.messenger.AndroidUtilities.dp;
 import static org.telegram.messenger.AndroidUtilities.replaceTags;
+import static org.telegram.messenger.LocaleController.formatPluralString;
+import static org.telegram.messenger.LocaleController.formatPluralStringComma;
 import static org.telegram.messenger.LocaleController.formatString;
 import static org.telegram.messenger.LocaleController.getString;
 
@@ -71,10 +73,10 @@ public class GiveawayMessageCell {
     private final ChatMessageCell parentView;
     private final ImageReceiver giftReceiver;
 
-    private final CharSequence[] chatTitles = new CharSequence[10];
-    private final float[] chatTitleWidths = new float[10];
-    private final boolean[] needNewRow = new boolean[10];
-    private final Rect[] clickRect = new Rect[10];
+    private CharSequence[] chatTitles = new CharSequence[10];
+    private float[] chatTitleWidths = new float[10];
+    private boolean[] needNewRow = new boolean[10];
+    private Rect[] clickRect = new Rect[10];
     private boolean[] avatarVisible;
     private int measuredHeight = 0;
     private int measuredWidth = 0;
@@ -218,6 +220,7 @@ public void setMessageContent(MessageObject messageObject, int parentWidth, int
         createImages();
         setGiftImage(messageObject);
         TLRPC.TL_messageMediaGiveaway giveaway = (TLRPC.TL_messageMediaGiveaway) messageObject.messageOwner.media;
+        checkArraysLimits(giveaway.channels.size());
 
         int giftSize = AndroidUtilities.dp(148);
         int maxWidth;
@@ -231,8 +234,13 @@ public void setMessageContent(MessageObject messageObject, int parentWidth, int
         SpannableStringBuilder topStringBuilder = new SpannableStringBuilder(giveawayPrizes);
         topStringBuilder.setSpan(new RelativeSizeSpan(1.05f), 0, giveawayPrizes.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
         topStringBuilder.append("\n");
-        CharSequence subTitle = replaceTags(formatString("BoostingGiveawayMsgInfo", R.string.BoostingGiveawayMsgInfo, giveaway.quantity, LocaleController.formatPluralString("BoldMonths", giveaway.months)));
-        topStringBuilder.append(subTitle);
+        SpannableStringBuilder subTitleBuilder = new SpannableStringBuilder();
+        subTitleBuilder.append(replaceTags(formatPluralStringComma("BoostingGiveawayMsgInfoPlural1", giveaway.quantity)));
+        subTitleBuilder.append("\n");
+        subTitleBuilder.append(replaceTags(formatPluralString("BoostingGiveawayMsgInfoPlural2", giveaway.quantity, LocaleController.formatPluralString("BoldMonths", giveaway.months))));
+        CharSequence subTitle = subTitleBuilder;
+
+        topStringBuilder.append(subTitleBuilder);
         topStringBuilder.append("\n\n");
 
         topStringBuilder.setSpan(new RelativeSizeSpan(0.5f), topStringBuilder.length() - 1, topStringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
@@ -243,9 +251,9 @@ public void setMessageContent(MessageObject messageObject, int parentWidth, int
         topStringBuilder.append("\n");
 
         if (giveaway.only_new_subscribers) {
-            topStringBuilder.append(getString("BoostingGiveawayMsgNewSubs", R.string.BoostingGiveawayMsgNewSubs));
+            topStringBuilder.append(formatPluralString("BoostingGiveawayMsgNewSubsPlural", giveaway.channels.size()));
         } else {
-            topStringBuilder.append(getString("BoostingGiveawayMsgAllSubs", R.string.BoostingGiveawayMsgAllSubs));
+            topStringBuilder.append(formatPluralString("BoostingGiveawayMsgAllSubsPlural", giveaway.channels.size()));
         }
 
         CharSequence dateTitle = replaceTags(getString("BoostingWinnersDate", R.string.BoostingWinnersDate));
@@ -268,6 +276,10 @@ public void setMessageContent(MessageObject messageObject, int parentWidth, int
             maxRowLength = (int) Math.max(maxRowLength, Math.ceil(bottomLayout.getLineWidth(a)));
         }
 
+        if (maxRowLength < dp(180)) {
+            maxRowLength = dp(180);
+        }
+
         if (giveaway.countries_iso2.size() > 0) {
             List countriesWithFlags = new ArrayList<>();
             for (String iso2 : giveaway.countries_iso2) {
@@ -275,7 +287,7 @@ public void setMessageContent(MessageObject messageObject, int parentWidth, int
                 String flag = LocaleController.getLanguageFlag(iso2);
                 SpannableStringBuilder builder = new SpannableStringBuilder();
                 if (flag != null) {
-                    builder.append(flag).append(" ");
+                    builder.append(flag).append("\u00A0");
                 }
                 builder.append(countryName);
                 countriesWithFlags.add(builder);
@@ -529,6 +541,28 @@ private void createImages() {
         }
     }
 
+    private void checkArraysLimits(int channelsCount) {
+        if (avatarImageReceivers.length < channelsCount) {
+            int oldLength = avatarImageReceivers.length;
+            avatarImageReceivers = Arrays.copyOf(avatarImageReceivers, channelsCount);
+            avatarDrawables = Arrays.copyOf(avatarDrawables, channelsCount);
+            avatarVisible = Arrays.copyOf(avatarVisible, channelsCount);
+            chatTitles = Arrays.copyOf(chatTitles, channelsCount);
+            chatTitleWidths = Arrays.copyOf(chatTitleWidths, channelsCount);
+            needNewRow = Arrays.copyOf(needNewRow, channelsCount);
+            clickRect = Arrays.copyOf(clickRect, channelsCount);
+
+            for (int i = oldLength - 1; i < channelsCount; i++) {
+                avatarImageReceivers[i] = new ImageReceiver(parentView);
+                avatarImageReceivers[i].setAllowLoadingOnAttachedOnly(true);
+                avatarImageReceivers[i].setRoundRadius(AndroidUtilities.dp(12));
+                avatarDrawables[i] = new AvatarDrawable();
+                avatarDrawables[i].setTextSize(AndroidUtilities.dp(18));
+                clickRect[i] = new Rect();
+            }
+        }
+    }
+
     private void setGiftImage(MessageObject messageObject) {
         TLRPC.TL_messageMediaGiveaway giveaway = (TLRPC.TL_messageMediaGiveaway) messageObject.messageOwner.media;
         TLRPC.TL_messages_stickerSet set;
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/selector/SelectorCountryCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/selector/SelectorCountryCell.java
index 6ac63b97bb..22dc8de9e3 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/selector/SelectorCountryCell.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/selector/SelectorCountryCell.java
@@ -67,25 +67,14 @@ public void setCountry(TLRPC.TL_help_country country, boolean divider) {
     private CharSequence getCountryNameWithFlag(TLRPC.TL_help_country country) {
         SpannableStringBuilder sb = new SpannableStringBuilder();
         String flag = LocaleController.getLanguageFlag(country.iso2);
-        if (!LocaleController.isRTL) {
-            if (flag != null) {
-                sb.append(flag).append(" ");
-                sb.setSpan(new SpaceDrawable(16), flag.length(), flag.length() + 1, 0);
-            } else {
-                sb.append(" ");
-                sb.setSpan(new SpaceDrawable(34), 0, 1, 0);
-            }
-            sb.append(country.default_name);
+        if (flag != null) {
+            sb.append(flag).append(" ");
+            sb.setSpan(new SpaceDrawable(16), flag.length(), flag.length() + 1, 0);
         } else {
-            sb.append(country.default_name);
-            if (flag != null) {
-                sb.append(" ").append(flag);
-                sb.setSpan(new SpaceDrawable(16), country.default_name.length(), country.default_name.length() + 1, 0);
-            } else {
-                sb.append(" ");
-                sb.setSpan(new SpaceDrawable(34), country.default_name.length(), country.default_name.length() + 1, 0);
-            }
+            sb.append(" ");
+            sb.setSpan(new SpaceDrawable(34), 0, 1, 0);
         }
+        sb.append(country.default_name);
         return sb;
     }
 
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/statistics/GiftedUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/statistics/GiftedUserCell.java
index 3900cab7a3..57e6d80cdc 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/statistics/GiftedUserCell.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/boosts/cells/statistics/GiftedUserCell.java
@@ -105,8 +105,8 @@ public void setStatus(TL_stories.TL_boost boost) {
                 avatarImageView.setForUserOrChat(null, avatarDrawable);
                 nameTextView.setRightDrawable(null);
             }
-            String date = LocaleController.getInstance().formatterScheduleDay.format(new Date(boost.date * 1000L));
-            String time = LocaleController.getInstance().formatterDay.format(new Date(boost.date * 1000L));
+            String date = LocaleController.getInstance().formatterScheduleDay.format(new Date(boost.expires * 1000L));
+            String time = LocaleController.getInstance().formatterDay.format(new Date(boost.expires * 1000L));
 
             statusTextView.setText(LocaleController.formatString("BoostingShortMonths", R.string.BoostingShortMonths, months) + " • " + LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, date, time));
 
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/QuoteHighlight.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/QuoteHighlight.java
index 47ab9a8a80..32eed94218 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/QuoteHighlight.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/QuoteHighlight.java
@@ -76,6 +76,9 @@ public QuoteHighlight(
             final int blockEnd = Math.min(end - block.charactersOffset, block.charactersEnd - block.charactersOffset);
 
             currentOffsetX = -offsetX;
+            if (block.code && !block.quote) {
+                currentOffsetX += dp(10);
+            }
             currentOffsetY = block.textYOffset + block.padTop;
             minX = block.quote ? dp(10) : 0;
 
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReplyMessageLine.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReplyMessageLine.java
index 8a2ea05dc3..e9095d5312 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReplyMessageLine.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReplyMessageLine.java
@@ -45,6 +45,7 @@ public class ReplyMessageLine {
     private float lastHeight;
     private Path color2Path = new Path();
     private Path color3Path = new Path();
+    private int switchedCount = 0;
 
     private AnimatedEmojiDrawable.SwapAnimatedEmojiDrawable emoji;
 
@@ -58,6 +59,7 @@ public class ReplyMessageLine {
     public final AnimatedFloat color3Alpha;
     public final AnimatedFloat emojiLoadedT;
     public final AnimatedFloat loadingStateT;
+    public final AnimatedFloat switchStateT;
 
     public ReplyMessageLine(View view) {
         this.parentView = view;
@@ -85,6 +87,7 @@ public void onViewDetachedFromWindow(@NonNull View v) {
         color3Alpha = new AnimatedFloat(view, 0, 400, CubicBezierInterpolator.EASE_OUT_QUINT);
         emojiLoadedT = new AnimatedFloat(view, 0, 440, CubicBezierInterpolator.EASE_OUT_QUINT);
         loadingStateT = new AnimatedFloat(view, 0, 320, CubicBezierInterpolator.EASE_OUT_QUINT);
+        switchStateT = new AnimatedFloat(view, 0, 320, CubicBezierInterpolator.EASE_OUT_QUINT);
     }
 
     public int getColor() {
@@ -95,7 +98,21 @@ public int getBackgroundColor() {
         return backgroundColor;
     }
 
+    public void setBackgroundColor(int backgroundColor) {
+        this.backgroundColor = backgroundColor;
+    }
+
+    private int wasMessageId;
+    private int wasColorId;
     private void resolveColor(MessageObject messageObject, int colorId, Theme.ResourcesProvider resourcesProvider) {
+        if (wasColorId != colorId) {
+            final int msgId = messageObject != null ? messageObject.getId() : 0;
+            if (msgId == wasMessageId) {
+                switchedCount++;
+            }
+            wasColorId = colorId;
+            wasMessageId = msgId;
+        }
         if (colorId < 7) {
             color1 = color2 = color3 = Theme.getColor(Theme.keys_avatar_nameInMessage[colorId], resourcesProvider);
             hasColor2 = hasColor3 = false;
@@ -351,8 +368,6 @@ public void drawLine(Canvas canvas, RectF rect, float alpha) {
             canvas.drawPaint(color1Paint);
             color1Paint.setAlpha(wasAlpha);
 
-            canvas.clipPath(lineClipPath);
-
             incrementLoadingT();
 
             float x = (float) Math.pow(loadingT / 240f / 4f, .85f) * 4f;
@@ -372,7 +387,6 @@ public void drawLine(Canvas canvas, RectF rect, float alpha) {
 
             parentView.invalidate();
         }
-
         canvas.drawPaint(color1Paint);
         final float color2Alpha = this.color2Alpha.set(hasColor2);
         if (color2Alpha > 0) {
@@ -387,7 +401,8 @@ public void drawLine(Canvas canvas, RectF rect, float alpha) {
             } else {
                 fh = rect.height() - Math.floorMod((int) rect.height(), dp(6.33f + 3 + 3.33f));
             }
-            canvas.translate(0, -((loadingTranslationT + (reversedOut ? 100 : 0)) / 1000f * dp(30) % fh));
+
+            canvas.translate(0, -((loadingTranslationT + switchStateT.set(switchedCount * 425) + (reversedOut ? 100 : 0)) / 1000f * dp(30) % fh));
 
             checkColorPathes(rect.height() * 2);
             int wasAlpha = color2Paint.getAlpha();
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Text.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Text.java
index c3f5275146..9161dba4fc 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Text.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Text.java
@@ -42,6 +42,10 @@ public void setText(CharSequence text) {
         left = layout.getLineCount() > 0 ? layout.getLineLeft(0) : 0;
     }
 
+    public float getTextSize() {
+        return paint.getTextSize();
+    }
+
     public boolean isEmpty() {
         return layout == null || TextUtils.isEmpty(layout.getText());
     }
@@ -121,6 +125,10 @@ public float getWidth() {
         return ellipsizeWidth >= 0 ? Math.min(ellipsizeWidth, width) : width;
     }
 
+    public float getCurrentWidth() {
+        return width;
+    }
+
     @NonNull
     public CharSequence getText() {
         if (layout == null || layout.getText() == null) {
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 8e97508c10..57b592b66c 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert2.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TranslateAlert2.java
@@ -337,10 +337,13 @@ public static TLRPC.TL_textWithEntities preprocess(TLRPC.TL_textWithEntities sou
                     newEntity.length = entity.length;
                     received.entities.set(i, newEntity);
                 }
+            } else if (entity instanceof TLRPC.TL_messageEntityPre) {
+                if (source != null && source.entities != null && i < source.entities.size() && source.entities.get(i) instanceof TLRPC.TL_messageEntityPre) {
+                    entity.language = source.entities.get(i).language;
+                }
             }
         }
         if (source != null && source.text != null && !source.entities.isEmpty()) {
-
             HashMap> srcIndexes = groupEmojiRanges(source.text);
             HashMap> destIndexes = groupEmojiRanges(received.text);
 
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java
index f7396f248e..da3806807a 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java
@@ -1408,13 +1408,13 @@ public void showWithAction(ArrayList dialogIds, int action, Object infoObj
                     infoTextView.setText(LocaleController.getString("BoostingSelectUpToWarningUsers", R.string.BoostingSelectUpToWarningUsers));
                     break;
                 case ACTION_BOOSTING_SELECTOR_WARNING_CHANNEL:
-                    infoTextView.setText(LocaleController.formatString("BoostingSelectUpToWarningChannels", R.string.BoostingSelectUpToWarningChannels, BoostRepository.giveawayAddPeersMax()));
+                    infoTextView.setText(LocaleController.formatPluralString("BoostingSelectUpToWarningChannelsPlural", (int) BoostRepository.giveawayAddPeersMax()));
                     break;
                 case ACTION_BOOSTING_SELECTOR_WARNING_COUNTRY:
-                    infoTextView.setText(LocaleController.formatString("BoostingSelectUpToWarningCountries", R.string.BoostingSelectUpToWarningCountries, BoostRepository.giveawayCountriesMax()));
+                    infoTextView.setText(LocaleController.formatPluralString("BoostingSelectUpToWarningCountriesPlural", (int) BoostRepository.giveawayCountriesMax()));
                     break;
                 case ACTION_BOOSTING_AWAIT:
-                    infoTextView.setText(AndroidUtilities.replaceTags(LocaleController.formatString("BoostingWaitWarning", R.string.BoostingWaitWarning, BoostRepository.boostsPerSentGift())));
+                    infoTextView.setText(AndroidUtilities.replaceTags(LocaleController.formatPluralString("BoostingWaitWarningPlural", BoostRepository.boostsPerSentGift())));
                     break;
             }
             layoutParams.leftMargin = AndroidUtilities.dp(58);
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 fe9d798413..fe24f98937 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ViewPagerFixed.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ViewPagerFixed.java
@@ -110,16 +110,20 @@ protected void onTabAnimationUpdate(boolean manual) {
     public float getPositionAnimated() {
         float position = 0;
         if (viewPages[0] != null && viewPages[0].getVisibility() == View.VISIBLE) {
-            final float t = Utilities.clamp(1f - Math.abs(viewPages[0].getTranslationX() / (float) AndroidUtilities.displaySize.x), 1, 0);
+            final float t = Utilities.clamp(1f - Math.abs(viewPages[0].getTranslationX() / getAvailableTranslationX()), 1, 0);
             position += currentPosition * t;
         }
         if (viewPages[1] != null && viewPages[1].getVisibility() == View.VISIBLE) {
-            final float t = Utilities.clamp(1f - Math.abs(viewPages[1].getTranslationX() / (float) AndroidUtilities.displaySize.x), 1, 0);
+            final float t = Utilities.clamp(1f - Math.abs(viewPages[1].getTranslationX() / getAvailableTranslationX()), 1, 0);
             position += nextPosition * t;
         }
         return position;
     }
 
+    protected float getAvailableTranslationX() {
+        return (float) AndroidUtilities.displaySize.x;
+    }
+
     protected boolean canScroll(MotionEvent e) {
         return true;
     }
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 712727b0b5..5530916e25 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
@@ -771,7 +771,7 @@ public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end,
                 layout = StaticLayout.Builder.obtain(sb, 0, sb.length(), textLayout.getPaint(), textLayout.getWidth())
                         .setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY)
                         .setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_NONE)
-                        .setAlignment(Layout.Alignment.ALIGN_NORMAL)
+                        .setAlignment(textLayout.getAlignment())
                         .setLineSpacing(textLayout.getSpacingAdd(), textLayout.getSpacingMultiplier())
                         .build();
             } else {
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java
index f333a1e56a..e319d94656 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java
@@ -5589,7 +5589,9 @@ public void onAnimationEnd(Animator animation) {
                         notificationsLocker.unlock();
                         authHintCellAnimating = false;
                         authHintCellProgress = visible ? 1f : 0;
-                        fragmentView.requestLayout();
+                        if (fragmentView != null) {
+                            fragmentView.requestLayout();
+                        }
                         viewPages[0].listView.requestLayout();
                         viewPages[0].listView.setTranslationY(0);
                         if (!visible) {
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java
index 08ca4b5a93..83ef8ff411 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java
@@ -6503,8 +6503,12 @@ public void onAnimationEnd(Animator animation) {
             }
             actionBarLayout.animateThemedValues(theme, accentId, nightTheme, instant, calcInBackgroundEnd);
             if (AndroidUtilities.isTablet()) {
-                layersActionBarLayout.animateThemedValues(theme, accentId, nightTheme, instant);
-                rightActionBarLayout.animateThemedValues(theme, accentId, nightTheme, instant);
+                if (layersActionBarLayout != null) {
+                    layersActionBarLayout.animateThemedValues(theme, accentId, nightTheme, instant);
+                }
+                if (rightActionBarLayout != null) {
+                    rightActionBarLayout.animateThemedValues(theme, accentId, nightTheme, instant);
+                }
             }
         } else if (id == NotificationCenter.notificationsCountUpdated) {
             if (sideMenu != null) {
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java
index 1c084e107c..da47eec0bc 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/PeerColorActivity.java
@@ -3,6 +3,7 @@
 import static android.content.DialogInterface.BUTTON_NEGATIVE;
 import static org.telegram.messenger.AndroidUtilities.dp;
 import static org.telegram.messenger.AndroidUtilities.dpf2;
+import static org.telegram.messenger.AndroidUtilities.getPath;
 import static org.telegram.ui.Components.Premium.LimitReachedBottomSheet.TYPE_BOOSTS_FOR_COLOR;
 import static org.telegram.ui.Components.Premium.LimitReachedBottomSheet.TYPE_BOOSTS_FOR_USERS;
 
@@ -16,7 +17,9 @@
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
+import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
+import android.icu.util.Measure;
 import android.os.Build;
 import android.os.Bundle;
 import android.text.SpannableStringBuilder;
@@ -47,6 +50,7 @@
 import org.telegram.messenger.NotificationCenter;
 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.ActionBar;
 import org.telegram.ui.ActionBar.AlertDialog;
@@ -84,7 +88,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente
     private RecyclerView.Adapter listAdapter;
     private FrameLayout buttonContainer;
     private ButtonWithCounterView button;
-    private PeerColorPicker peerColorPicker;
+    private PeerColorGrid peerColorPicker;
 
     private int selectedColor;
     private long selectedEmoji;
@@ -98,6 +102,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente
     int infoRow;
     int iconRow;
     int info2Row;
+    int buttonRow;
 
     int rowCount;
 
@@ -105,6 +110,7 @@ public class PeerColorActivity extends BaseFragment implements NotificationCente
     private static final int VIEW_TYPE_COLOR_PICKER = 1;
     private static final int VIEW_TYPE_INFO = 2;
     private static final int VIEW_TYPE_ICON = 3;
+    private static final int VIEW_TYPE_BUTTONPAD = 5;
 
     public PeerColorActivity(long dialogId) {
         super();
@@ -183,13 +189,25 @@ public void onItemClick(int id) {
 
         FrameLayout frameLayout = new FrameLayout(context);
 
-        listView = new RecyclerListView(context);
-        ((DefaultItemAnimator)listView.getItemAnimator()).setSupportsChangeAnimations(false);
+        listView = new RecyclerListView(context) {
+            @Override
+            protected void onMeasure(int widthSpec, int heightSpec) {
+                super.onMeasure(widthSpec, heightSpec);
+                updateButtonY();
+            }
+
+            @Override
+            protected void onLayout(boolean changed, int l, int t, int r, int b) {
+                super.onLayout(changed, l, t, r, b);
+                updateButtonY();
+            }
+        };
+        ((DefaultItemAnimator) listView.getItemAnimator()).setSupportsChangeAnimations(false);
         listView.setLayoutManager(new LinearLayoutManager(context));
         listView.setAdapter(listAdapter = new RecyclerListView.SelectionAdapter() {
             @Override
             public boolean isEnabled(RecyclerView.ViewHolder holder) {
-                return holder.getItemViewType() == VIEW_TYPE_COLOR_PICKER || holder.getItemViewType() == VIEW_TYPE_ICON;
+                return holder.getItemViewType() == VIEW_TYPE_ICON;
             }
 
             @NonNull
@@ -211,18 +229,12 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int
                         view = cell;
                         break;
                     case VIEW_TYPE_COLOR_PICKER:
-                        PeerColorPicker colorPicker = peerColorPicker = new PeerColorPicker(context, currentAccount, getResourceProvider());
-                        colorPicker.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite, getResourceProvider()));
+                        PeerColorGrid colorPicker = peerColorPicker = new PeerColorGrid(context, currentAccount);
+                        colorPicker.setBackgroundColor(getThemedColor(Theme.key_windowBackgroundWhite));
                         colorPicker.setSelected(selectedColor);
-                        colorPicker.layoutManager.scrollToPositionWithOffset(colorPicker.selectedPosition, AndroidUtilities.displaySize.x / 2);
-                        colorPicker.setOnItemClickListener((item, position) -> {
-                            selectedColor = colorPicker.toColorId(position);
-                            colorPicker.setSelectedPosition(position);
-                            if (item.getLeft() - colorPicker.getPaddingLeft() < AndroidUtilities.dp(24)) {
-                                colorPicker.smoothScrollBy(position == 0 ? Math.max(-(item.getLeft() - colorPicker.getPaddingLeft()), -AndroidUtilities.dp(64)) : -AndroidUtilities.dp(64), 0);
-                            } else if (item.getRight() - colorPicker.getPaddingLeft() > AndroidUtilities.displaySize.x - colorPicker.getPaddingLeft() - colorPicker.getPaddingRight() - AndroidUtilities.dp(24)) {
-                                colorPicker.smoothScrollBy(position == colorPicker.adapter.getItemCount() - 1 ? Math.min(AndroidUtilities.displaySize.x - item.getRight() - colorPicker.getPaddingRight(), AndroidUtilities.dp(64)) : AndroidUtilities.dp(64), 0);
-                            }
+                        colorPicker.setOnColorClick(colorId -> {
+                            selectedColor = colorId;
+                            colorPicker.setSelected(colorId);
                             updateMessages();
                             if (setReplyIconCell != null) {
                                 setReplyIconCell.invalidate();
@@ -230,6 +242,14 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int
                         });
                         view = colorPicker;
                         break;
+                    case VIEW_TYPE_BUTTONPAD:
+                        view = new View(context) {
+                            @Override
+                            protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+                                super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(dp(14 + 48 + 14), MeasureSpec.EXACTLY));
+                            }
+                        };
+                        break;
                     case VIEW_TYPE_ICON:
                         SetReplyIconCell setcell = setReplyIconCell = new SetReplyIconCell(context);
                         setcell.update(false);
@@ -285,6 +305,9 @@ public int getItemViewType(int position) {
                 if (position == iconRow) {
                     return VIEW_TYPE_ICON;
                 }
+                if (position == buttonRow) {
+                    return VIEW_TYPE_BUTTONPAD;
+                }
                 if (position == getItemCount() - 1) {
                     return 4;
                 }
@@ -314,6 +337,12 @@ public int getItemViewType(int position) {
         buttonContainer.addView(button, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48));
 
         frameLayout.addView(buttonContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM));
+        listView.setOnScrollListener(new RecyclerView.OnScrollListener() {
+            @Override
+            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
+                updateButtonY();
+            }
+        });
 
         fragmentView = contentView = frameLayout;
 
@@ -323,6 +352,29 @@ public int getItemViewType(int position) {
         return contentView;
     }
 
+    private void updateButtonY() {
+        if (buttonContainer == null) {
+            return;
+        }
+        final int lastPosition = listAdapter.getItemCount() - 1;
+        boolean foundLastPosition = false;
+        int maxTop = 0;
+        for (int i = 0; i < listView.getChildCount(); ++i) {
+            View child = listView.getChildAt(i);
+            final int position = listView.getChildAdapterPosition(child);
+            if (position != RecyclerListView.NO_POSITION && position <= lastPosition) {
+                maxTop = Math.max(maxTop, child.getTop());
+                if (position == lastPosition) {
+                    foundLastPosition = true;
+                }
+            }
+        }
+        if (!foundLastPosition) {
+            maxTop = listView.getMeasuredHeight();
+        }
+        buttonContainer.setTranslationY(Math.max(0, maxTop - (listView.getMeasuredHeight() - dp(14 + 48 + 14))));
+    }
+
     private void showBoostLimit(boolean error) {
         getMessagesController().getBoostsController().getBoostsStats(dialogId, boostsStatus -> {
             if (error || boostsStatus.level < getMessagesController().channelColorLevelMin) {
@@ -688,9 +740,9 @@ private void updateRows() {
         rowCount = 0;
         previewRow = rowCount++;
         colorPickerRow = rowCount++;
-        infoRow = rowCount++;
         iconRow = rowCount++;
-        info2Row = rowCount++;
+        infoRow = rowCount++;
+        buttonRow = rowCount++;
     }
 
     @Override
@@ -1136,6 +1188,276 @@ protected void dispatchDraw(Canvas canvas) {
         }
     }
 
+    public static class PeerColorGrid extends View {
+
+        public class ColorButton {
+            private final Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+            private final Paint paint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
+            private final Paint paint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
+            private final Paint paint3 = new Paint(Paint.ANTI_ALIAS_FLAG);
+            private final Path circlePath = new Path();
+            private final Path color2Path = new Path();
+            private boolean hasColor2, hasColor3;
+
+            private final ButtonBounce bounce = new ButtonBounce(PeerColorGrid.this);
+
+            public ColorButton() {
+                backgroundPaint.setStyle(Paint.Style.STROKE);
+            }
+
+            public void setBackgroundColor(int backgroundColor) {
+                backgroundPaint.setColor(backgroundColor);
+            }
+
+            public void set(int color) {
+                hasColor2 = hasColor3 = false;
+                paint1.setColor(color);
+            }
+
+            public void set(int color1, int color2) {
+                hasColor2 = true;
+                hasColor3 = false;
+                paint1.setColor(color1);
+                paint2.setColor(color2);
+            }
+
+            public void set(MessagesController.PeerColor color) {
+                if (color == null) {
+                    return;
+                }
+                if (Theme.isCurrentThemeDark() && color.hasColor2() && !color.hasColor3()) {
+                    paint1.setColor(color.getColor2());
+                    paint2.setColor(color.getColor1());
+                } else {
+                    paint1.setColor(color.getColor1());
+                    paint2.setColor(color.getColor2());
+                }
+                paint3.setColor(color.getColor3());
+                hasColor2 = color.hasColor2();
+                hasColor3 = color.hasColor3();
+            }
+
+            private boolean selected;
+            private final AnimatedFloat selectedT = new AnimatedFloat(PeerColorGrid.this, 0, 320, CubicBezierInterpolator.EASE_OUT_QUINT);
+            public void setSelected(boolean selected, boolean animated) {
+                this.selected = selected;
+                if (!animated) {
+                    selectedT.set(selected, true);
+                }
+                invalidate();
+            }
+
+            private static final int VIEW_SIZE_DP = 56;
+            private static final int CIRCLE_RADIUS_DP = 20;
+
+            public int id;
+            private final RectF bounds = new RectF();
+            public final RectF clickBounds = new RectF();
+            public void layout(int id, RectF bounds) {
+                this.id = id;
+                this.bounds.set(bounds);
+            }
+            public void layoutClickBounds(RectF bounds) {
+                this.clickBounds.set(bounds);
+            }
+
+            protected void draw(Canvas canvas) {
+                canvas.save();
+                final float s = bounce.getScale(.05f);
+                canvas.scale(s, s, bounds.centerX(), bounds.centerY());
+
+                canvas.save();
+                circlePath.rewind();
+                circlePath.addCircle(bounds.centerX(), bounds.centerY(), Math.min(bounds.height() / 2f, bounds.width() / 2f), Path.Direction.CW);
+                canvas.clipPath(circlePath);
+                canvas.drawPaint(paint1);
+                if (hasColor2) {
+                    color2Path.rewind();
+                    color2Path.moveTo(bounds.right, bounds.top);
+                    color2Path.lineTo(bounds.right, bounds.bottom);
+                    color2Path.lineTo(bounds.left, bounds.bottom);
+                    color2Path.close();
+                    canvas.drawPath(color2Path, paint2);
+                }
+                canvas.restore();
+
+                if (hasColor3) {
+                    canvas.save();
+                    final float color3Size = (bounds.width() * .315f);
+                    AndroidUtilities.rectTmp.set(
+                        bounds.centerX() - color3Size / 2f,
+                        bounds.centerY() - color3Size / 2f,
+                        bounds.centerX() + color3Size / 2f,
+                        bounds.centerY() + color3Size / 2f
+                    );
+                    canvas.rotate(45f, bounds.centerX(), bounds.centerY());
+                    canvas.drawRoundRect(AndroidUtilities.rectTmp, dp(2.33f), dp(2.33f), paint3);
+                    canvas.restore();
+                }
+
+                final float selectT = selectedT.set(selected);
+
+                if (selectT > 0) {
+                    backgroundPaint.setStrokeWidth(dpf2(2));
+                    canvas.drawCircle(
+                        bounds.centerX(), bounds.centerY(),
+                        Math.min(bounds.height() / 2f, bounds.width() / 2f) + backgroundPaint.getStrokeWidth() * AndroidUtilities.lerp(.5f, -2f, selectT),
+                        backgroundPaint
+                    );
+                }
+
+                canvas.restore();
+            }
+
+            private boolean pressed;
+            public boolean isPressed() {
+                return pressed;
+            }
+
+            public void setPressed(boolean pressed) {
+                bounce.setPressed(this.pressed = pressed);
+            }
+        }
+
+        private int currentAccount;
+
+        private ColorButton[] buttons;
+
+        public PeerColorGrid(Context context, int currentAccount) {
+            super(context);
+            this.currentAccount = currentAccount;
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            final int width = MeasureSpec.getSize(widthMeasureSpec);
+
+            final MessagesController.PeerColors peerColors = MessagesController.getInstance(currentAccount).peerColors;
+            final int colorsCount = 7 + (peerColors == null ? 0 : peerColors.colors.size());
+            final int columns = 7;
+
+            final float iconSize = Math.min(dp(38 + 16), width / (columns + (columns + 1) * .28947f));
+            final float horizontalSeparator = iconSize * .28947f;
+            final float verticalSeparator = iconSize * .315789474f;
+
+            final int rows = colorsCount / columns;
+            final int height = (int) (iconSize * rows + verticalSeparator * (rows + 1));
+
+            setMeasuredDimension(width, height);
+
+            if (buttons == null || buttons.length != colorsCount) {
+                buttons = new ColorButton[colorsCount];
+                for (int i = 0; i < colorsCount; ++i) {
+                    buttons[i] = new ColorButton();
+                    buttons[i].setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite));
+                    if (i < 7) {
+                        buttons[i].set(Theme.getColor(Theme.keys_avatar_nameInMessage[i]));
+                    } else if (peerColors != null) {
+                        buttons[i].set(peerColors.getColor(i));
+                    }
+                }
+            }
+            final float itemsWidth = iconSize * columns + horizontalSeparator * (columns + 1);
+            final float startX = (width - itemsWidth) / 2f + horizontalSeparator;
+            if (buttons != null) {
+                float x = startX, y = verticalSeparator;
+                for (int i = 0; i < buttons.length; ++i) {
+                    AndroidUtilities.rectTmp.set(x, y, x + iconSize, y + iconSize);
+                    buttons[i].layout(i, AndroidUtilities.rectTmp);
+                    AndroidUtilities.rectTmp.inset(-horizontalSeparator / 2, -verticalSeparator / 2);
+                    buttons[i].layoutClickBounds(AndroidUtilities.rectTmp);
+                    buttons[i].setSelected(i == selectedColorId, false);
+
+                    if (i % columns == (columns - 1)) {
+                        x = startX;
+                        y += iconSize + verticalSeparator;
+                    } else {
+                        x += iconSize + horizontalSeparator;
+                    }
+                }
+            }
+        }
+
+        @Override
+        protected void dispatchDraw(Canvas canvas) {
+            if (buttons != null) {
+                for (int i = 0; i < buttons.length; ++i) {
+                    buttons[i].draw(canvas);
+                }
+            }
+            canvas.drawRect(dp(21), getMeasuredHeight() - 1, getMeasuredWidth() - dp(21), getMeasuredHeight(), Theme.dividerPaint);
+        }
+
+        private int selectedColorId = 0;
+        public void setSelected(int colorId) {
+            selectedColorId = colorId;
+            if (buttons != null) {
+                for (int i = 0; i < buttons.length; ++i) {
+                    buttons[i].setSelected(i == colorId, true);
+                }
+            }
+        }
+        public int getColorId() {
+            return selectedColorId;
+        }
+
+        private Utilities.Callback onColorClick;
+        public void setOnColorClick(Utilities.Callback onColorClick) {
+            this.onColorClick = onColorClick;
+        }
+
+        private ColorButton pressedButton;
+        @Override
+        public boolean dispatchTouchEvent(MotionEvent event) {
+            ColorButton button = null;
+            if (buttons != null) {
+                for (int i = 0; i < buttons.length; ++i) {
+                    if (buttons[i].clickBounds.contains(event.getX(), event.getY())) {
+                        button = buttons[i];
+                        break;
+                    }
+                }
+            }
+            if (event.getAction() == MotionEvent.ACTION_DOWN) {
+                pressedButton = button;
+                if (button != null) {
+                    button.setPressed(true);
+                }
+                if (getParent() != null) {
+                    getParent().requestDisallowInterceptTouchEvent(true);
+                }
+            } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
+                if (pressedButton != button) {
+                    if (pressedButton != null) {
+                        pressedButton.setPressed(false);
+                    }
+                    if (button != null) {
+                        button.setPressed(true);
+                    }
+                    if (pressedButton != null && button != null) {
+                        if (onColorClick != null) {
+                            onColorClick.run(button.id);
+                        }
+                    }
+                    pressedButton = button;
+                }
+            } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
+                if (event.getAction() == MotionEvent.ACTION_UP && pressedButton != null) {
+                    if (onColorClick != null) {
+                        onColorClick.run(pressedButton.id);
+                    }
+                }
+                if (buttons != null) {
+                    for (int i = 0; i < buttons.length; ++i) {
+                        buttons[i].setPressed(false);
+                    }
+                }
+                pressedButton = null;
+            }
+            return true;
+        }
+    }
+
     public static class PeerColorDrawable extends Drawable {
 
         public static PeerColorDrawable from(int currentAccount, int colorId) {
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java
index eeba4c11e6..9b2560fc1a 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java
@@ -7926,7 +7926,9 @@ public void getOutline(View view, Outline outline) {
         }
 
         if (usedSurfaceView) {
-            videoPlayer.player.setVideoTextureView(null);
+            if (videoPlayer.player != null) {
+                videoPlayer.player.setVideoTextureView(null);
+            }
             videoPlayer.setSurfaceView(videoSurfaceView);
             videoSurfaceView.setVisibility(View.INVISIBLE);
             waitingForFirstTextureUpload = 2;
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java
index 6182705312..eca71d7da2 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java
@@ -1609,14 +1609,6 @@ public String getFormattedPricePerYear() {
             return googlePlayProductDetails == null ? "" : BillingController.getInstance().formatCurrency(getPricePerYear(), getCurrency(), 6);
         }
 
-        public String getFormattedPricePerMonthRounded() {
-            if (BuildVars.useInvoiceBilling() || subscriptionOption.store_product == null) {
-                return BillingController.getInstance().formatCurrency(getPricePerMonth(), getCurrency(), BillingController.getInstance().getCurrencyExp(getCurrency()), true);
-            }
-
-            return googlePlayProductDetails == null ? "" : BillingController.getInstance().formatCurrency(getPricePerMonth(), getCurrency(), 6, true);
-        }
-
         public String getFormattedPricePerMonth() {
             if (BuildVars.useInvoiceBilling() || subscriptionOption.store_product == null) {
                 return BillingController.getInstance().formatCurrency(getPricePerMonth(), getCurrency());
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java
index 89b41e2658..abd8ade103 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java
@@ -2018,8 +2018,7 @@ public void onItemClick(final int id) {
                     Bundle args = new Bundle();
                     args.putLong("user_id", user.id);
                     args.putBoolean("addContact", true);
-                    presentFragment(new ContactAddActivity(args, resourcesProvider));
-                    wentToAddContacts = true;
+                    openAddToContact(user, args);
                 } else if (id == share_contact) {
                     Bundle args = new Bundle();
                     args.putBoolean("onlySelect", true);
@@ -2033,7 +2032,6 @@ public void onItemClick(final int id) {
                     Bundle args = new Bundle();
                     args.putLong("user_id", userId);
                     presentFragment(new ContactAddActivity(args, resourcesProvider));
-                    wentToAddContacts = true;
                 } else if (id == delete_contact) {
                     final TLRPC.User user = getMessagesController().getUser(userId);
                     if (user == null || getParentActivity() == null) {
@@ -3261,8 +3259,7 @@ public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerVi
                 args.putString("phone", vcardPhone);
                 args.putString("first_name_card", vcardFirstName);
                 args.putString("last_name_card", vcardLastName);
-                presentFragment(new ContactAddActivity(args, resourcesProvider));
-                wentToAddContacts = true;
+                openAddToContact(user, args);
             } else if (position == reportReactionRow) {
                 AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity(), resourcesProvider);
                 builder.setTitle(LocaleController.getString("ReportReaction", R.string.ReportReaction));
@@ -11535,8 +11532,6 @@ private void onTextDetailCellImageClicked(View view) {
         }
     }
 
-    private boolean wentToAddContacts;
-
     @Override
     public void onBecomeFullyVisible() {
         super.onBecomeFullyVisible();
@@ -11550,11 +11545,48 @@ public void onBecomeFullyVisible() {
             combinedDrawable.setIconSize(AndroidUtilities.dp(56), AndroidUtilities.dp(56));
             writeButton.setBackground(combinedDrawable);
         } catch (Exception e) {}
+    }
 
-        if (wentToAddContacts) {
-            updateListAnimated(false);
-            wentToAddContacts = false;
-        }
+    @SuppressLint("NotifyDataSetChanged")
+    private void openAddToContact(TLRPC.User user, Bundle args) {
+        ContactAddActivity contactAddActivity = new ContactAddActivity(args, resourcesProvider);
+        contactAddActivity.setDelegate(() -> {
+            int currentAddToContactsRow = addToContactsRow;
+            if (currentAddToContactsRow >= 0) {
+                if (sharedMediaRow == -1) {
+                    updateRowsIds();
+                    listAdapter.notifyDataSetChanged();
+                } else {
+                    updateListAnimated(false);
+                }
+            }
+
+            if (sharedMediaRow == -1) {
+                if (isInLandscapeMode || AndroidUtilities.isTablet()) {
+                    listView.setPadding(0, AndroidUtilities.dp(88), 0, 0);
+                    expandAnimator.cancel();
+                    expandAnimatorValues[0] = 1f;
+                    expandAnimatorValues[1] = 0f;
+                    setAvatarExpandProgress(1f);
+                    extraHeight = AndroidUtilities.dp(88);
+                } else {
+                    final int actionBarHeight = ActionBar.getCurrentActionBarHeight() + (actionBar.getOccupyStatusBar() ? AndroidUtilities.statusBarHeight : 0);
+                    int ws = View.MeasureSpec.makeMeasureSpec(listView.getMeasuredWidth(), View.MeasureSpec.EXACTLY);
+                    int hs = View.MeasureSpec.makeMeasureSpec(listView.getMeasuredHeight(), View.MeasureSpec.UNSPECIFIED);
+                    int contentHeight = 0;
+                    for (int i = 0; i < listAdapter.getItemCount(); i++) {
+                        RecyclerView.ViewHolder holder = listAdapter.createViewHolder(null, listAdapter.getItemViewType(i));
+                        listAdapter.onBindViewHolder(holder, i);
+                        holder.itemView.measure(ws, hs);
+                        contentHeight += holder.itemView.getMeasuredHeight();
+                    }
+                    int paddingBottom = Math.max(0, fragmentView.getMeasuredHeight() - (contentHeight + AndroidUtilities.dp(88) + actionBarHeight));
+                    listView.setPadding(0, listView.getPaddingTop(), 0, paddingBottom);
+                }
+            }
+            undoView.showWithAction(dialogId, UndoView.ACTION_CONTACT_ADDED, user);
+        });
+        presentFragment(contactAddActivity);
     }
 
     private boolean isQrNeedVisible() {
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java
index 3b5c693f62..47062a7366 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java
@@ -694,7 +694,7 @@ public void onItemClick(final int id) {
         });
 
         avatarContainer.setTitleColors(Theme.getColor(Theme.key_player_actionBarTitle), Theme.getColor(Theme.key_player_actionBarSubtitle));
-        actionBar.setItemsColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2), false);
+        actionBar.setItemsColor(Theme.getColor(Theme.key_player_actionBarTitle), false);
         actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_actionBarActionModeDefaultSelector), false);
         actionBar.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite));
 
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java b/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java
index b2ddaac31d..3fbf8dbb7f 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Stories/PeerStoriesView.java
@@ -2551,6 +2551,17 @@ private void bindInternal(int startFromPosition) {
             avatarDrawable.setInfo(chat);
             headerView.backupImageView.getImageReceiver().setForUserOrChat(chat, avatarDrawable);
             headerView.titleView.setText(chat.title);
+
+            if (chat != null && chat.verified) {
+                Drawable verifyDrawable = ContextCompat.getDrawable(getContext(), R.drawable.verified_profile).mutate();
+                verifyDrawable.setAlpha(255);
+                CombinedDrawable drawable = new CombinedDrawable(verifyDrawable, null);
+                drawable.setFullsize(true);
+                drawable.setCustomSize(AndroidUtilities.dp(16), AndroidUtilities.dp(16));
+                headerView.titleView.setRightDrawable(drawable);
+            } else {
+                headerView.titleView.setRightDrawable(null);
+            }
         }
         if (isActive && (isSelf || isChannel)) {
             storiesController.pollViewsForSelfStories(dialogId, true);
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TextMessageEnterTransition.java b/TMessagesProj/src/main/java/org/telegram/ui/TextMessageEnterTransition.java
index 7d3f8ea7eb..79dbeec3ef 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/TextMessageEnterTransition.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/TextMessageEnterTransition.java
@@ -639,7 +639,7 @@ public void onDraw(Canvas canvas) {
                 replyImageSz = AndroidUtilities.lerp(AndroidUtilities.dp(35), sz, progressX);
                 messageView.replyImageReceiver.setImageCoords(
                     AndroidUtilities.lerp(replyX, replySelectorRect.left + AndroidUtilities.dp(8), progressX),
-                    AndroidUtilities.lerp(replyY, replySelectorRect.top + AndroidUtilities.dp(5), progressX),
+                    AndroidUtilities.lerp(replyY, replySelectorRect.top + AndroidUtilities.dp((messageView.isReplyQuote && messageView.replyTextLayout != null && messageView.replyTextLayout.getLineCount() <= 1 ? 2 : 0) + 5), progressX),
                     replyImageSz, replyImageSz
                 );
                 messageView.replyImageReceiver.draw(canvas);
@@ -690,8 +690,17 @@ public void onDraw(Canvas canvas) {
 
             if (messageView.replyTextLayout != null) {
                 canvas.save();
-                final float offsetX2 = (messageView.needReplyImage && (!messageView.isReplyQuote || messageView.replyTextRTL) ? replyImageSz + AndroidUtilities.dp(3) : 0) + AndroidUtilities.dp(messageView.isReplyQuote && messageView.needReplyImage ? -2 : 0);
-                canvas.translate(replyMessageX + offsetX2, replyY + AndroidUtilities.lerp(AndroidUtilities.dp(19), Theme.chat_replyNamePaint.getTextSize() + AndroidUtilities.dp(4) + offsetY, progressX));
+                float left = replyToMessageX;
+                if (messageView.isReplyQuote && messageView.needReplyImage) {
+                    left -= AndroidUtilities.dp(2);
+                }
+                if (messageView.needReplyImage && (!messageView.isReplyQuote || messageView.replyTextRTL)) {
+                    left += replyImageSz + AndroidUtilities.dp(3);
+                }
+                if (messageView.replyTextRTL && messageView.replyTextOffset > 0) {
+                    left = replySelectorRect.right - AndroidUtilities.dp(8) - messageView.replyTextLayout.getWidth() - offset * progressX;
+                }
+                canvas.translate(AndroidUtilities.lerp(fromReplayX - messageView.replyTextOffset, left, progressX), replyY + AndroidUtilities.lerp(AndroidUtilities.dp(19), Theme.chat_replyNamePaint.getTextSize() + AndroidUtilities.dp(4) + offsetY, progressX));
 
                 canvas.save();
                 SpoilerEffect.clipOutCanvas(canvas, messageView.replySpoilers);
diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml
index d97fc6756d..fc2ddc25b4 100644
--- a/TMessagesProj/src/main/res/values/strings.xml
+++ b/TMessagesProj/src/main/res/values/strings.xml
@@ -1266,6 +1266,7 @@
     Delete for %1$s
     Delete for all members
     Text copied to clipboard
+    Code copied to clipboard
     Hold to record audio.
     Hold to record audio. Tap to switch to video.
     Hold to record video. Tap to switch to audio.
@@ -4717,6 +4718,12 @@
     %1$d-months
     %1$d-months
     %1$d-months
+    %1$d-month
+    %1$d-month
+    %1$d-month
+    %1$d-month
+    %1$d-month
+    %1$d-month
     **%1$d** month
     **%1$d** months
     **%1$d** months
@@ -5880,8 +5887,6 @@
     Gift Telegram Premium
     Let **%1$s** enjoy exclusive features of Telegram with **Telegram Premium**.
     Telegram Premium
-    %1$s subscriptions
-    %1$d Telegram Premium
     Go **beyond the limits**, get exclusive features and support us by subscribing to **Telegram Premium**.
     You are all set!
     Thank you for subscribing to **Telegram Premium**.\nHere’s what is now unlocked.
@@ -7166,7 +7171,8 @@
     All viewers
     Reactions First
     Newest First
-    Choose the order for the 
list of viewers.
+    Choose the order for the 
+list of viewers.
     None of your contacts viewed this story.
     Viewers
     You are in Stealth Mode now
@@ -7228,7 +7234,7 @@
     Congratulations!
     You\'ve received a gift\nfrom **%s**.
     You\'ve received a gift.
-    Your gift is a **Telegram Premium**\n subscription for %s.
+    Your gift is a **Telegram Premium**\nsubscription for %s.
     Unclaimed Prize
     You have an unclaimed prize from a giveaway by **%s**.
     This prize is a **Telegram Premium** subscription for %s.
@@ -7237,12 +7243,22 @@
     Open Gift Link
     Save Recipients
     %s just started a giveaway of Telegram Premium subscriptions to its followers.
-    %d boost
-    %d boost
-    %d boosts
-    %d boosts
-    %d boosts
-    %d boosts
+    %d boost
+    %d boost
+    %d boosts
+    %d boosts
+    %d boosts
+    %d boosts
+    %2$s subscription
+    %2$s subscriptions
+    %2$s subscriptions
+    %2$s subscriptions
+    %2$s subscriptions
+    %1$d Telegram Premium
+    %1$d Telegram Premium
+    %1$d Telegram Premium
+    %1$d Telegram Premium
+    %1$d Telegram Premium
     Get Boosts via Gifts
     Use Link
     Share this link with your subsсribers to get more boosts.
@@ -7264,7 +7280,7 @@
     %1$d Gifts
     %1$d Gifts
     %1$d Boosts
-    %1$d Boosts
+    %1$d Boost
     %1$d Boosts
     %1$d Boosts
     %1$d Boosts
@@ -7313,7 +7329,11 @@
     Date
     Prepaid giveaways
     Prepaid giveaway
-    %1$d subscriptions for %2$s
+    %1$d subscription for %2$s
+    %1$d subscriptions for %2$s
+    %1$d subscriptions for %2$s
+    %1$d subscriptions for %2$s
+    %1$d subscriptions for %2$s
     select recipients
     from all countries
     from %1$s
@@ -7326,7 +7346,7 @@
     from %1$d countries
     from %1$d countries
     You can also **send this link** to a friend as a gift.
-    You can also **send this link** to a anyone as a gift.
+    You can also **send this link** to anyone as a gift.
     This link was used on %s.
     Quantity of prizes
     Choose how many Premium subscriptions to give away and boosts to receive.
@@ -7356,21 +7376,41 @@
     On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s**.
     On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s**.
     On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s**.
-    On **%2$s**, Telegram will automatically select **%3$s** random user that joined **%4$s** and **%5$s** other listed channels.
-    On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s** and **%5$s** other listed channels.
-    On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s** and **%5$s** other listed channels.
-    On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s** and **%5$s** other listed channels.
-    On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s** and **%5$s** other listed channels.
+    On **%2$s**, Telegram will automatically select **%3$s** random user that joined **%4$s** %5$s.
+    On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s** %5$s.
+    On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s** %5$s.
+    On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s** %5$s.
+    On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s** %5$s.
+    On **%2$s**, Telegram automatically selected **%3$s** random user that joined **%4$s** %5$s.
+    On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s** %5$s.
+    On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s** %5$s.
+    On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s** %5$s.
+    On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s** %5$s.
+    and **%1$d** other listed channel
+    and **%1$d** other listed channels
+    and **%1$d** other listed channels
+    and **%1$d** other listed channels
+    and **%1$d** other listed channels
+    On **%2$s**, Telegram will automatically select **%3$s** random user that joined **%4$s** %5$s.
+    On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s** %5$s.
+    On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s** %5$s.
+    On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s** %5$s.
+    On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s** %5$s.
+    On **%2$s**, Telegram automatically selected **%3$s** random user that joined **%4$s** %5$s.
+    On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s** %5$s.
+    On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s** %5$s.
+    On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s** %5$s.
+    On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s** %5$s.
+    and **%1$d** other listed channel after **%2$s** on **%3$s**
+    and **%1$d** other listed channels after **%2$s** on **%3$s**
+    and **%1$d** other listed channels after **%2$s** on **%3$s**
+    and **%1$d** other listed channels after **%2$s** on **%3$s**
+    and **%1$d** other listed channels after **%2$s** on **%3$s**
     On **%2$s**, Telegram will automatically select **%3$s** random user that joined **%4$s** after **%5$s** on **%6$s**.
     On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s** after **%5$s** on **%6$s**.
     On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s** after **%5$s** on **%6$s**.
     On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s** after **%5$s** on **%6$s**.
     On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s** after **%5$s** on **%6$s**.
-    On **%2$s**, Telegram will automatically select **%3$s** random user that joined **%4$s** and **%5$s** other listed channels after **%6$s** on **%7$s**.
-    On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s** and **%5$s** other listed channels after **%6$s** on **%7$s**.
-    On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s** and **%5$s** other listed channels after **%6$s** on **%7$s**.
-    On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s** and **%5$s** other listed channels after **%6$s** on **%7$s**.
-    On **%2$s**, Telegram will automatically select **%3$s** random users that joined **%4$s** and **%5$s** other listed channels after **%6$s** on **%7$s**.
     This giveaway was sponsored by the admins of **%2$s**, who acquired **%3$s Telegram Premium** subscription for %4$s for its followers.
     This giveaway was sponsored by the admins of **%2$s**, who acquired **%3$s Telegram Premium** subscriptions for %4$s for its followers.
     This giveaway was sponsored by the admins of **%2$s**, who acquired **%3$s Telegram Premium** subscriptions for %4$s for its followers.
@@ -7381,21 +7421,11 @@
     On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s**.
     On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s**.
     On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s**.
-    On **%2$s**, Telegram automatically selected **%3$s** random user that joined **%4$s** and **%5$s** other listed channels.
-    On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s** and **%5$s** other listed channels.
-    On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s** and **%5$s** other listed channels.
-    On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s** and **%5$s** other listed channels.
-    On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s** and **%5$s** other listed channels.
     On **%2$s**, Telegram automatically selected **%3$s** random user that joined **%4$s** after **%5$s** on **%6$s**.
     On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s** after **%5$s** on **%6$s**.
     On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s** after **%5$s** on **%6$s**.
     On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s** after **%5$s** on **%6$s**.
     On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s** after **%5$s** on **%6$s**.
-    On **%2$s**, Telegram automatically selected **%3$s** random user that joined **%4$s** and **%5$s** other listed channels after **%6$s** on **%7$s**.
-    On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s** and **%5$s** other listed channels after **%6$s** on **%7$s**.
-    On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s** and **%5$s** other listed channels after **%6$s** on **%7$s**.
-    On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s** and **%5$s** other listed channels after **%6$s** on **%7$s**.
-    On **%2$s**, Telegram automatically selected **%3$s** random users that joined **%4$s** and **%5$s** other listed channels after **%6$s** on **%7$s**.
     Reduce Quantity
     Giveaway ended
     Channel is Private
@@ -7409,30 +7439,70 @@
     **%1$d** of the winners already used their gift links.
     **%1$d** of the winners already used their gift links.
     **%1$d** of the winners already used their gift links.
-    You can’t purchase **%1$d** %2$s subscriptions in the app. Do you want to reduce the prize quantity to **%3$d**?
-    You can’t purchase **%1$d** subscriptions in the app. Only **%2$s** available.
-    Select up to %1$d channels
-    Select up to %1$d countries
+    You can’t purchase **%1$d** %2$s subscription in the app. Do you want to reduce the prize quantity to **%3$d**?
+    You can’t purchase **%1$d** %2$s subscriptions in the app. Do you want to reduce the prize quantity to **%3$d**?
+    You can’t purchase **%1$d** %2$s subscriptions in the app. Do you want to reduce the prize quantity to **%3$d**?
+    You can’t purchase **%1$d** %2$s subscriptions in the app. Do you want to reduce the prize quantity to **%3$d**?
+    You can’t purchase **%1$d** %2$s subscriptions in the app. Do you want to reduce the prize quantity to **%3$d**?
+    You can’t purchase **%1$d** subscription in the app. Only **%2$s** available.
+    You can’t purchase **%1$d** subscriptions in the app. Only **%2$s** available.
+    You can’t purchase **%1$d** subscriptions in the app. Only **%2$s** available.
+    You can’t purchase **%1$d** subscriptions in the app. Only **%2$s** available.
+    You can’t purchase **%1$d** subscriptions in the app. Only **%2$s** available.
+    Select up to %1$d channel
+    Select up to %1$d channels
+    Select up to %1$d channels
+    Select up to %1$d channels
+    Select up to %1$d channels
+    Select up to %1$d country
+    Select up to %1$d countries
+    Select up to %1$d countries
+    Select up to %1$d countries
+    Select up to %1$d countries
     You have changed the list of users. Apply changes?
     You have changed the list of channels. Apply changes?
     You have changed the list of countries. Apply changes?
     You are participating in this giveaway, because you have joined channel **%1$s**.
-    You are participating in this giveaway, because you have joined channel **%1$s** (and **%2$d** other listed channels).
+    You are participating in this giveaway, because you have joined channel **%2$s** (and **%1$d** other listed channel).
+    You are participating in this giveaway, because you have joined channel **%2$s** (and **%1$d** other listed channels).
+    You are participating in this giveaway, because you have joined channel **%2$s** (and **%1$d** other listed channels).
+    You are participating in this giveaway, because you have joined channel **%2$s** (and **%1$d** other listed channels).
+    You are participating in this giveaway, because you have joined channel **%2$s** (and **%1$d** other listed channels).
+    To take part in this giveaway please join channel **%2$s** (and **%1$d** other listed channel) before **%3$s**.
+    To take part in this giveaway please join channel **%2$s** (and **%1$d** other listed channels) before **%3$s**.
+    To take part in this giveaway please join channel **%2$s** (and **%1$d** other listed channels) before **%3$s**.
+    To take part in this giveaway please join channel **%2$s** (and **%1$d** other listed channels) before **%3$s**.
+    To take part in this giveaway please join channel **%2$s** (and **%1$d** other listed channels) before **%3$s**.
     To take part in this giveaway please join channel **%1$s** before **%2$s**.
-    To take part in this giveaway please join channel **%1$s** (and **%2$d** other listed channels) before **%3$s**.
     You are not eligible to participate in this giveaway, because you joined this channel on **%1$s**, which is before the contest started.
     You are not eligible to participate in this giveaway, because you are an admin of participating channel (**%1$s**).
     You are not eligible to participate in this giveaway, because your country is not included in the terms of the giveaway.
     Only the recipient can see the link.
     Only giveaway creator can see the link.
     You can select maximum 10 users.
-    You can select maximum %1$d channels.
-    You can select maximum %1$d countries.
-    Wait until the boost is available or get **%1$d** more boosts by gifting a **Telegram Premium** subscription.
+    You can select maximum %1$d channel.
+    You can select maximum %1$d channels.
+    You can select maximum %1$d channels.
+    You can select maximum %1$d channels.
+    You can select maximum %1$d channels.
+    You can select maximum %1$d country.
+    You can select maximum %1$d countries.
+    You can select maximum %1$d countries.
+    You can select maximum %1$d countries.
+    You can select maximum %1$d countries.
+    Wait until the boost is available or get **%1$d** more boost by gifting a **Telegram Premium** subscription.
+    Wait until the boost is available or get **%1$d** more boosts by gifting a **Telegram Premium** subscription.
+    Wait until the boost is available or get **%1$d** more boosts by gifting a **Telegram Premium** subscription.
+    Wait until the boost is available or get **%1$d** more boosts by gifting a **Telegram Premium** subscription.
+    Wait until the boost is available or get **%1$d** more boosts by gifting a **Telegram Premium** subscription.
     Boost Again
     Reassign Boost
     More Boosts Needed
-    %1$s reassigned from %2$s
+    %1$d boost reassigned from %2$s
+    %1$d boosts reassigned from %2$s
+    %1$d boosts reassigned from %2$s
+    %1$d boosts reassigned from %2$s
+    %1$d boosts reassigned from %2$s
     %d other channels
     %d other channel
     %d other channels
@@ -7441,7 +7511,11 @@
     %d other channels
     To boost **%1$s**, get more boosts by gifting **Telegram Premium** to a friend.
     Reassign Boosts
-    To boost **%1$s**, reassign a previous boost or gift **Telegram Premium** to a friend to get **%2$d** additional boosts.
+    To boost **%2$s**, reassign a previous boost or gift **Telegram Premium** to a friend to get **%1$d** additional boost.
+    To boost **%2$s**, reassign a previous boost or gift **Telegram Premium** to a friend to get **%1$d** additional boosts.
+    To boost **%2$s**, reassign a previous boost or gift **Telegram Premium** to a friend to get **%1$d** additional boosts.
+    To boost **%2$s**, reassign a previous boost or gift **Telegram Premium** to a friend to get **%1$d** additional boosts.
+    To boost **%2$s**, reassign a previous boost or gift **Telegram Premium** to a friend to get **%1$d** additional boosts.
     Remove your boost from
     available in %1$s
     Duration of Premium subscriptions
@@ -7450,10 +7524,21 @@
     from %1$s
     **Winners Selection Date**
     **Giveaway Prizes**
-    **%1$d** Telegram Premium\nSubscription for %2$s.
+    **%1$d** Telegram Premium
+    **%1$d** Telegram Premium
+    **%1$d** Telegram Premium
+    **%1$d** Telegram Premium
+    **%1$d** Telegram Premium
+    Subscription for %2$s.
+    Subscriptions for %2$s.
+    Subscriptions for %2$s.
+    Subscriptions for %2$s.
+    Subscriptions for %2$s.
     **Participants**
-    All subscribers of the channel:
-    New subscribers of the channel:
+    All subscribers of the channel:
+    All subscribers of the channels:
+    New subscribers of the channel:
+    New subscribers of the channels:
     You can’t add up more than 5 reactions tags to a story.
     Someone just got access to your messages!
     Yes, it’s me
@@ -7611,4 +7696,5 @@
     OPEN
     Your name color has been updated!
     Your channel color has been updated!
+    Copy Code
 
diff --git a/gradle.properties b/gradle.properties
index aa02381aba..8768cb9960 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_CODE=4075
-APP_VERSION_NAME=10.2.3
+APP_VERSION_CODE=4082
+APP_VERSION_NAME=10.2.6
 APP_PACKAGE=nekox.messenger.broken
 RELEASE_KEY_PASSWORD=android
 RELEASE_KEY_ALIAS=androidkey